diff options
Diffstat (limited to 'src/main/java/com/gitblit/wicket')
186 files changed, 20072 insertions, 0 deletions
diff --git a/src/main/java/com/gitblit/wicket/AuthorizationStrategy.java b/src/main/java/com/gitblit/wicket/AuthorizationStrategy.java new file mode 100644 index 00000000..765d8608 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/AuthorizationStrategy.java @@ -0,0 +1,86 @@ +/*
+ * Copyright 2011 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;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.RestartResponseException;
+import org.apache.wicket.authorization.IUnauthorizedComponentInstantiationListener;
+import org.apache.wicket.authorization.strategies.page.AbstractPageAuthorizationStrategy;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.UserModel;
+import com.gitblit.wicket.pages.BasePage;
+import com.gitblit.wicket.pages.RepositoriesPage;
+
+public class AuthorizationStrategy extends AbstractPageAuthorizationStrategy implements
+ IUnauthorizedComponentInstantiationListener {
+
+ public AuthorizationStrategy() {
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ protected boolean isPageAuthorized(Class pageClass) {
+ if (RepositoriesPage.class.equals(pageClass)) {
+ // allow all requests to get to the RepositoriesPage with its inline
+ // authentication form
+ return true;
+ }
+
+ if (BasePage.class.isAssignableFrom(pageClass)) {
+ boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, true);
+ boolean authenticateAdmin = GitBlit.getBoolean(Keys.web.authenticateAdminPages, true);
+ boolean allowAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, true);
+
+ GitBlitWebSession session = GitBlitWebSession.get();
+ if (authenticateView && !session.isLoggedIn()) {
+ // authentication required
+ session.cacheRequest(pageClass);
+ return false;
+ }
+
+ UserModel user = session.getUser();
+ if (pageClass.isAnnotationPresent(RequiresAdminRole.class)) {
+ // admin page
+ if (allowAdmin) {
+ if (authenticateAdmin) {
+ // authenticate admin
+ if (user != null) {
+ return user.canAdmin();
+ }
+ return false;
+ } else {
+ // no admin authentication required
+ return true;
+ }
+ } else {
+ // admin prohibited
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onUnauthorizedInstantiation(Component component) {
+
+ if (component instanceof BasePage) {
+ throw new RestartResponseException(RepositoriesPage.class);
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/ExternalImage.java b/src/main/java/com/gitblit/wicket/ExternalImage.java new file mode 100644 index 00000000..33257740 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/ExternalImage.java @@ -0,0 +1,35 @@ +/*
+ * Copyright 2012 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;
+
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.WebComponent;
+import org.apache.wicket.model.Model;
+
+public class ExternalImage extends WebComponent {
+
+ private static final long serialVersionUID = 1L;
+
+ public ExternalImage(String id, String url) {
+ super(id, new Model<String>(url));
+ }
+
+ protected void onComponentTag(ComponentTag tag) {
+ super.onComponentTag(tag);
+ checkComponentTag(tag, "img");
+ tag.put("src", getDefaultModelObjectAsString());
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java new file mode 100644 index 00000000..2300d0ff --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java @@ -0,0 +1,160 @@ +/*
+ * Copyright 2011 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;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.Page;
+import org.apache.wicket.Request;
+import org.apache.wicket.Response;
+import org.apache.wicket.Session;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.protocol.http.WebApplication;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.wicket.pages.ActivityPage;
+import com.gitblit.wicket.pages.BlamePage;
+import com.gitblit.wicket.pages.BlobDiffPage;
+import com.gitblit.wicket.pages.BlobPage;
+import com.gitblit.wicket.pages.BranchesPage;
+import com.gitblit.wicket.pages.CommitDiffPage;
+import com.gitblit.wicket.pages.CommitPage;
+import com.gitblit.wicket.pages.DocsPage;
+import com.gitblit.wicket.pages.FederationRegistrationPage;
+import com.gitblit.wicket.pages.ForkPage;
+import com.gitblit.wicket.pages.ForksPage;
+import com.gitblit.wicket.pages.GitSearchPage;
+import com.gitblit.wicket.pages.GravatarProfilePage;
+import com.gitblit.wicket.pages.HistoryPage;
+import com.gitblit.wicket.pages.LogPage;
+import com.gitblit.wicket.pages.LogoutPage;
+import com.gitblit.wicket.pages.LuceneSearchPage;
+import com.gitblit.wicket.pages.MarkdownPage;
+import com.gitblit.wicket.pages.MetricsPage;
+import com.gitblit.wicket.pages.PatchPage;
+import com.gitblit.wicket.pages.ProjectPage;
+import com.gitblit.wicket.pages.ProjectsPage;
+import com.gitblit.wicket.pages.RawPage;
+import com.gitblit.wicket.pages.RepositoriesPage;
+import com.gitblit.wicket.pages.ReviewProposalPage;
+import com.gitblit.wicket.pages.SummaryPage;
+import com.gitblit.wicket.pages.TagPage;
+import com.gitblit.wicket.pages.TagsPage;
+import com.gitblit.wicket.pages.TicketPage;
+import com.gitblit.wicket.pages.TicketsPage;
+import com.gitblit.wicket.pages.TreePage;
+import com.gitblit.wicket.pages.UserPage;
+import com.gitblit.wicket.pages.UsersPage;
+
+public class GitBlitWebApp extends WebApplication {
+
+ @Override
+ public void init() {
+ super.init();
+
+ // Setup page authorization mechanism
+ boolean useAuthentication = GitBlit.getBoolean(Keys.web.authenticateViewPages, false)
+ || GitBlit.getBoolean(Keys.web.authenticateAdminPages, false);
+ if (useAuthentication) {
+ AuthorizationStrategy authStrategy = new AuthorizationStrategy();
+ getSecuritySettings().setAuthorizationStrategy(authStrategy);
+ getSecuritySettings().setUnauthorizedComponentInstantiationListener(authStrategy);
+ }
+
+ // Grab Browser info (like timezone, etc)
+ if (GitBlit.getBoolean(Keys.web.useClientTimezone, false)) {
+ getRequestCycleSettings().setGatherExtendedBrowserInfo(true);
+ }
+
+ // configure the resource cache duration to 90 days for deployment
+ if (!GitBlit.isDebugMode()) {
+ getResourceSettings().setDefaultCacheDuration(90 * 86400);
+ }
+
+ // setup the standard gitweb-ish urls
+ mount("/summary", SummaryPage.class, "r");
+ mount("/log", LogPage.class, "r", "h");
+ mount("/tags", TagsPage.class, "r");
+ mount("/branches", BranchesPage.class, "r");
+ mount("/commit", CommitPage.class, "r", "h");
+ mount("/tag", TagPage.class, "r", "h");
+ mount("/tree", TreePage.class, "r", "h", "f");
+ mount("/blob", BlobPage.class, "r", "h", "f");
+ mount("/raw", RawPage.class, "r", "h", "f");
+ mount("/blobdiff", BlobDiffPage.class, "r", "h", "f");
+ mount("/commitdiff", CommitDiffPage.class, "r", "h");
+ mount("/patch", PatchPage.class, "r", "h", "f");
+ mount("/history", HistoryPage.class, "r", "h", "f");
+ mount("/search", GitSearchPage.class);
+ mount("/metrics", MetricsPage.class, "r");
+ mount("/blame", BlamePage.class, "r", "h", "f");
+ mount("/users", UsersPage.class);
+ mount("/logout", LogoutPage.class);
+
+ // setup ticket urls
+ mount("/tickets", TicketsPage.class, "r");
+ mount("/ticket", TicketPage.class, "r", "f");
+
+ // setup the markdown urls
+ mount("/docs", DocsPage.class, "r");
+ mount("/markdown", MarkdownPage.class, "r", "h", "f");
+
+ // federation urls
+ mount("/proposal", ReviewProposalPage.class, "t");
+ mount("/registration", FederationRegistrationPage.class, "u", "n");
+
+ mount("/activity", ActivityPage.class, "r", "h");
+ mount("/gravatar", GravatarProfilePage.class, "h");
+ mount("/lucene", LuceneSearchPage.class);
+ mount("/project", ProjectPage.class, "p");
+ mount("/projects", ProjectsPage.class);
+ mount("/user", UserPage.class, "user");
+ mount("/forks", ForksPage.class, "r");
+ mount("/fork", ForkPage.class, "r");
+ }
+
+ private void mount(String location, Class<? extends WebPage> clazz, String... parameters) {
+ if (parameters == null) {
+ parameters = new String[] {};
+ }
+ if (!GitBlit.getBoolean(Keys.web.mountParameters, true)) {
+ parameters = new String[] {};
+ }
+ mount(new GitblitParamUrlCodingStrategy(location, clazz, parameters));
+ }
+
+ @Override
+ public Class<? extends Page> getHomePage() {
+ return RepositoriesPage.class;
+ }
+
+ @Override
+ public final Session newSession(Request request, Response response) {
+ return new GitBlitWebSession(request);
+ }
+
+ @Override
+ public final String getConfigurationType() {
+ if (GitBlit.isDebugMode()) {
+ return Application.DEVELOPMENT;
+ }
+ return Application.DEPLOYMENT;
+ }
+
+ public static GitBlitWebApp get() {
+ return (GitBlitWebApp) WebApplication.get();
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties new file mode 100644 index 00000000..7a2b1bb3 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -0,0 +1,447 @@ +gb.repository = repository
+gb.owner = owner
+gb.description = description
+gb.lastChange = last change
+gb.refs = refs
+gb.tag = tag
+gb.tags = tags
+gb.author = author
+gb.committer = committer
+gb.commit = commit
+gb.tree = tree
+gb.parent = parent
+gb.url = URL
+gb.history = history
+gb.raw = raw
+gb.object = object
+gb.ticketId = ticket id
+gb.ticketAssigned = assigned
+gb.ticketOpenDate = open date
+gb.ticketState = state
+gb.ticketComments = comments
+gb.view = view
+gb.local = local
+gb.remote = remote
+gb.branches = branches
+gb.patch = patch
+gb.diff = diff
+gb.log = log
+gb.moreLogs = more commits...
+gb.allTags = all tags...
+gb.allBranches = all branches...
+gb.summary = summary
+gb.ticket = ticket
+gb.newRepository = new repository
+gb.newUser = new user
+gb.commitdiff = commitdiff
+gb.tickets = tickets
+gb.pageFirst = first
+gb.pagePrevious prev
+gb.pageNext = next
+gb.head = HEAD
+gb.blame = blame
+gb.login = login
+gb.logout = logout
+gb.username = username
+gb.password = password
+gb.tagger = tagger
+gb.moreHistory = more history...
+gb.difftocurrent = diff to current
+gb.search = search
+gb.searchForAuthor = Search for commits authored by
+gb.searchForCommitter = Search for commits committed by
+gb.addition = addition
+gb.modification = modification
+gb.deletion = deletion
+gb.rename = rename
+gb.metrics = metrics
+gb.stats = stats
+gb.markdown = markdown
+gb.changedFiles = changed files
+gb.filesAdded = {0} files added
+gb.filesModified = {0} files modified
+gb.filesDeleted = {0} files deleted
+gb.filesCopied = {0} files copied
+gb.filesRenamed = {0} files renamed
+gb.missingUsername = Missing Username
+gb.edit = edit
+gb.searchTypeTooltip = Select Search Type
+gb.searchTooltip = Search {0}
+gb.delete = delete
+gb.docs = docs
+gb.accessRestriction = access restriction
+gb.name = name
+gb.enableTickets = enable tickets
+gb.enableDocs = enable docs
+gb.save = save
+gb.showRemoteBranches = show remote branches
+gb.editUsers = edit users
+gb.confirmPassword = confirm password
+gb.restrictedRepositories = restricted repositories
+gb.canAdmin = can admin
+gb.notRestricted = anonymous view, clone, & push
+gb.pushRestricted = authenticated push
+gb.cloneRestricted = authenticated clone & push
+gb.viewRestricted = authenticated view, clone, & push
+gb.useTicketsDescription = readonly, distributed Ticgit issues
+gb.useDocsDescription = enumerates Markdown documentation in repository
+gb.showRemoteBranchesDescription = show remote branches
+gb.canAdminDescription = can administer Gitblit server
+gb.permittedUsers = permitted users
+gb.isFrozen = is frozen
+gb.isFrozenDescription = deny push operations
+gb.zip = zip
+gb.showReadme = show readme
+gb.showReadmeDescription = show a \"readme\" Markdown file on the summary page
+gb.nameDescription = use '/' to group repositories. e.g. libraries/mycoollib.git
+gb.ownerDescription = the owner may edit repository settings
+gb.blob = blob
+gb.commitActivityTrend = commit activity trend
+gb.commitActivityDOW = commit activity by day of week
+gb.commitActivityAuthors = primary authors by commit activity
+gb.feed = feed
+gb.cancel = cancel
+gb.changePassword = change password
+gb.isFederated = is federated
+gb.federateThis = federate this repository
+gb.federateOrigin = federate the origin
+gb.excludeFromFederation = exclude from federation
+gb.excludeFromFederationDescription = block federated Gitblit instances from pulling this account
+gb.tokens = federation tokens
+gb.tokenAllDescription = all repositories, users, & settings
+gb.tokenUnrDescription = all repositories & users
+gb.tokenJurDescription = all repositories
+gb.federatedRepositoryDefinitions = repository definitions
+gb.federatedUserDefinitions = user definitions
+gb.federatedSettingDefinitions = setting definitions
+gb.proposals = federation proposals
+gb.received = received
+gb.type = type
+gb.token = token
+gb.repositories = repositories
+gb.proposal = proposal
+gb.frequency = frequency
+gb.folder = folder
+gb.lastPull = last pull
+gb.nextPull = next pull
+gb.inclusions = inclusions
+gb.exclusions = exclusions
+gb.registration = registration
+gb.registrations = federation registrations
+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.federationStrategy = federation strategy
+gb.federationRegistration = federation registration
+gb.federationResults = federation pull results
+gb.federationSets = federation sets
+gb.message = message
+gb.myUrlDescription = the publicly accessible url for your Gitblit instance
+gb.destinationUrl = send to
+gb.destinationUrlDescription = the url of the Gitblit instance to send your proposal
+gb.users = users
+gb.federation = federation
+gb.error = error
+gb.refresh = refresh
+gb.browse = browse
+gb.clone = clone
+gb.filter = filter
+gb.create = create
+gb.servers = servers
+gb.recent = recent
+gb.available = available
+gb.selected = selected
+gb.size = size
+gb.downloading = downloading
+gb.loading = loading
+gb.starting = starting
+gb.general = general
+gb.settings = settings
+gb.manage = manage
+gb.lastLogin = last login
+gb.skipSizeCalculation = skip size calculation
+gb.skipSizeCalculationDescription = do not calculate the repository size (reduces page load time)
+gb.skipSummaryMetrics = skip summary metrics
+gb.skipSummaryMetricsDescription = do not calculate metrics on the summary page (reduces page load time)
+gb.accessLevel = access level
+gb.default = default
+gb.setDefault = set default
+gb.since = since
+gb.status = status
+gb.bootDate = boot date
+gb.servletContainer = servlet container
+gb.heapMaximum = maximum heap
+gb.heapAllocated = allocated heap
+gb.heapUsed = used heap
+gb.free = free
+gb.version = version
+gb.releaseDate = release date
+gb.date = date
+gb.activity = activity
+gb.subscribe = subscribe
+gb.branch = branch
+gb.maxHits = max hits
+gb.recentActivity = recent activity
+gb.recentActivityStats = last {0} days / {1} commits by {2} authors
+gb.recentActivityNone = last {0} days / none
+gb.dailyActivity = daily activity
+gb.activeRepositories = active repositories
+gb.activeAuthors = active authors
+gb.commits = commits
+gb.teams = teams
+gb.teamName = team name
+gb.teamMembers = team members
+gb.teamMemberships = team memberships
+gb.newTeam = new team
+gb.permittedTeams = permitted teams
+gb.emptyRepository = empty repository
+gb.repositoryUrl = repository url
+gb.mailingLists = mailing lists
+gb.preReceiveScripts = pre-receive scripts
+gb.postReceiveScripts = post-receive scripts
+gb.hookScripts = hook scripts
+gb.customFields = custom fields
+gb.customFieldsDescription = custom fields available to Groovy hooks
+gb.accessPermissions = access permissions
+gb.filters = filters
+gb.generalDescription = common settings
+gb.accessPermissionsDescription = restrict access by users and teams
+gb.accessPermissionsForUserDescription = set team memberships or grant access to specific restricted repositories
+gb.accessPermissionsForTeamDescription = set team members and grant access to specific restricted repositories
+gb.federationRepositoryDescription = share this repository with other Gitblit servers
+gb.hookScriptsDescription = run Groovy scripts on pushes to this Gitblit server
+gb.reset = reset
+gb.pages = pages
+gb.workingCopy = working copy
+gb.workingCopyWarning = this repository has a working copy and can not receive pushes
+gb.query = query
+gb.queryHelp = Standard query syntax is supported.<p/><p/>Please see <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> for details.
+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.noIndexedRepositoriesWarning = none of your repositories are configured for Lucene indexing
+gb.undefinedQueryWarning = query is undefined!
+gb.noSelectedRepositoriesWarning = please select one or more repositories!
+gb.luceneDisabled = Lucene indexing is disabled
+gb.failedtoRead = Failed to read
+gb.isNotValidFile = is not a valid file
+gb.failedToReadMessage = Failed to read default message from {0}!
+gb.passwordsDoNotMatch = Passwords do not match!
+gb.passwordTooShort = Password is too short. Minimum length is {0} characters.
+gb.passwordChanged = Password successfully changed.
+gb.passwordChangeAborted = Password change aborted.
+gb.pleaseSetRepositoryName = Please set repository name!
+gb.illegalLeadingSlash = Leading root folder references (/) are prohibited.
+gb.illegalRelativeSlash = Relative folder references (../) are prohibited.
+gb.illegalCharacterRepositoryName = Illegal character ''{0}'' in repository name!
+gb.selectAccessRestriction = Please select access restriction!
+gb.selectFederationStrategy = Please select federation strategy!
+gb.pleaseSetTeamName = Please enter a teamname!
+gb.teamNameUnavailable = Team name ''{0}'' is unavailable.
+gb.teamMustSpecifyRepository = A team must specify at least one repository.
+gb.teamCreated = New team ''{0}'' successfully created.
+gb.pleaseSetUsername = Please enter a username!
+gb.usernameUnavailable = Username ''{0}'' is unavailable.
+gb.combinedMd5Rename = Gitblit is configured for combined-md5 password hashing. You must enter a new password on account rename.
+gb.userCreated = New user ''{0}'' successfully created.
+gb.couldNotFindFederationRegistration = Could not find federation registration!
+gb.failedToFindGravatarProfile = Failed to find Gravatar profile for {0}
+gb.branchStats = {0} commits and {1} tags in {2}
+gb.repositoryNotSpecified = Repository not specified!
+gb.repositoryNotSpecifiedFor = Repository not specified for {0}!
+gb.canNotLoadRepository = Can not load repository
+gb.commitIsNull = Commit is null
+gb.unauthorizedAccessForRepository = Unauthorized access for repository
+gb.failedToFindCommit = Failed to find commit \"{0}\" in {1} for {2} page!
+gb.couldNotFindFederationProposal = Could not find federation proposal!
+gb.invalidUsernameOrPassword = Invalid username or password!
+gb.OneProposalToReview = There is 1 federation proposal awaiting review.
+gb.nFederationProposalsToReview = There are {0} federation proposals awaiting review.
+gb.couldNotFindTag = Could not find tag {0}
+gb.couldNotCreateFederationProposal = Could not create federation proposal!
+gb.pleaseSetGitblitUrl = Please enter your Gitblit url!
+gb.pleaseSetDestinationUrl = Please enter a destination url for your proposal!
+gb.proposalReceived = Proposal successfully received by {0}.
+gb.noGitblitFound = Sorry, {0} could not find a Gitblit instance at {1}.
+gb.noProposals = Sorry, {0} is not accepting proposals at this time.
+gb.noFederation = Sorry, {0} is not configured to federate with any Gitblit instances.
+gb.proposalFailed = Sorry, {0} did not receive any proposal data!
+gb.proposalError = Sorry, {0} reports that an unexpected error occurred!
+gb.failedToSendProposal = Failed to send proposal!
+gb.userServiceDoesNotPermitAddUser = {0} does not permit adding a user account!
+gb.userServiceDoesNotPermitPasswordChanges = {0} does not permit password changes!
+gb.displayName = display name
+gb.emailAddress = email address
+gb.errorAdminLoginRequired = Administration requires a login
+gb.errorOnlyAdminMayCreateRepository = Only an administrator may create a repository
+gb.errorOnlyAdminOrOwnerMayEditRepository = Only an administrator or the owner may edit a repository
+gb.errorAdministrationDisabled = Administration is disabled
+gb.lastNDays = last {0} days
+gb.completeGravatarProfile = Complete profile on Gravatar.com
+gb.none = none
+gb.line = line
+gb.content = content
+gb.empty = empty
+gb.inherited = inherited
+gb.deleteRepository = Delete repository \"{0}\"?
+gb.repositoryDeleted = Repository ''{0}'' deleted.
+gb.repositoryDeleteFailed = Failed to delete repository ''{0}''!
+gb.deleteUser = Delete user \"{0}\"?
+gb.userDeleted = User ''{0}'' deleted.
+gb.userDeleteFailed = Failed to delete user ''{0}''!
+gb.time.justNow = just now
+gb.time.today = today
+gb.time.yesterday = yesterday
+gb.time.minsAgo = {0} mins ago
+gb.time.hoursAgo = {0} hours ago
+gb.time.daysAgo = {0} days ago
+gb.time.weeksAgo = {0} weeks ago
+gb.time.monthsAgo = {0} months ago
+gb.time.oneYearAgo = 1 year ago
+gb.time.yearsAgo = {0} years ago
+gb.duration.oneDay = 1 day
+gb.duration.days = {0} days
+gb.duration.oneMonth = 1 month
+gb.duration.months = {0} months
+gb.duration.oneYear = 1 year
+gb.duration.years = {0} years
+gb.authorizationControl = authorization control
+gb.allowAuthenticatedDescription = grant RW+ permission to all authenticated users
+gb.allowNamedDescription = grant fine-grained permissions to named users or teams
+gb.markdownFailure = Failed to parse Markdown content!
+gb.clearCache = clear cache
+gb.projects = projects
+gb.project = project
+gb.allProjects = all projects
+gb.copyToClipboard = copy to clipboard
+gb.fork = fork
+gb.forks = forks
+gb.forkRepository = fork {0}?
+gb.repositoryForked = {0} has been forked
+gb.repositoryForkFailed= fork has failed
+gb.personalRepositories = personal repositories
+gb.allowForks = allow forks
+gb.allowForksDescription = allow authorized users to fork this repository
+gb.forkedFrom = forked from
+gb.canFork = can fork
+gb.canForkDescription = can fork authorized repositories to personal repositories
+gb.myFork = view my fork
+gb.forksProhibited = forks prohibited
+gb.forksProhibitedWarning = this repository forbids forks
+gb.noForks = {0} has no forks
+gb.forkNotAuthorized = sorry, you are not authorized to fork {0}
+gb.forkInProgress = fork in progress
+gb.preparingFork = preparing your fork...
+gb.isFork = is fork
+gb.canCreate = can create
+gb.canCreateDescription = can create personal repositories
+gb.illegalPersonalRepositoryLocation = your personal repository must be located at \"{0}\"
+gb.verifyCommitter = verify committer
+gb.verifyCommitterDescription = require committer identity to match pushing Gitblt user account
+gb.verifyCommitterNote = all merges require "--no-ff" to enforce committer identity
+gb.repositoryPermissions = repository permissions
+gb.userPermissions = user permissions
+gb.teamPermissions = team permissions
+gb.add = add
+gb.noPermission = DELETE THIS PERMISSION
+gb.excludePermission = {0} (exclude)
+gb.viewPermission = {0} (view)
+gb.clonePermission = {0} (clone)
+gb.pushPermission = {0} (push)
+gb.createPermission = {0} (push, ref creation)
+gb.deletePermission = {0} (push, ref creation+deletion)
+gb.rewindPermission = {0} (push, ref creation+deletion+rewind)
+gb.permission = permission
+gb.regexPermission = this permission is set from regular expression \"{0}\"
+gb.accessDenied = access denied
+gb.busyCollectingGarbage = sorry, Gitblit is busy collecting garbage in {0}
+gb.gcPeriod = GC period
+gb.gcPeriodDescription = duration between garbage collections
+gb.gcThreshold = GC threshold
+gb.gcThresholdDescription = minimum total size of loose objects to trigger early garbage collection
+gb.ownerPermission = repository owner
+gb.administrator = admin
+gb.administratorPermission = Gitblit administrator
+gb.team = team
+gb.teamPermission = permission set by \"{0}\" team membership
+gb.missing = missing!
+gb.missingPermission = the repository for this permission is missing!
+gb.mutable = mutable
+gb.specified = specified
+gb.effective = effective
+gb.organizationalUnit = organizational unit
+gb.organization = organization
+gb.locality = locality
+gb.stateProvince = state or province
+gb.countryCode = country code
+gb.properties = properties
+gb.issued = issued
+gb.expires = expires
+gb.expired = expired
+gb.expiring = expiring
+gb.revoked = revoked
+gb.serialNumber = serial number
+gb.certificates = certificates
+gb.newCertificate = new certificate
+gb.revokeCertificate = revoke certificate
+gb.sendEmail = send email
+gb.passwordHint = password hint
+gb.ok = ok
+gb.invalidExpirationDate = invalid expiration date!
+gb.passwordHintRequired = password hint required!
+gb.viewCertificate = view certificate
+gb.subject = subject
+gb.issuer = issuer
+gb.validFrom = valid from
+gb.validUntil = valid until
+gb.publicKey = public key
+gb.signatureAlgorithm = signature algorithm
+gb.sha1FingerPrint = SHA-1 Fingerprint
+gb.md5FingerPrint = MD5 Fingerprint
+gb.reason = reason
+gb.revokeCertificateReason = Please select a reason for certificate revocation
+gb.unspecified = unspecified
+gb.keyCompromise = key compromise
+gb.caCompromise = CA compromise
+gb.affiliationChanged = affiliation changed
+gb.superseded = superseded
+gb.cessationOfOperation = cessation of operation
+gb.privilegeWithdrawn = privilege withdrawn
+gb.time.inMinutes = in {0} mins
+gb.time.inHours = in {0} hours
+gb.time.inDays = in {0} days
+gb.hostname = hostname
+gb.hostnameRequired = Please enter a hostname
+gb.newSSLCertificate = new server SSL certificate
+gb.newCertificateDefaults = new certificate defaults
+gb.duration = duration
+gb.certificateRevoked = Certificate {0,number,0} has been revoked
+gb.clientCertificateGenerated = Successfully generated new client certificate for {0}
+gb.sslCertificateGenerated = Successfully generated new server SSL certificate for {0}
+gb.newClientCertificateMessage = NOTE:\nThe 'password' is not the user's password, it is the password to protect the user's keystore. This password is not saved so you must also enter a 'hint' which will be included in the user's README instructions.
+gb.certificate = certificate
+gb.emailCertificateBundle = email client certificate bundle
+gb.pleaseGenerateClientCertificate = Please generate a client certificate for {0}
+gb.clientCertificateBundleSent = Client certificate bundle for {0} sent
+gb.enterKeystorePassword = Please enter the Gitblit keystore password
+gb.warning = warning
+gb.jceWarning = Your Java Runtime Environment does not have the \"JCE Unlimited Strength Jurisdiction Policy\" files.\nThis will limit the length of passwords you may use to encrypt your keystores to 7 characters.\nThese policy files are an optional download from Oracle.\n\nWould you like to continue and generate the certificate infrastructure anyway?\n\nAnswering No will direct your browser to Oracle's download page so that you may download the policy files.
+gb.maxActivityCommits = max activity commits
+gb.maxActivityCommitsDescription = maximum number of commits to contribute to the Activity page
+gb.noMaximum = no maximum
+gb.attributes = attributes
+gb.serveCertificate = serve https with this certificate
+gb.sslCertificateGeneratedRestart = Successfully generated new server SSL certificate for {0}.\nYou must restart Gitblit to use the new certificate.\n\nIf you are launching with the '--alias' parameter you will have to set that to ''--alias {0}''.
+gb.validity = validity
+gb.siteName = site name
+gb.siteNameDescription = short, descriptive name of your server
+gb.excludeFromActivity = exclude from activity page
+gb.isSparkleshared = repository is Sparkleshared
+gb.owners = owners
+gb.sessionEnded = Session has been closed
+gb.closeBrowser = Please close the browser to properly end the session.
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_es.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_es.properties new file mode 100644 index 00000000..210a75f9 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_es.properties @@ -0,0 +1,445 @@ +gb.repository = Repositorio
+gb.owner = Propietario
+gb.description = Descripci\u00F3n
+gb.lastChange = Actualizado
+gb.refs = Refs
+gb.tag = Etiqueta
+gb.tags = Etiquetas
+gb.author = Autor
+gb.committer = Consignador
+gb.commit = Consigna
+gb.tree = \u00C1rbol
+gb.parent = Antecesor
+gb.url = URL
+gb.history = Hist\u00F3rico
+gb.raw = Bruto
+gb.object = Objeto
+gb.ticketId = Id Ticket
+gb.ticketAssigned = Asignado
+gb.ticketOpenDate = Fecha de apertura
+gb.ticketState = Estado
+gb.ticketComments = Comentarios
+gb.view = Ver
+gb.local = Local
+gb.remote = Remoto
+gb.branches = Ramas
+gb.patch = Parche
+gb.diff = Dif
+gb.log = Reg.
+gb.moreLogs = M\u00E1s Consignas...
+gb.allTags = Todas las Etiquetas...
+gb.allBranches = Todas las Ramas...
+gb.summary = Resumen
+gb.ticket = Ticket
+gb.newRepository = Nuevo Repositorio
+gb.newUser = Nuevo usuario
+gb.commitdiff = Dif Consigna
+gb.tickets = Tickets
+gb.pageFirst = Primera
+gb.pagePrevious = Anterior
+gb.pageNext = Siguiente
+gb.head = HEAD
+gb.blame = Acuse
+gb.login = Idenfiticarse
+gb.logout = Salir
+gb.username = Usuario
+gb.password = Contrase\u00F1a
+gb.tagger = Etiquetador
+gb.moreHistory = M\u00E1s hist\u00F3ricos...
+gb.difftocurrent = Dif con actual
+gb.search = Buscar
+gb.searchForAuthor = Buscar consignas de autor por
+gb.searchForCommitter = Buscar consignas enviadas por
+gb.addition = Adici\u00F3n
+gb.modification = Modificaci\u00F3n
+gb.deletion = Eliminado
+gb.rename = Renombrar
+gb.metrics = Movimientos
+gb.stats = Estadísticas
+gb.markdown = Markdown
+gb.changedFiles = Archivos cambiados
+gb.filesAdded = {0} Archivos a\u00F1adidos
+gb.filesModified = {0} Archivos modificados
+gb.filesDeleted = {0} Archivos eliminados
+gb.filesCopied = {0} Archivos copiados
+gb.filesRenamed = {0} Archivos renombrados
+gb.missingUsername = Falta usuario
+gb.edit = Editar
+gb.searchTypeTooltip = Seleccionar tipo de b\u00FAsqueda
+gb.searchTooltip = Buscar {0}
+gb.delete = Eliminar
+gb.docs = Docs
+gb.accessRestriction = Restricci\u00F3n de acceso
+gb.name = Nombre
+gb.enableTickets = Habilitar tickets
+gb.enableDocs = Habilitar Docs
+gb.save = Guardar
+gb.showRemoteBranches = Mostrar ramas remotas
+gb.editUsers = Editar usuarios
+gb.confirmPassword = Confirmar contrase\u00F1a
+gb.restrictedRepositories = Repositorios restringidos
+gb.canAdmin = Puede Administrar
+gb.notRestricted = An\u00F3nimos pueden Ver, clonar y empujar
+gb.pushRestricted = Autentificados pueden empujar
+gb.cloneRestricted = Autentificados pueden clonar y empujar
+gb.viewRestricted = Autentificados pueden Ver, clonar y empujar
+gb.useTicketsDescription = Distribuir temas mediante Ticgit (s\u00F3lo lecura)
+gb.useDocsDescription = Enumerar documentaci\u00F3n Markdown en el Repositorio.
+gb.showRemoteBranchesDescription = Mostrar Ramas Remotas
+gb.canAdminDescription = Puede administrar el servidor de GitBlit
+gb.permittedUsers = Usuarios permitidos
+gb.isFrozen = Est\u00E1 congelado
+gb.isFrozenDescription = No se le puede empujar
+gb.zip = Zip
+gb.showReadme = Ver l\u00E9eme
+gb.showReadmeDescription = Mostrar el archivo \"l\u00E9eme\" de Markdown en la p\u00E1gina resumen
+gb.nameDescription = Usa '/' para agrupar repositorios. ej. librerias/mylibreria.git
+gb.ownerDescription = El propietario puede editar la configuraci\u00F3n del repositorio
+gb.blob = Objeto
+gb.commitActivityTrend = Tendencia de actividad del repositorio
+gb.commitActivityDOW = Actividad de consignas por d\u00EDa de la semana
+gb.commitActivityAuthors = Principales autores por actividad de consignas
+gb.feed = Sindicaci\u00F3n
+gb.cancel = Cancelar
+gb.changePassword = Cambiar contrase\u00F1a
+gb.isFederated = Est\u00E1 federado
+gb.federateThis = Federar este repositorio
+gb.federateOrigin = Federar desde el origen
+gb.excludeFromFederation = Excluir de la federaci\u00F3n
+gb.excludeFromFederationDescription = Bloquear a esta cuenta el recibir de instancias federadas de GitBlit
+gb.tokens = Tarjetas de federaci\u00F3n
+gb.tokenAllDescription = Todos los repositorios, usuarios y configuraciones
+gb.tokenUnrDescription = Todos los repositorios y usuarios
+gb.tokenJurDescription = Todos los repositorios
+gb.federatedRepositoryDefinitions = Definiciones del repositorio
+gb.federatedUserDefinitions = Definiciones del usuario
+gb.federatedSettingDefinitions = Definiciones de configuraci\u00F3n
+gb.proposals = Propuestas de federaci\u00F3n
+gb.received = Recibida
+gb.type = Tipo
+gb.token = Tarjeta
+gb.repositories = Repositorios
+gb.proposal = Propuesta
+gb.frequency = Frecuencia
+gb.folder = Carpeta
+gb.lastPull = \u00DAltimo recibo
+gb.nextPull = Siguiente recibo
+gb.inclusions = Inclusiones
+gb.exclusions = Exclusiones
+gb.registration = Registro
+gb.registrations = Registros de federaci\u00F3n
+gb.sendProposal = Proponer
+gb.status = Estado
+gb.origin = Origen
+gb.headRef = Rama por defecto (HEAD)
+gb.headRefDescription = Cambiar la Ref. a la que apunta HEAD ej. refs/heads/master
+gb.federationStrategy = Estrategia de federaci\u00F3n
+gb.federationRegistration = Registro de federaci\u00F3n
+gb.federationResults = Resultados de recibos federados
+gb.federationSets = Grupos de federaci\u00F3n
+gb.message = Mensaje
+gb.myUrlDescription = La URL p\u00FAblica y accesible de tu instancia de GitBlit
+gb.destinationUrl = Enviar a
+gb.destinationUrlDescription = La URL de la instancia de GitBlit a la que env\u00EDas tu propuesta
+gb.users = Usuarios
+gb.federation = Federaci\u00F3n
+gb.error = Error
+gb.refresh = Actualizar
+gb.browse = Buscar
+gb.clone = Clonar
+gb.filter = Filtrar
+gb.create = Crear
+gb.servers = Servidores
+gb.recent = Recientes
+gb.available = Disponible
+gb.selected = Seleccionados
+gb.size = Tama\u00F1o
+gb.downloading = Descargando
+gb.loading = Cargando
+gb.starting = Iniciando
+gb.general = General
+gb.settings = Configuraci\u00F3n
+gb.manage = Administrar
+gb.lastLogin = \u00DAltimo acceso
+gb.skipSizeCalculation = Saltar comprobaciones de tama\u00F1o
+gb.skipSizeCalculationDescription = No calcular el tama\u00F1o del repositorio (Reduce tiempo de carga de la p\u00E1gina)
+gb.skipSummaryMetrics = Saltar resumen de estad\u00EDsticas
+gb.skipSummaryMetricsDescription = No calcular estad\u00EDsticas (Reduce tiempo de carga de la p\u00E1gina)
+gb.accessLevel = Nivel de acceso
+gb.default = Predeterminado
+gb.setDefault = Ajustar por defecto
+gb.since = Desde
+gb.status = Estado
+gb.bootDate = Fecha de inicio
+gb.servletContainer = Contenedor ServLet
+gb.heapMaximum = Pila m\u00E1xima
+gb.heapAllocated = Pila asignada
+gb.heapUsed = Pila usada
+gb.free = Libre
+gb.version = Versi\u00F3n
+gb.releaseDate = Fecha de lanzamiento
+gb.date = Fecha
+gb.activity = Actividad
+gb.subscribe = Suscribir
+gb.branch = Rama
+gb.maxHits = Coincidencias m\u00E1ximas
+gb.recentActivity = Actividad reciente
+gb.recentActivityStats = \u00DAltimo(s) {0} d\u00EDa(s) / {1} Consigna(s) de {2} Autor(es)
+gb.recentActivityNone = \u00DAltimo(s) {0} d\u00EDa(s) / Ninguna
+gb.dailyActivity = Actividad diaria
+gb.activeRepositories = Repositorios activos
+gb.activeAuthors = Autores activos
+gb.commits = Consignas
+gb.teams = Equipos
+gb.teamName = Nombre del Equipo
+gb.teamMembers = Suscriptores
+gb.teamMemberships = Inscripciones
+gb.newTeam = Nuevo Equipo
+gb.permittedTeams = Equipos permitidos
+gb.emptyRepository = Repositorio vac\u00EDo
+gb.repositoryUrl = URL del Repositorio
+gb.mailingLists = Listas de correo
+gb.preReceiveScripts = Scripts para pre-recibo
+gb.postReceiveScripts = Scripts para post-recibo
+gb.hookScripts = Scripts enganchados
+gb.customFields = Campos Propios
+gb.customFieldsDescription = Campos Propios disponibles para los engachados Groovy
+gb.accessPermissions = Permisos de acceso
+gb.filters = Filtros
+gb.generalDescription = Configuraciones comunes
+gb.accessPermissionsDescription = Restringir acceso a usuarios y Equipos
+gb.accessPermissionsForUserDescription = Modificar inscripciones y especificar acceso a repositorios o restringirlos
+gb.accessPermissionsForTeamDescription = A\u00F1ada miembros al Equipo y conceda o restrinja acceso a repositorios.
+gb.federationRepositoryDescription = Compartir este repositorio con otros servidores GitBlit
+gb.hookScriptsDescription = Scripts Groovy ha ejecutar cuando empujen a este servidor.
+gb.reset = Reinicializa
+gb.pages = P\u00E1ginas
+gb.workingCopy = Copia de trabajo
+gb.workingCopyWarning = Este repositorio tiene una copia de trabajo y no se le puede empujar
+gb.query = Consulta
+gb.queryHelp = Se admite la sintaxis de consulta est\u00E1ndar.<p/>Por favor, lee el: <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Analizador sint\u00E1ctico de consultas de Lucene</a> para m\u00E1s detalles.
+gb.queryResults = Resultados {0} - {1} ({2} coincidencias)
+gb.noHits = Sin coincidencias
+gb.authored = Autor
+gb.committed = Consignado
+gb.indexedBranches = Ramas indexadas
+gb.indexedBranchesDescription = Selecciona las Ramas a incluir en tu \u00EDndice de Lucene
+gb.noIndexedRepositoriesWarning = Ninguno de tus repositorios est\u00E1 configurado para el indexado de Lucene
+gb.undefinedQueryWarning = \u00A1Consulta indefinida!
+gb.noSelectedRepositoriesWarning = \u00A1Por favor selecciona uno o m\u00E1s repositorios!
+gb.luceneDisabled = Indexado de Lucene deshabilitado
+gb.failedtoRead = Fallo de lectura
+gb.isNotValidFile = No es un archivo v\u00E1lido
+gb.failedToReadMessage = \u00A1Fallo al leer el mensaje por defecto de {0}!
+gb.passwordsDoNotMatch = \u00A1Las contrase\u00F1as no coinciden!
+gb.passwordTooShort = La contrase\u00F1a es muy corta. La longitud m\u00EDnima es de {0} caracteres.
+gb.passwordChanged = Contrase\u00F1a cambiada satisfactoriamente.
+gb.passwordChangeAborted = Cambio de contrase\u00F1a abortado.
+gb.pleaseSetRepositoryName = \u00A1Por favor introduce un nombre para el repositorio!
+gb.illegalLeadingSlash = Referencias a la carpeta ra\i00EDz (/) estu00E1n prohibidas.
+gb.illegalRelativeSlash = Referencias relativas a la carpeta (../) est\u00E1n prohibidas.
+gb.illegalCharacterRepositoryName = \u00A1Caracter ilegal ''{0}'' en el nombre del repositorio!
+gb.selectAccessRestriction = \u00A1Por favor selecciona la restricci\u00F3n de acceso!
+gb.selectFederationStrategy = \u00A1Por favor, selecciona la estrategia de federaci\u00F3n!
+gb.pleaseSetTeamName = \u00A1Por favor, introduce un nombre para el Equipo!
+gb.teamNameUnavailable = El nombre de Equipo ''{0}'' no est\u00E1 disponible.
+gb.teamMustSpecifyRepository = Debe especificar al menos un repositorio para el Equipo.
+gb.teamCreated = Nuevo Equipo ''{0}'' creado satisfactoriamente.
+gb.pleaseSetUsername = \u00A1Por favor, introduce un usuario!
+gb.usernameUnavailable = El usuario ''{0}'' no est\u00E1 disponible.
+gb.combinedMd5Rename = GitBlit est\u00E1 configurado para Hashes combinados md5. Debes introducir una nueva contrase\u00F1a para renombrar la cuenta.
+gb.userCreated = Nuevo usuario ''{0}'' creado satisfactoriamente.
+gb.couldNotFindFederationRegistration = \u00A1No se pudo encontrar el registro de federaci\u00F3n!
+gb.failedToFindGravatarProfile = Fallo al buscar el perfil Gravatar de {0}
+gb.branchStats = {0} consigna(s) y {1} etiqueta(s) en {2}
+gb.repositoryNotSpecified = /u00A1Repositorio no especificado!
+gb.repositoryNotSpecifiedFor = /u00A1Repositorio no especificado para {0}!
+gb.canNotLoadRepository = No se puede cargar el repositorio
+gb.commitIsNull = La consigna es nula
+gb.unauthorizedAccessForRepository = Acceso no autorizado al repositorio
+gb.failedToFindCommit = \u00A1Fallo al buscar la consigna \"{0}\" en {1} de {2} p\u00E1ginas!
+gb.couldNotFindFederationProposal = \u00A1No se puede encontrar una propuesta de federaci\u00F3n!
+gb.invalidUsernameOrPassword = \u00A1Usuario o contrase\u00F1a inv\u00E1lidos!
+gb.OneProposalToReview = Hay 1 petici\u00F3n de federaci\u00F3n esperando revisi\u00F3n.
+gb.nFederationProposalsToReview = Hay {0} peticiones de federaci\u00F3n esperando revisi\u00F3n.
+gb.couldNotFindTag = No se puede encontrar la etiqueta {0}
+gb.couldNotCreateFederationProposal = \u00A1No se puede crear una propuesta de federaci\u00F3n!
+gb.pleaseSetGitblitUrl = \u00A1Por favor, introduce la URL de tu GitBlit!
+gb.pleaseSetDestinationUrl = \u00A1Por favor, introduce la URL de destino para tu propuesta!
+gb.proposalReceived = Propuesta recibida satisfactoriamente por {0}.
+gb.noGitblitFound = Lo siento, {0} no puede encontrar una instancia de GitBlit en {1}.
+gb.noProposals = Lo siento, {0} no acepta propuestas en este momento.
+gb.noFederation = Lo siento, {0} no est\u00E1 configurado para Federar con ninguna instancia de GitBlit.
+gb.proposalFailed = /u00A1Lo siento, {0} no ha recibido ning\u00FAn dato de propuesta!
+gb.proposalError = /u00A1Lo siento, {0} informa de que ha ocurrido un error inesperado!
+gb.failedToSendProposal = /u00A1Fallo al enviar la propuesta!
+gb.userServiceDoesNotPermitAddUser = \u00A1{0} no permite a\u00F1adir una cuenta de usuario!
+gb.userServiceDoesNotPermitPasswordChanges = \u00A1{0} no permite cambio de contrase\u00F1a!
+gb.displayName = Nombre
+gb.emailAddress = Direcci\u00F3n de correo
+gb.errorAdminLoginRequired = La administración requiere identificarse
+gb.errorOnlyAdminMayCreateRepository = Sólo un administrador puede crear un repositorio
+gb.errorOnlyAdminOrOwnerMayEditRepository = Sólo un administrador o el propietario puede editar un repositorio
+gb.errorAdministrationDisabled = La administración está desactivada
+gb.lastNDays = \u00FAltimos {0} d\u00EDas
+gb.completeGravatarProfile = Perfil completo en Gravatar.com
+gb.none = nadie
+gb.line = L\u00EDenea
+gb.content = Contenido
+gb.empty = vac\u00EDo
+gb.inherited = heredado
+gb.deleteRepository = \u00BFBorrar el repositorio \"{0}\"?
+gb.repositoryDeleted = Repositorio ''{0}'' borrado.
+gb.repositoryDeleteFailed = \u00A1Fallo al borrar el repositorio ''{0}''!
+gb.deleteUser = \u00BFEliminar usuario\"{0}\"?
+gb.userDeleted = Usuario ''{0}'' eliminado.
+gb.userDeleteFailed = \u00A1Fallo al eliminar usuario ''{0}''!
+gb.time.justNow = hace poco
+gb.time.today = hoy
+gb.time.yesterday = ayer
+gb.time.minsAgo = hace {0} min
+gb.time.hoursAgo = hace {0} horas
+gb.time.daysAgo = hace {0} d\u00EDas
+gb.time.weeksAgo = hace {0} semanas
+gb.time.monthsAgo = hace {0} meses
+gb.time.oneYearAgo = hace 1 a\u00F1o
+gb.time.yearsAgo = hace {0} a\u00F1os
+gb.duration.oneDay = 1 d\u00EDa
+gb.duration.days = {0} d\u00EDas
+gb.duration.oneMonth = 1 mes
+gb.duration.months = {0} meses
+gb.duration.oneYear = 1 a\u00F1o
+gb.duration.years = {0} a\u00F1os
+gb.authorizationControl = Control de autorizaciones
+gb.allowAuthenticatedDescription = Permitir acceso a todos los usuarios registrados
+gb.allowNamedDescription = Permitir acceso a usuarios inscritos \u00F3 equipos
+gb.markdownFailure = \u00A1Fallo al analizar el contenido Markdown!
+gb.clearCache = Limpiar cache
+gb.projects = Proyectos
+gb.project = Proyecto
+gb.allProjects = Todos los proyectos
+gb.copyToClipboard = Copiar al portapapeles
+gb.fork = Bifurcar
+gb.forks = Bifurcados
+gb.forkRepository = \u00BFBifurcar {0}?
+gb.repositoryForked = {0} se ha bifurcado
+gb.repositoryForkFailed= Bifurcaci\u00F3n fallida
+gb.personalRepositories = Repositorios personales
+gb.allowForks = Permitir bifurcados
+gb.allowForksDescription = Permitir a usuarios autorizados bifurcar este repositorio
+gb.forkedFrom = Bifurcado de
+gb.canFork = Puede bifurcar
+gb.canForkDescription = Puede bifurcar repositorios permitidos ha sus repositorios personales
+gb.myFork = Ver mi bifurcado
+gb.forksProhibited = Prohibido bifurcar
+gb.forksProhibitedWarning = Este repositorio proh\u00EDbe bifurcarse
+gb.noForks = {0} no tiene bifurcados
+gb.forkNotAuthorized = Perdona, no est\u00E1s autorizado a bifurcar {0}
+gb.forkInProgress = Bifurcar en curso
+gb.preparingFork = Preparando tu bifurcaci\u00F3n...
+gb.isFork = Es bifurcado
+gb.canCreate = Puede crear
+gb.canCreateDescription = Puede crear repositorios personales
+gb.illegalPersonalRepositoryLocation = Tu repositorio personal debe estar ubicado en \"{0}\"
+gb.verifyCommitter = Consignador acreditado
+gb.verifyCommitterDescription = Require que la acreditaci\u00F3n del consignador coincida con la de la cuenta del usuario en Gitblt
+gb.verifyCommitterNote = es obligatorio "--no-ff" al empujar para que el consignador se acredite
+gb.repositoryPermissions = Permisos del repositorio
+gb.userPermissions = Permisos de usuarios
+gb.teamPermissions = Permisos de equipos
+gb.add = A\u00F1adir
+gb.noPermission = BORRAR ESTE PERMISO
+gb.excludePermission = {0} (excluir)
+gb.viewPermission = {0} (ver)
+gb.clonePermission = {0} (clonar)
+gb.pushPermission = {0} (empujar)
+gb.createPermission = {0} (empujar, ref creaci\u00F3n)
+gb.deletePermission = {0} (empujar, ref creaci\u00F3n+borrado)
+gb.rewindPermission = {0} (empujar, ref creaci\u00F3n+borrado+supresi\u00F3n)
+gb.permission = Permisos
+gb.regexPermission = Estos permisos se ajustan desde la expresi\u00F3n regulare \"{0}\"
+gb.accessDenied = Acceso denegado
+gb.busyCollectingGarbage = Perd\u00F3n, Gitblit est\u00E1 ocupado quitando basura de {0}
+gb.gcPeriod = Periodo para GC
+gb.gcPeriodDescription = Duraci\u00F3n entre periodos de limpieza
+gb.gcThreshold = L\u00EDmites para GC
+gb.gcThresholdDescription = Tama\u00F1o m\u00EDnimo total de objetos sueltos para activar la recolecci\u00F3n inmediata de basura
+gb.ownerPermission = Propietario del repositorio
+gb.administrator = Admin
+gb.administratorPermission = Administrador de Gitblit
+gb.team = Equipo
+gb.teamPermission = Permisos ajustados para \"{0}\" mienbros de equipo
+gb.missing = \u00A1Omitido!
+gb.missingPermission = \u00A1Falta el repositorio de este permiso!
+gb.mutable = Alterables
+gb.specified = Espec\u00EDficos
+gb.effective = Efectivos
+gb.organizationalUnit = Unidad de organizaci\u00F3n
+gb.organization = Organizaci\u00F3n
+gb.locality = Localidad
+gb.stateProvince = Estado o provincia
+gb.countryCode = C\u00F3digo postal
+gb.properties = Propiedades
+gb.issued = Publicado
+gb.expires = Expira
+gb.expired = Expirado
+gb.expiring = Concluido
+gb.revoked = Revocado
+gb.serialNumber = N\u00FAmero de serie
+gb.certificates = Certificados
+gb.newCertificate = Nuevo certificado
+gb.revokeCertificate = Revocar certificado
+gb.sendEmail = Enviar correo
+gb.passwordHint = Recordatorio de contrase\u00F1a
+gb.ok = ok
+gb.invalidExpirationDate = \u00A1La fecha de expiraci\u00F3n no es v\u00E1lida!
+gb.passwordHintRequired = \u00A1Se requiere una pista para la contrase\u00F1a!
+gb.viewCertificate = Ver certificado
+gb.subject = Asunto
+gb.issuer = Emisor
+gb.validFrom = V\u00E1lido desde
+gb.validUntil = V\u00E1lido hasta
+gb.publicKey = Clave p\u00FAblica
+gb.signatureAlgorithm = Algoritmo de firma
+gb.sha1FingerPrint = Huella digital SHA-1
+gb.md5FingerPrint = Huella digital MD5
+gb.reason = Motivo
+gb.revokeCertificateReason = Por favor, selecciona un motivo por el que revocas el certificado
+gb.unspecified = Sin especificar
+gb.keyCompromise = Clave de compromiso
+gb.caCompromise = Compromiso CA
+gb.affiliationChanged = Afiliaci\u00F3n cambiada
+gb.superseded = Sustituida
+gb.cessationOfOperation = Cese de operaci\u00F3n
+gb.privilegeWithdrawn = Privilegios retirados
+gb.time.inMinutes = en {0} mints
+gb.time.inHours = en {0} horas
+gb.time.inDays = en {0} d\u00EDas
+gb.hostname = Nombre de host
+gb.hostnameRequired = Por favor, introduzca un nombre de host
+gb.newSSLCertificate = Nuevo certificado SSL del servidor
+gb.newCertificateDefaults = Nuevo certificado predeterminado
+gb.duration = Duraci\u00F3n
+gb.certificateRevoked = El cretificado {0,n\u00FAmero,0} ha sido revocado
+gb.clientCertificateGenerated = Nuevo certificado de cliente generado correctamente para {0}
+gb.sslCertificateGenerated = Nuevo certificado de SSL generado correctamente para {0}
+gb.newClientCertificateMessage = AVISO:\nLa 'contrase\u00F1a' no es la contrase\u00F1a del usuario, es la contrase\u00F1a para proteger el almac\u00E9n de claves del usuario. Esta contrase\u00F1a no se guarda por lo que tambi\u00E9n debe introducirse una "pista" que ser\u00E1 incluida en las instrucciones LEEME del usuario.
+gb.certificate = Certificado
+gb.emailCertificateBundle = Correo del cliente para el paquete del certificado
+gb.pleaseGenerateClientCertificate = Por favor, genera un certificado de cliente para {0}
+gb.clientCertificateBundleSent = Paquete de certificado de cliente {0} enviado
+gb.enterKeystorePassword = Por favor, introduzca la contrase\u00F1a del almac\u00E9n de claves de Gitblit
+gb.warning = Advertencia
+gb.jceWarning = Tu entorno de trabajo JAVA no contiene los archivos \"JCE Unlimited Strength Jurisdiction Policy\".\nEsto limita la longitud de la contrase\u00F1a que puedes usuar para cifrar el almac\u00E9n de claves a 7 caracteres.\nEstos archivos opcionales puedes descargarlos desde Oracle.\n\n\u00BFQuieres continuar y generar la infraestructura de certificados de todos modos?\n\nSi respondes No tu navegador te dirigir\u00E1 a la p\u00E1gina de descarga de Oracle para que pueda descargar dichos archivos.
+gb.maxActivityCommits = Actividad m\u00E1xima de consignas
+gb.maxActivityCommitsDescription = N\u00FAmero m\u00E1ximo de consignas a incluir en la p\u00E1gina de actividad
+gb.noMaximum = Sin m\u00E1ximos
+gb.attributes = Atributos
+gb.serveCertificate = Servidor https con este certificado
+gb.sslCertificateGeneratedRestart = Certificado SSL generado correctamente para {0}.\nDebes reiniciar Gitblit para usar el nuevo certificado.\n\nSi lo has iniciado con la opci\u00F3n '--alias' deber\u00E1s ajustar dicha opci\u00F3n a ''--alias {0}''.
+gb.validity = Vigencia
+gb.siteName = Nombre del sitio
+gb.siteNameDescription = Nombre corto y descriptivo de tu servidor
+gb.excludeFromActivity = Excluir de la p\u00E1gina de actividad
+gb.sessionEnded = La sesi\u00F3n ha sido cerrada
+gb.closeBrowser = Porfavor cierre el navegador para terminar correctamente la sesi\u00F3n.
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_ja.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_ja.properties new file mode 100644 index 00000000..d0234f87 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_ja.properties @@ -0,0 +1,318 @@ +gb.repository = \u30ea\u30dd\u30b8\u30c8\u30ea
+gb.owner = \u6240\u6709\u8005
+gb.description = \u8aac\u660e
+gb.lastChange = \u6700\u5f8c\u306e\u5909\u66f4
+gb.refs = refs
+gb.tag = \u30bf\u30b0
+gb.tags = \u30bf\u30b0
+gb.author = \u4f5c\u8005
+gb.committer = \u30b3\u30df\u30c3\u30bf\u30fc
+gb.commit = \u30b3\u30df\u30c3\u30c8
+gb.tree = tree
+gb.parent = \u89aa
+gb.url = URL
+gb.history = \u5c65\u6b74
+gb.raw = raw
+gb.object = object
+gb.ticketId = \u30c1\u30b1\u30c3\u30c8ID
+gb.ticketAssigned = \u5272\u308a\u5f53\u3066\u6e08\u307f
+gb.ticketOpenDate = \u30aa\u30fc\u30d7\u30f3\u65e5
+gb.ticketState = \u72b6\u614b
+gb.ticketComments = \u30b3\u30e1\u30f3\u30c8
+gb.view = \u898b\u308b
+gb.local = \u30ed\u30fc\u30ab\u30eb
+gb.remote = \u30ea\u30e2\u30fc\u30c8
+gb.branches = \u30d6\u30e9\u30f3\u30c1
+gb.patch = \u30d1\u30c3\u30c1
+gb.diff = diff
+gb.log = \u30ed\u30b0
+gb.moreLogs = more commits...
+gb.allTags = all tags...
+gb.allBranches = all branches...
+gb.summary = \u6982\u8981
+gb.ticket = \u30c1\u30b1\u30c3\u30c8
+gb.newRepository = \u30ea\u30dd\u30b8\u30c8\u30ea\u4f5c\u6210
+gb.newUser = \u30e6\u30fc\u30b6\u30fc\u4f5c\u6210
+gb.commitdiff = commitdiff
+gb.tickets = \u30c1\u30b1\u30c3\u30c8
+gb.pageFirst = first
+gb.pagePrevious = prev
+gb.pageNext = next
+gb.head = HEAD
+gb.blame = \u6ce8\u91c8\u5c65\u6b74
+gb.login = \u30ed\u30b0\u30a4\u30f3
+gb.logout = \u30ed\u30b0\u30a2\u30a6\u30c8
+gb.username = \u30e6\u30fc\u30b6\u30fc\u540d
+gb.password = \u30d1\u30b9\u30ef\u30fc\u30c9
+gb.tagger = tagger
+gb.moreHistory = more history...
+gb.difftocurrent = diff to current
+gb.search = \u691c\u7d22
+gb.searchForAuthor = Search for commits authored by
+gb.searchForCommitter = Search for commits committed by
+gb.addition = \u8ffd\u52a0
+gb.modification = \u4fee\u6b63
+gb.deletion = \u524a\u9664
+gb.rename = \u30ea\u30cd\u30fc\u30e0
+gb.metrics = \u6307\u6a19
+gb.stats = \u7d71\u8a08
+gb.markdown = markdown
+gb.changedFiles = \u5909\u66f4\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb
+gb.filesAdded = {0} \u30d5\u30a1\u30a4\u30eb\u304c\u8ffd\u52a0
+gb.filesModified = {0} \u30d5\u30a1\u30a4\u30eb\u304c\u5909\u66f4
+gb.filesDeleted = {0} \u30d5\u30a1\u30a4\u30eb\u304c\u524a\u9664
+gb.filesCopied = {0} \u30d5\u30a1\u30a4\u30eb\u304c\u30b3\u30d4\u30fc
+gb.filesRenamed = {0} \u30d5\u30a1\u30a4\u30eb\u304c\u30ea\u30cd\u30fc\u30e0
+gb.missingUsername = Missing Username
+gb.edit = \u7de8\u96c6
+gb.searchTypeTooltip = Select Search Type
+gb.searchTooltip = Search {0}
+gb.delete = \u524a\u9664
+gb.docs = docs
+gb.accessRestriction = \u30a2\u30af\u30bb\u30b9\u5236\u9650
+gb.name = \u540d\u524d
+gb.enableTickets = \u30c1\u30b1\u30c3\u30c8\u3092\u6709\u52b9\u5316
+gb.enableDocs = \u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u3092\u6709\u52b9\u5316
+gb.save = \u4fdd\u5b58
+gb.showRemoteBranches = \u30ea\u30e2\u30fc\u30c8\u30d6\u30e9\u30f3\u30c1\u3092\u8868\u793a
+gb.editUsers = \u30e6\u30fc\u30b6\u30fc\u7de8\u96c6
+gb.confirmPassword = \u30d1\u30b9\u30ef\u30fc\u30c9(\u78ba\u8a8d)
+gb.restrictedRepositories = \u5236\u9650\u30ea\u30dd\u30b8\u30c8\u30ea
+gb.canAdmin = \u7ba1\u7406\u8005
+gb.notRestricted = \u533f\u540d view, clone, & push
+gb.pushRestricted = \u8a8d\u8a3c push
+gb.cloneRestricted = \u8a8d\u8a3c clone & push
+gb.viewRestricted = \u8a8d\u8a3c view, clone, & push
+gb.useTicketsDescription = \u5206\u6563\u30a4\u30b7\u30e5\u30fc\u7ba1\u7406\u30b7\u30b9\u30c6\u30e0 Ticgit \u3092\u5229\u7528\u3059\u308b
+gb.useDocsDescription = \u30ea\u30dd\u30b8\u30c8\u30ea\u5185\u306e Markdown \u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u3092\u5217\u6319\u3059\u308b
+gb.showRemoteBranchesDescription = \u30ea\u30e2\u30fc\u30c8\u30d6\u30e9\u30f3\u30c1\u3092\u8868\u793a\u3059\u308b
+gb.canAdminDescription = Gitblit\u30b5\u30fc\u30d0\u30fc\u306e\u7ba1\u7406\u8005
+gb.permittedUsers = \u8a31\u53ef\u3055\u308c\u305f\u30e6\u30fc\u30b6\u30fc
+gb.isFrozen = \u51cd\u7d50
+gb.isFrozenDescription = push\u64cd\u4f5c\u3092\u62d2\u5426\u3059\u308b
+gb.zip = zip
+gb.showReadme = readme\u8868\u793a
+gb.showReadmeDescription = \"readme\" Markdown\u30d5\u30a1\u30a4\u30eb\u3092\u6982\u8981\u30da\u30fc\u30b8\u306b\u8868\u793a\u3059\u308b
+gb.nameDescription = \u30ea\u30dd\u30b8\u30c8\u30ea\u3092\u30b0\u30eb\u30fc\u30d7\u5316\u3059\u308b\u306b\u306f '/' \u3092\u4f7f\u3046\u3002 e.g. libraries/mycoollib.git
+gb.ownerDescription = \u6240\u6709\u8005\u306f\u30ea\u30dd\u30b8\u30c8\u30ea\u306e\u8a2d\u5b9a\u3092\u5909\u66f4\u3067\u304d\u308b
+gb.blob = blob
+gb.commitActivityTrend = commit activity trend
+gb.commitActivityDOW = commit activity by day of week
+gb.commitActivityAuthors = primary authors by commit activity
+gb.feed = \u30d5\u30a3\u30fc\u30c9
+gb.cancel = \u30ad\u30e3\u30f3\u30bb\u30eb
+gb.changePassword = \u30d1\u30b9\u30ef\u30fc\u30c9\u5909\u66f4
+gb.isFederated = is federated
+gb.federateThis = federate this repository
+gb.federateOrigin = federate the origin
+gb.excludeFromFederation = \u30d5\u30a7\u30c7\u30ec\u30fc\u30b7\u30e7\u30f3\u304b\u3089\u9664\u5916\u3059\u308b
+gb.excludeFromFederationDescription = block federated Gitblit instances from pulling this account
+gb.tokens = federation tokens
+gb.tokenAllDescription = all repositories, users, & settings
+gb.tokenUnrDescription = all repositories & users
+gb.tokenJurDescription = all repositories
+gb.federatedRepositoryDefinitions = repository definitions
+gb.federatedUserDefinitions = user definitions
+gb.federatedSettingDefinitions = setting definitions
+gb.proposals = federation proposals
+gb.received = received
+gb.type = type
+gb.token = token
+gb.repositories = \u30ea\u30dd\u30b8\u30c8\u30ea
+gb.proposal = proposal
+gb.frequency = frequency
+gb.folder = \u30d5\u30a9\u30eb\u30c0\u30fc
+gb.lastPull = last pull
+gb.nextPull = next pull
+gb.inclusions = inclusions
+gb.exclusions = exclusions
+gb.registration = registration
+gb.registrations = federation registrations
+gb.sendProposal = propose
+gb.status = status
+gb.origin = origin
+gb.headRef = \u30c7\u30d5\u30a9\u30eb\u30c8\u30d6\u30e9\u30f3\u30c1 (HEAD)
+gb.headRefDescription = HEAD \u306e\u30ea\u30f3\u30af\u5148 ref \u3092\u5909\u66f4\u3059\u308b e.g. refs/heads/master
+gb.federationStrategy = \u30d5\u30a7\u30c7\u30ec\u30fc\u30b7\u30e7\u30f3\u6226\u7565
+gb.federationRegistration = federation registration
+gb.federationResults = federation pull results
+gb.federationSets = federation sets
+gb.message = \u30e1\u30c3\u30bb\u30fc\u30b8
+gb.myUrlDescription = the publicly accessible url for your Gitblit instance
+gb.destinationUrl = send to
+gb.destinationUrlDescription = the url of the Gitblit instance to send your proposal
+gb.users = \u30e6\u30fc\u30b6\u30fc
+gb.federation = \u30d5\u30a7\u30c7\u30ec\u30fc\u30b7\u30e7\u30f3
+gb.error = \u30a8\u30e9\u30fc
+gb.refresh = \u66f4\u65b0
+gb.browse = \u95b2\u89a7
+gb.clone = clone
+gb.filter = \u30d5\u30a3\u30eb\u30bf\u30fc
+gb.create = \u4f5c\u6210
+gb.servers = \u30b5\u30fc\u30d0\u30fc
+gb.recent = recent
+gb.available = available
+gb.selected = selected
+gb.size = \u30b5\u30a4\u30ba
+gb.downloading = downloading
+gb.loading = loading
+gb.starting = starting
+gb.general = \u4e00\u822c
+gb.settings = \u8a2d\u5b9a
+gb.manage = \u7ba1\u7406
+gb.lastLogin = last login
+gb.skipSizeCalculation = \u30b5\u30a4\u30ba\u8a08\u7b97\u3092\u30b9\u30ad\u30c3\u30d7
+gb.skipSizeCalculationDescription = \u30ea\u30dd\u30b8\u30c8\u30ea\u306e\u30b5\u30a4\u30ba\u3092\u8a08\u7b97\u3057\u306a\u3044 (\u30da\u30fc\u30b8\u306e\u30ed\u30fc\u30c9\u6642\u9593\u3092\u524a\u6e1b)
+gb.skipSummaryMetrics = \u6982\u8981\u3067\u306e\u6307\u6a19\u3092\u30b9\u30ad\u30c3\u30d7
+gb.skipSummaryMetricsDescription = \u6982\u8981\u30da\u30fc\u30b8\u3067\u6307\u6a19\u3092\u8a08\u7b97\u3057\u306a\u3044 (\u30da\u30fc\u30b8\u306e\u30ed\u30fc\u30c9\u6642\u9593\u3092\u524a\u6e1b)
+gb.accessLevel = \u30a2\u30af\u30bb\u30b9\u30ec\u30d9\u30eb
+gb.default = \u30c7\u30d5\u30a9\u30eb\u30c8
+gb.setDefault = \u30c7\u30d5\u30a9\u30eb\u30c8\u306b\u8a2d\u5b9a
+gb.since = since
+gb.status = status
+gb.bootDate = boot date
+gb.servletContainer = \u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30b3\u30f3\u30c6\u30ca
+gb.heapMaximum = \u6700\u5927\u30d2\u30fc\u30d7
+gb.heapAllocated = \u78ba\u4fdd\u6e08\u307f\u30d2\u30fc\u30d7
+gb.heapUsed = \u4f7f\u7528\u30d2\u30fc\u30d7
+gb.free = free
+gb.version = \u30d0\u30fc\u30b8\u30e7\u30f3
+gb.releaseDate = \u30ea\u30ea\u30fc\u30b9\u65e5
+gb.date = date
+gb.activity = \u6d3b\u52d5
+gb.subscribe = \u8cfc\u8aad
+gb.branch = \u30d6\u30e9\u30f3\u30c1
+gb.maxHits = \u6700\u5927\u30d2\u30c3\u30c8\u6570
+gb.recentActivity = \u6700\u8fd1\u306e\u6d3b\u52d5
+gb.recentActivityStats = \u3053\u3053{0}\u65e5\u9593 / {2}\u4eba\u306e\u4f5c\u8005\u304b\u3089 {1}\u30b3\u30df\u30c3\u30c8
+gb.recentActivityNone = \u3053\u3053{0}\u65e5\u9593 / \u306a\u3057
+gb.dailyActivity = \u6bce\u65e5\u306e\u6d3b\u52d5
+gb.activeRepositories = \u6d3b\u767a\u306a\u30ea\u30dd\u30b8\u30c8\u30ea
+gb.activeAuthors = \u6d3b\u767a\u306a\u4f5c\u8005
+gb.commits = \u30b3\u30df\u30c3\u30c8
+gb.teams = \u30c1\u30fc\u30e0
+gb.teamName = \u30c1\u30fc\u30e0\u540d
+gb.teamMembers = \u30c1\u30fc\u30e0\u30e1\u30f3\u30d0\u30fc
+gb.teamMemberships = \u30c1\u30fc\u30e0
+gb.newTeam = \u30c1\u30fc\u30e0\u4f5c\u6210
+gb.permittedTeams = \u8a31\u53ef\u3055\u308c\u305f\u30c1\u30fc\u30e0
+gb.emptyRepository = \u7a7a\u306e\u30ea\u30dd\u30b8\u30c8\u30ea
+gb.repositoryUrl = \u30ea\u30dd\u30b8\u30c8\u30ea\u306eURL
+gb.mailingLists = \u30e1\u30fc\u30ea\u30f3\u30b0\u30ea\u30b9\u30c8
+gb.preReceiveScripts = pre-receive \u30b9\u30af\u30ea\u30d7\u30c8
+gb.postReceiveScripts = post-receive \u30b9\u30af\u30ea\u30d7\u30c8
+gb.hookScripts = \u30d5\u30c3\u30af\u30b9\u30af\u30ea\u30d7\u30c8
+gb.customFields = custom fields
+gb.customFieldsDescription = custom fields available to Groovy hooks
+gb.accessPermissions = \u30a2\u30af\u30bb\u30b9\u6a29\u9650
+gb.filters = \u30d5\u30a3\u30eb\u30bf\u30fc
+gb.generalDescription = \u4e00\u822c\u7684\u306a\u8a2d\u5b9a
+gb.accessPermissionsDescription = \u30e6\u30fc\u30b6\u30fc\u3068\u30c1\u30fc\u30e0\u3067\u30a2\u30af\u30bb\u30b9\u3092\u5236\u9650\u3059\u308b
+gb.accessPermissionsForUserDescription = \u30c1\u30fc\u30e0\u3092\u8a2d\u5b9a\u3059\u308b\u3001\u7279\u5b9a\u306e\u5236\u9650\u30ea\u30dd\u30b8\u30c8\u30ea\u3078\u306e\u30a2\u30af\u30bb\u30b9\u3092\u8a31\u53ef\u3059\u308b
+gb.accessPermissionsForTeamDescription = \u30c1\u30fc\u30e0\u30e1\u30f3\u30d0\u30fc\u3092\u8a2d\u5b9a\u3059\u308b\u3001\u7279\u5b9a\u306e\u5236\u9650\u30ea\u30dd\u30b8\u30c8\u30ea\u3078\u306e\u30a2\u30af\u30bb\u30b9\u3092\u8a31\u53ef\u3059\u308b
+gb.federationRepositoryDescription = \u3053\u306e\u30ea\u30dd\u30b8\u30c8\u30ea\u3092\u4ed6\u306e Gitblit \u30b5\u30fc\u30d0\u30fc\u3068\u5171\u6709\u3059\u308b
+gb.hookScriptsDescription = \u3053\u306e Gitblit \u30b5\u30fc\u30d0\u30fc\u306b push \u3055\u308c\u305f\u6642\u306b Groovy \u30b9\u30af\u30ea\u30d7\u30c8\u3092\u5b9f\u884c\u3059\u308b
+gb.reset = \u30ea\u30bb\u30c3\u30c8
+gb.pages = \u30da\u30fc\u30b8
+gb.workingCopy = \u4f5c\u696d\u30b3\u30d4\u30fc
+gb.workingCopyWarning = \u3053\u306e\u30ea\u30dd\u30b8\u30c8\u30ea\u306b\u306f\u4f5c\u696d\u30b3\u30d4\u30fc\u304c\u3042\u308b\u305f\u3081 push \u3067\u304d\u307e\u305b\u3093
+gb.query = \u30af\u30a8\u30ea\u30fc
+gb.queryHelp = \u6a19\u6e96\u7684\u306a\u30af\u30a8\u30ea\u30fc\u66f8\u5f0f\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u3059\u3002<p/><p/>\u8a73\u7d30\u306f <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> \u3092\u53c2\u7167\u3057\u3066\u4e0b\u3055\u3044\u3002
+gb.queryResults = results {0} - {1} ({2} hits)
+gb.noHits = no hits
+gb.authored = authored
+gb.committed = committed
+gb.indexedBranches = \u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3059\u308b\u30d6\u30e9\u30f3\u30c1
+gb.indexedBranchesDescription = Lucene \u3067\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3059\u308b\u30d6\u30e9\u30f3\u30c1\u3092\u9078\u629e
+gb.noIndexedRepositoriesWarning = Lucene \u3067\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3059\u308b\u3088\u3046\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u308b\u30ea\u30dd\u30b8\u30c8\u30ea\u304c\u3042\u308a\u307e\u305b\u3093
+gb.undefinedQueryWarning = \u30af\u30a8\u30ea\u30fc\u304c\u672a\u5b9a\u7fa9\u3067\u3059!
+gb.noSelectedRepositoriesWarning = \u3072\u3068\u3064\u4ee5\u4e0a\u306e\u30ea\u30dd\u30b8\u30c8\u30ea\u3092\u9078\u629e\u3057\u3066\u4e0b\u3055\u3044!
+gb.luceneDisabled = Lucene \u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306f\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+gb.failedtoRead = \u8aad\u307f\u8fbc\u307f\u5931\u6557
+gb.isNotValidFile = is not a valid file
+gb.failedToReadMessage = {0}\u304b\u3089\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u30e1\u30c3\u30bb\u30fc\u30b8\u306e\u8aad\u307f\u8fbc\u307f\u306b\u5931\u6557\u3057\u307e\u3057\u305f!
+gb.passwordsDoNotMatch = \u30d1\u30b9\u30ef\u30fc\u30c9\u304c\u4e00\u81f4\u3057\u307e\u305b\u3093!
+gb.passwordTooShort = \u30d1\u30b9\u30ef\u30fc\u30c9\u304c\u77ed\u3059\u304e\u307e\u3059\u3002\u6700\u4f4e\u3067{0}\u6587\u5b57\u5fc5\u8981\u3067\u3059\u3002
+gb.passwordChanged = \u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u5909\u66f4\u3057\u307e\u3057\u305f\u3002
+gb.passwordChangeAborted = \u30d1\u30b9\u30ef\u30fc\u30c9\u306e\u5909\u66f4\u3092\u4e2d\u6b62\u3057\u307e\u3057\u305f\u3002
+gb.pleaseSetRepositoryName = \u30ea\u30dd\u30b8\u30c8\u30ea\u540d\u3092\u8a2d\u5b9a\u3057\u3066\u4e0b\u3055\u3044\u3002
+gb.illegalLeadingSlash = \u5148\u982d\u306e\u30eb\u30fc\u30c8\u30d5\u30a9\u30eb\u30c0\u53c2\u7167(/)\u306f\u7981\u6b62\u3067\u3059\u3002
+gb.illegalRelativeSlash = \u76f8\u5bfe\u30d5\u30a9\u30eb\u30c0\u53c2\u7167(../)\u306f\u7981\u6b62\u3067\u3059\u3002
+gb.illegalCharacterRepositoryName = \u30ea\u30dd\u30b8\u30c8\u30ea\u540d\u306b''{0}''\u4e0d\u6b63\u306a\u6587\u5b57\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3059!
+gb.selectAccessRestriction = \u30a2\u30af\u30bb\u30b9\u5236\u9650\u3092\u9078\u629e\u3057\u3066\u4e0b\u3055\u3044!
+gb.selectFederationStrategy = \u30d5\u30a7\u30c7\u30ec\u30fc\u30b7\u30e7\u30f3\u6226\u7565\u3092\u9078\u629e\u3057\u3066\u4e0b\u3055\u3044!
+gb.pleaseSetTeamName = \u30c1\u30fc\u30e0\u540d\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044!
+gb.teamNameUnavailable = \u30c1\u30fc\u30e0\u540d''{0}''\u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002.
+gb.teamMustSpecifyRepository = \u6700\u4f4e\u3067\u3082\u30ea\u30dd\u30b8\u30c8\u30ea\u3092\u30c1\u30fc\u30e0\u306b\u4e00\u3064\u6307\u5b9a\u3057\u3066\u4e0b\u3055\u3044\u3002
+gb.teamCreated = \u65b0\u3057\u3044\u30c1\u30fc\u30e0''{0}''\u3092\u4f5c\u6210\u3057\u307e\u3057\u305f\u3002
+gb.pleaseSetUsername = \u30e6\u30fc\u30b6\u30fc\u540d\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044!
+gb.usernameUnavailable = \u30e6\u30fc\u30b6\u30fc\u540d''{0}''\u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002
+gb.combinedMd5Rename = Gitblit\u306fcombined-md5\u30d1\u30b9\u30ef\u30fc\u30c9\u30cf\u30c3\u30b7\u30e5\u304c\u6709\u52b9\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059\u3002\u30a2\u30ab\u30a6\u30f3\u30c8\u540d\u306e\u5909\u66f4\u3067\u306f\u65b0\u3057\u3044\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044\u3002
+gb.userCreated = \u65b0\u3057\u3044\u30e6\u30fc\u30b6\u30fc''{0}''\u3092\u4f5c\u6210\u3057\u307e\u3057\u305f\u3002
+gb.couldNotFindFederationRegistration = \u30d5\u30a7\u30c7\u30ec\u30fc\u30b7\u30e7\u30f3\u767b\u9332\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f!
+gb.failedToFindGravatarProfile = Failed to find Gravatar profile for {0}
+gb.branchStats = {0} commits and {1} tags in {2}
+gb.repositoryNotSpecified = Repository not specified!
+gb.repositoryNotSpecifiedFor = Repository not specified for {0}!
+gb.canNotLoadRepository = \u30ea\u30dd\u30b8\u30c8\u30ea\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093
+gb.commitIsNull = \u30b3\u30df\u30c3\u30c8\u304c\u7a7a\u3067\u3059
+gb.unauthorizedAccessForRepository = \u30ea\u30dd\u30b8\u30c8\u30ea\u3078\u306e\u30a2\u30af\u30bb\u30b9\u6a29\u304c\u3042\u308a\u307e\u305b\u3093
+gb.failedToFindCommit = Failed to find commit \"{0}\" in {1} for {2} page!
+gb.couldNotFindFederationProposal = Could not find federation proposal!
+gb.invalidUsernameOrPassword = \u30e6\u30fc\u30b6\u30fc\u540d\u307e\u305f\u306f\u30d1\u30b9\u30ef\u30fc\u30c9\u304c\u7121\u52b9\u3067\u3059!
+gb.OneProposalToReview = There is 1 federation proposal awaiting review.
+gb.nFederationProposalsToReview = There are {0} federation proposals awaiting review.
+gb.couldNotFindTag = {0} \u30bf\u30b0\u3092\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f
+gb.couldNotCreateFederationProposal = Could not create federation proposal!
+gb.pleaseSetGitblitUrl = Please enter your Gitblit url!
+gb.pleaseSetDestinationUrl = Please enter a destination url for your proposal!
+gb.proposalReceived = Proposal successfully received by {0}.
+gb.noGitblitFound = Sorry, {0} could not find a Gitblit instance at {1}.
+gb.noProposals = Sorry, {0} is not accepting proposals at this time.
+gb.noFederation = Sorry, {0} is not configured to federate with any Gitblit instances.
+gb.proposalFailed = Sorry, {0} did not receive any proposal data!
+gb.proposalError = Sorry, {0} reports that an unexpected error occurred!
+gb.failedToSendProposal = Failed to send proposal!
+gb.userServiceDoesNotPermitAddUser = {0} does not permit adding a user account!
+gb.userServiceDoesNotPermitPasswordChanges = {0} does not permit password changes!
+gb.displayName = display name
+gb.emailAddress = email address
+gb.errorAdminLoginRequired = Administration requires a login
+gb.errorOnlyAdminMayCreateRepository = Only an administrator may create a repository
+gb.errorOnlyAdminOrOwnerMayEditRepository = Only an administrator or the owner may edit a repository
+gb.errorAdministrationDisabled = Administration is disabled
+gb.lastNDays = last {0} days
+gb.completeGravatarProfile = Complete profile on Gravatar.com
+gb.none = none
+gb.line = line
+gb.content = content
+gb.empty = empty
+gb.inherited = inherited
+gb.deleteRepository = Delete repository \"{0}\"?
+gb.repositoryDeleted = Repository ''{0}'' deleted.
+gb.repositoryDeleteFailed = Failed to delete repository ''{0}''!
+gb.deleteUser = Delete user \"{0}\"?
+gb.userDeleted = User ''{0}'' deleted.
+gb.userDeleteFailed = Failed to delete user ''{0}''!
+gb.time.justNow = \u305f\u3063\u305f\u4eca
+gb.time.today = \u4eca\u65e5
+gb.time.yesterday = \u6628\u65e5
+gb.time.minsAgo = {0}\u5206\u524d
+gb.time.hoursAgo = {0}\u6642\u9593\u524d
+gb.time.daysAgo = {0}\u65e5\u524d
+gb.time.weeksAgo = {0}\u9031\u524d
+gb.time.monthsAgo = {0}\u6708\u524d
+gb.time.oneYearAgo = 1\u5e74\u524d
+gb.time.yearsAgo = {0}\u5e74\u524d
+gb.duration.oneDay = 1\u65e5
+gb.duration.days = {0}\u65e5
+gb.duration.oneMonth = 1\u30f6\u6708
+gb.duration.months = {0}\u30f6\u6708
+gb.duration.oneYear = 1\u5e74
+gb.duration.years = {0}\u5e74
+gb.authorizationControl = \u6a29\u9650\u5236\u5fa1
+gb.allowAuthenticatedDescription = \u5168\u3066\u306e\u8a8d\u8a3c\u6e08\u307f\u30e6\u30fc\u30b6\u30fc\u3078\u30a2\u30af\u30bb\u30b9\u3092\u8a31\u53ef\u3059\u308b
+gb.allowNamedDescription = \u6307\u5b9a\u3057\u305f\u540d\u524d\u306e\u30e6\u30fc\u30b6\u30fc/\u30c1\u30fc\u30e0\u3078\u30a2\u30af\u30bb\u30b9\u3092\u8a31\u53ef\u3059\u308b
+gb.markdownFailure = Markdown \u306e\u30d1\u30fc\u30b9\u306b\u5931\u6557\u3057\u307e\u3057\u305f!
+gb.sessionEnded = Session has been closed
+gb.closeBrowser = Please close the browser to properly end the session.
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_ko.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_ko.properties new file mode 100644 index 00000000..42915df8 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_ko.properties @@ -0,0 +1,445 @@ +gb.repository = \uC800\uC7A5\uC18C +gb.owner = \uC18C\uC720\uC790 +gb.description = \uC124\uBA85 +gb.lastChange = \uCD5C\uADFC \uBCC0\uACBD +gb.refs = refs +gb.tag = \uD0DC\uADF8 +gb.tags = \uD0DC\uADF8 +gb.author = \uC791\uC131\uC790 +gb.committer = \uCEE4\uBBF8\uD130 +gb.commit = \uCEE4\uBC0B +gb.tree = \uD2B8\uB9AC +gb.parent = \uBD80\uBAA8 +gb.url = URL +gb.history = \uD788\uC2A4\uD1A0\uB9AC +gb.raw = raw +gb.object = object +gb.ticketId = \uD2F0\uCF13 id +gb.ticketAssigned = \uD560\uB2F9 +gb.ticketOpenDate = \uC5F4\uB9B0 \uB0A0\uC790 +gb.ticketState = \uC0C1\uD0DC +gb.ticketComments = \uCF54\uBA58\uD2B8 +gb.view = \uBCF4\uAE30 +gb.local = \uB85C\uCEEC +gb.remote = \uB9AC\uBAA8\uD2B8 +gb.branches = \uBE0C\uB79C\uCE58 +gb.patch = \uD328\uCE58 +gb.diff = \uCC28\uC774 +gb.log = \uB85C\uADF8 +gb.moreLogs = \uCEE4\uBC0B \uB354 \uBCF4\uAE30... +gb.allTags = \uBAA8\uB4E0 \uD0DC\uADF8... +gb.allBranches = \uBAA8\uB4E0 \uBE0C\uB79C\uCE58... +gb.summary = \uC694\uC57D +gb.ticket = \uD2F0\uCF13 +gb.newRepository = \uC0C8 \uC800\uC7A5\uC18C +gb.newUser = \uB0B4 \uC0AC\uC6A9\uC790 +gb.commitdiff = \uCEE4\uBC0B\uBE44\uAD50 +gb.tickets = \uD2F0\uCF13 +gb.pageFirst = \uCCAB +gb.pagePrevious = \uC774\uC804 +gb.pageNext = \uB2E4\uC74C +gb.head = HEAD +gb.blame = blame +gb.login = \uB85C\uADF8\uC778 +gb.logout = \uB85C\uADF8\uC544\uC6C3 +gb.username = \uC720\uC800\uB124\uC784 +gb.password = \uD328\uC2A4\uC6CC\uB4DC +gb.tagger = \uD0DC\uAC70 +gb.moreHistory = \uD788\uC2A4\uD1A0\uB9AC \uB354 \uBCF4\uAE30... +gb.difftocurrent = \uD604\uC7AC\uC640 \uBE44\uAD50 +gb.search = \uAC80\uC0C9 +gb.searchForAuthor = \uCEE4\uBC0B\uC744 \uC791\uC131\uC790\uB85C \uAC80\uC0C9 +gb.searchForCommitter = \uCEE4\uBC0B\uC744 \uCEE4\uBC0B\uD130\uB85C \uAC80\uC0C9 +gb.addition = \uCD94\uAC00 +gb.modification = \uBCC0\uACBD +gb.deletion = \uC0AD\uC81C +gb.rename = \uC774\uB984\uBCC0\uACBD +gb.metrics = \uBA54\uD2B8\uB9AD +gb.stats = \uC0C1\uD0DC +gb.markdown = \uB9C8\uD06C\uB2E4\uC6B4 +gb.changedFiles = \uD30C\uC77C \uBCC0\uACBD\uB428 +gb.filesAdded = {0} \uD30C\uC77C \uCD94\uAC00\uB428 +gb.filesModified = {0} \uD30C\uC77C \uBCC0\uACBD\uB428 +gb.filesDeleted = {0} \uD30C\uC77C \uC0AD\uC81C\uB428 +gb.filesCopied = {0} \uD30C\uC77C \uBCF5\uC0AC\uB428 +gb.filesRenamed = {0} \uD30C\uC77C \uC774\uB984 \uBCC0\uACBD\uB428 +gb.missingUsername = \uC720\uC800\uB124\uC784 \uB204\uB77D +gb.edit = \uC218\uC815 +gb.searchTypeTooltip = \uAC80\uC0C9 \uD0C0\uC785 \uC120\uD0DD +gb.searchTooltip = {0} \uAC80\uC0C9 +gb.delete = \uC0AD\uC81C +gb.docs = \uBB38\uC11C +gb.accessRestriction = \uC811\uC18D \uC81C\uD55C +gb.name = \uC774\uB984 +gb.enableTickets = \uD2F0\uCF13 \uC0AC\uC6A9 +gb.enableDocs = \uBB38\uC11C \uC0AC\uC6A9 +gb.save = \uC800\uC7A5 +gb.showRemoteBranches = \uB9AC\uBAA8\uD2B8 \uBE0C\uB79C\uCE58 \uBCF4\uAE30 +gb.editUsers = \uC720\uC800 \uC218\uC815 +gb.confirmPassword = \uD328\uC2A4\uC6CC\uB4DC \uD655\uC778 +gb.restrictedRepositories = \uC81C\uD55C\uB41C \uC800\uC7A5\uC18C +gb.canAdmin = \uAD00\uB9AC \uAC00\uB2A5 +gb.notRestricted = \uC775\uBA85 view, clone, & push +gb.pushRestricted = \uD5C8\uC6A9\uB41C \uC720\uC800\uB9CC push +gb.cloneRestricted = \uD5C8\uC6A9\uB41C \uC720\uC800\uB9CC clone & push +gb.viewRestricted = \uD5C8\uC6A9\uB41C \uC720\uC800\uB9CC view, clone, & push +gb.useTicketsDescription = Ticgit(\uBD84\uC0B0 \uD2F0\uCF13 \uC2DC\uC2A4\uD15C) \uC774\uC288 \uC0AC\uC6A9 +gb.useDocsDescription = \uC800\uC7A5\uC18C \uC788\uB294 \uB9C8\uD06C\uB2E4\uC6B4 \uBB38\uC11C \uC0AC\uC6A9 +gb.showRemoteBranchesDescription = \uB9AC\uBAA8\uD2B8 \uBE0C\uB79C\uCE58 \uBCF4\uAE30 +gb.canAdminDescription = Gitblit \uAD00\uB9AC \uAD8C\uD55C \uBD80\uC5EC +gb.permittedUsers = \uD5C8\uC6A9\uB41C \uC0AC\uC6A9\uC790 +gb.isFrozen = \uD504\uB9AC\uC9D5\uB428 +gb.isFrozenDescription = \uD478\uC2DC \uCC28\uB2E8 +gb.zip = zip +gb.showReadme = \uB9AC\uB4DC\uBBF8(readme) \uBCF4\uAE30 +gb.showReadmeDescription = \uC694\uC57D\uD398\uC774\uC9C0\uC5D0\uC11C \"readme\" \uB9C8\uD06C\uB2E4\uC6B4 \uD30C\uC77C \uBCF4\uAE30 +gb.nameDescription = \uC800\uC7A5\uC18C\uB97C \uADF8\uB8F9\uC73C\uB85C \uBB36\uC73C\uB824\uBA74 '/' \uB97C \uC0AC\uC6A9. \uC608) libraries/reponame.git +gb.ownerDescription = \uC18C\uC720\uC790\uB294 \uC800\uC7A5\uC18C \uC124\uC815\uC744 \uBCC0\uACBD\uD560 \uC218 \uC788\uC74C +gb.blob = blob +gb.commitActivityTrend = \uCEE4\uBC0B \uD65C\uB3D9 \uD2B8\uB79C\uB4DC +gb.commitActivityDOW = 1\uC8FC\uC77C\uC758 \uC77C\uB2E8\uC704 \uCEE4\uBC0B \uD65C\uB3D9 +gb.commitActivityAuthors = \uCEE4\uBC0B \uD65C\uB3D9\uC758 \uC8FC \uC791\uC131\uC790 +gb.feed = \uD53C\uB4DC +gb.cancel = \uCDE8\uC18C +gb.changePassword = \uD328\uC2A4\uC6CC\uB4DC \uBCC0\uACBD +gb.isFederated = \uD398\uB354\uB808\uC774\uC158\uB428 +gb.federateThis = \uC774 \uC800\uC7A5\uC18C\uB97C \uD398\uB354\uB808\uC774\uC158\uD568 +gb.federateOrigin = origin \uC5D0 \uD398\uB354\uB808\uC774\uC158 +gb.excludeFromFederation = \uD398\uB354\uB808\uC774\uC158 \uC81C\uC678 +gb.excludeFromFederationDescription = \uC774 \uACC4\uC815\uC73C\uB85C \uD480\uB9C1\uB418\uB294 \uD398\uB7EC\uB808\uC774\uC158 \uB41C Gitblit \uC778\uC2A4\uD134\uC2A4 \uCC28\uB2E8 +gb.tokens = \uD398\uB354\uB808\uC774\uC158 \uD1A0\uD070 +gb.tokenAllDescription = \uBAA8\uB4E0 \uC800\uC7A5\uC18C, \uD1A0\uD070, \uC0AC\uC6A9\uC790 & \uC124\uC815 +gb.tokenUnrDescription = \uBAA8\uB4E0 \uC800\uC7A5\uC18C & \uC0AC\uC6A9\uC790 +gb.tokenJurDescription = \uBAA8\uB4E0 \uC800\uC7A5\uC18C +gb.federatedRepositoryDefinitions = \uC800\uC7A5\uC18C \uC815\uC758 +gb.federatedUserDefinitions = \uC0AC\uC6A9\uC790 \uC815\uC758 +gb.federatedSettingDefinitions = \uC124\uC815 \uC815\uC758 +gb.proposals = \uD398\uB354\uB808\uC774\uC158 \uC81C\uC548 +gb.received = \uC218\uC2E0\uD568 +gb.type = \uD0C0\uC785 +gb.token = \uD1A0\uD070 +gb.repositories = \uC800\uC7A5\uC18C +gb.proposal = \uC81C\uC548 +gb.frequency = \uBE48\uB3C4 +gb.folder = \uD3F4\uB354 +gb.lastPull = \uB9C8\uC9C0\uB9C9 \uD480 +gb.nextPull = \uB2E4\uC74C \uD480 +gb.inclusions = \uD3EC\uD568 +gb.exclusions = \uC81C\uC678 +gb.registration = \uB4F1\uB85D +gb.registrations = \uD398\uB354\uB808\uC774\uC158 \uB4F1\uB85D +gb.sendProposal = \uC81C\uC548\uD558\uAE30 +gb.status = \uC0C1\uD0DC +gb.origin = origin +gb.headRef = \uB514\uD3F4\uD2B8 \uBE0C\uB79C\uCE58(HEAD) +gb.headRefDescription = \uB514\uD3F4\uD2B8 \uBE0C\uB79C\uCE58\uB97C \uC785\uB825. \uC608) refs/heads/master +gb.federationStrategy = \uD398\uB354\uB808\uC774\uC158 \uC815\uCC45 +gb.federationRegistration = \uD398\uB354\uB808\uC774\uC158 \uB4F1\uB85D +gb.federationResults = \uD398\uB354\uB808\uC774\uC158 \uD480 \uACB0\uACFC +gb.federationSets = \uD398\uB354\uB808\uC774\uC158 \uC14B +gb.message = \uBA54\uC2DC\uC9C0 +gb.myUrlDescription = \uACF5\uAC1C\uB418\uC5B4 \uC811\uC18D\uD560 \uC218 \uC788\uB294 Gitblit \uC778\uC2A4\uD134\uC2A4 url +gb.destinationUrl = \uB85C \uBCF4\uB0C4 +gb.destinationUrlDescription = \uC81C\uC548\uC744 \uC804\uC1A1\uD560 \uB300\uC0C1 Gitblit \uC778\uC2A4\uD134\uC2A4\uC758 url +gb.users = \uC720\uC800 +gb.federation = \uD398\uB354\uB808\uC774\uC158 +gb.error = \uC5D0\uB7EC +gb.refresh = \uC0C8\uB85C\uACE0\uCE68 +gb.browse = \uBE0C\uB77C\uC6B0\uC988 +gb.clone = clone +gb.filter = \uD544\uD130 +gb.create = \uC0DD\uC131 +gb.servers = \uC11C\uBC84 +gb.recent = recent +gb.available = \uAC00\uB2A5\uD55C +gb.selected = \uC120\uD0DD\uB41C +gb.size = \uD06C\uAE30 +gb.downloading = \uB2E4\uC6B4\uB85C\uB4DC\uC911 +gb.loading = \uB85C\uB529\uC911 +gb.starting = \uC2DC\uC791\uC911 +gb.general = \uC77C\uBC18 +gb.settings = \uC138\uD305 +gb.manage = \uAD00\uB9AC +gb.lastLogin = \uB9C8\uC9C0\uB9C9 \uB85C\uADF8\uC778 +gb.skipSizeCalculation = \uD06C\uAE30 \uACC4\uC0B0 \uBB34\uC2DC +gb.skipSizeCalculationDescription = \uC800\uC7A5\uC18C \uD06C\uAE30 \uACC4\uC0B0\uD558\uC9C0 \uC54A\uC74C (\uD398\uC774\uC9C0 \uB85C\uB529 \uC2DC\uAC04 \uB2E8\uCD95\uB428) +gb.skipSummaryMetrics = \uBA54\uD2B8\uB9AD \uC694\uC57D \uBB34\uC2DC +gb.skipSummaryMetricsDescription = \uC694\uC57D \uD398\uC9C0\uC774\uC5D0\uC11C \uBA54\uD2B8\uB9AD \uACC4\uC0B0\uD558\uC9C0 \uC54A\uC74C (\uD398\uC774\uC9C0 \uB85C\uB529 \uC2DC\uAC04 \uB2E8\uCD95\uB428) +gb.accessLevel = \uC811\uC18D \uB808\uBCA8 +gb.default = \uB514\uD3F4\uD2B8 +gb.setDefault = \uB514\uD3F4\uD2B8 \uC124\uC815 +gb.since = since +gb.status = \uC0C1\uD0DC +gb.bootDate = \uBD80\uD305 \uC77C\uC790 +gb.servletContainer = \uC11C\uBE14\uB9BF \uCEE8\uD14C\uC774\uB108 +gb.heapMaximum = \uB9E5\uC2DC\uBA48 \uD799 +gb.heapAllocated = \uD560\uB2F9\uB41C \uD799 +gb.heapUsed = \uC0AC\uC6A9\uB41C \uD799 +gb.free = \uD504\uB9AC +gb.version = \uBC84\uC804 +gb.releaseDate = \uB9B4\uB9AC\uC988 \uB0A0\uC9DC +gb.date = date +gb.activity = \uC561\uD2F0\uBE44\uD2F0 +gb.subscribe = \uAD6C\uB3C5 +gb.branch = \uBE0C\uB79C\uCE58 +gb.maxHits = \uB9E5\uC2A4\uD788\uD2B8 +gb.recentActivity = \uCD5C\uADFC \uC561\uD2F0\uBE44\uD2F0 +gb.recentActivityStats = \uC9C0\uB09C {0} \uC77C / {2} \uC5D0 \uC758\uD574 {1} \uAC1C \uCEE4\uBC0B \uB428 +gb.recentActivityNone = \uC9C0\uB09C {0} \uC77C / \uC5C6\uC74C +gb.dailyActivity = \uC77C\uC77C \uC561\uD2F0\uBE44\uD2F0 +gb.activeRepositories = \uC0AC\uC6A9\uC911\uC778 \uC800\uC7A5\uC18C +gb.activeAuthors = \uC0AC\uC6A9\uC911\uC778 \uC791\uC131\uC790 +gb.commits = \uCEE4\uBC0B +gb.teams = \uD300 +gb.teamName = \uD300 \uC774\uB984 +gb.teamMembers = \uD300 \uBA64\uBC84 +gb.teamMemberships = \uD300 \uB9F4\uBC84\uC27D +gb.newTeam = \uC0C8\uB85C\uC6B4 \uD300 +gb.permittedTeams = \uD5C8\uC6A9\uB41C \uD300 +gb.emptyRepository = \uBE48 \uC800\uC7A5\uC18C +gb.repositoryUrl = \uC800\uC7A5\uC18C url +gb.mailingLists = \uBA54\uC77C\uB9C1 \uB9AC\uC2A4\uD2B8 +gb.preReceiveScripts = pre-receive \uC2A4\uD06C\uB9BD\uD2B8 +gb.postReceiveScripts = post-receive \uC2A4\uD06C\uB9BD\uD2B8 +gb.hookScripts = \uD6C4\uD06C \uC2A4\uD06C\uB9BD\uD2B8 +gb.customFields = \uC0AC\uC6A9\uC790 \uD544\uB4DC +gb.customFieldsDescription = \uADF8\uB8E8\uBE44 \uD6C5\uC5D0 \uC0AC\uC6A9\uC790 \uD544\uB4DC \uC0AC\uC6A9 \uAC00\uB2A5 +gb.accessPermissions = \uC811\uC18D \uAD8C\uD55C +gb.filters = \uD544\uD130 +gb.generalDescription = \uC77C\uBC18 \uC124\uC815 +gb.accessPermissionsDescription = \uC720\uC800\uC640 \uD300\uC73C\uB85C \uC811\uC18D\uAD8C\uD55C \uBD80\uC5EC +gb.accessPermissionsForUserDescription = \uD300\uC744 \uC9C0\uC815\uD558\uAC70\uB098 \uC811\uC18D \uAD8C\uD55C\uC744 \uC9C0\uC815\uD560 \uC800\uC7A5\uC18C \uC120\uD0DD +gb.accessPermissionsForTeamDescription = \uD300 \uB9F4\uBC84\uB97C \uC120\uD0DD\uD558\uACE0, \uC811\uC18D \uAD8C\uD55C\uC744 \uC9C0\uC815\uD560 \uC800\uC7A5\uC18C \uC120\uD0DD +gb.federationRepositoryDescription = \uC774 \uC800\uC7A5\uC18C\uB97C \uB2E4\uB978 Gitblit \uC11C\uBC84\uC640 \uACF5\uC720 +gb.hookScriptsDescription = \uC774 Gitblit \uC11C\uBC84\uC5D0 \uD478\uC2DC\uB418\uBA74 \uADF8\uB8E8\uBE44(Groovy) \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uC2E4\uD589 +gb.reset = \uB9AC\uC14B +gb.pages = \uD398\uC774\uC9C0 +gb.workingCopy = \uC6CC\uD0B9 \uCE74\uD53C +gb.workingCopyWarning = \uC774 \uC800\uC7A5\uC18C\uB294 \uC6CC\uD0B9\uCE74\uD53C\uB97C \uAC00\uC9C0\uACE0 \uC788\uACE0 \uD478\uC2DC\uB97C \uBC1B\uC744 \uC218 \uC5C6\uC74C +gb.query = \uCFFC\uB9AC +gb.queryHelp = \uD45C\uC900 \uCFFC\uB9AC \uBB38\uBC95\uC744 \uC9C0\uC6D0.<p/><p/>\uC790\uC138\uD55C \uAC83\uC744 \uC6D0\uD55C\uB2E4\uBA74 <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> \uC744 \uBC29\uBB38\uD574 \uC8FC\uC138\uC694. +gb.queryResults = \uAC80\uC0C9\uACB0\uACFC {0} - {1} ({2}\uAC1C \uAC80\uC0C9\uB428) +gb.noHits = \uAC80\uC0C9 \uACB0\uACFC \uC5C6\uC74C +gb.authored = \uAC00 \uC791\uC131\uD568. +gb.committed = \uCEE4\uBC0B\uB428 +gb.indexedBranches = \uC778\uB371\uC2F1\uD560 \uBE0C\uB79C\uCE58 +gb.indexedBranchesDescription = \uB8E8\uC2E0 \uC778\uB371\uC2A4\uC5D0 \uD3EC\uD568\uD560 \uBE0C\uB79C\uCE58 \uC120\uD0DD +gb.noIndexedRepositoriesWarning = \uC800\uC7A5\uC18C\uAC00 \uB8E8\uC2E0 \uC778\uB371\uC2F1\uC5D0 \uC124\uC815\uB418\uC9C0 \uC54A\uC74C +gb.undefinedQueryWarning = \uCFFC\uB9AC \uC9C0\uC815\uB418\uC9C0 \uC54A\uC74C! +gb.noSelectedRepositoriesWarning = \uD558\uB098 \uB610\uB294 \uADF8 \uC774\uC0C1\uC758 \uC800\uC7A5\uC18C\uB97C \uC120\uD0DD\uD558\uC138\uC694! +gb.luceneDisabled = \uB8E8\uC2E0 \uC778\uB371\uC2F1 \uC911\uC9C0\uB428 +gb.failedtoRead = \uC77C\uAE30 \uC2E4\uD328 +gb.isNotValidFile = \uC720\uD6A8\uD55C \uD30C\uC77C\uC774 \uC544\uB2D8 +gb.failedToReadMessage = {0}\uC5D0\uC11C \uB514\uD3F4\uD2B8 \uBA54\uC2DC\uC9C0 \uC77C\uAE30 \uC2E4\uD328! +gb.passwordsDoNotMatch = \uD328\uC2A4\uC6CC\uB4DC\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC544\uC694! +gb.passwordTooShort = \uD328\uC2A4\uC6CC\uB4DC\uAC00 \uB108\uBB34 \uC9E7\uC544\uC694. \uC801\uC5B4\uB3C4 {0} \uAC1C \uBB38\uC790\uC5EC\uC57C \uD569\uB2C8\uB2E4. +gb.passwordChanged = \uD328\uC2A4\uC6CC\uB4DC\uAC00 \uBCC0\uACBD \uC131\uACF5. +gb.passwordChangeAborted = \uD328\uC2A4\uC6CC\uB4DC \uBCC0\uACBD \uCDE8\uC18C\uB428. +gb.pleaseSetRepositoryName = \uC800\uC7A5\uC18C \uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694! +gb.illegalLeadingSlash = \uC800\uC7A5\uC18C \uC774\uB984 \uB610\uB294 \uD3F4\uB354\uB294 (/) \uB85C \uC2DC\uC791\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. +gb.illegalRelativeSlash = \uC0C1\uB300 \uACBD\uB85C \uC9C0\uC815 (../) \uC740 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.. +gb.illegalCharacterRepositoryName = \uBB38\uC790 ''{0}'' \uC800\uC7A5\uC18C \uC774\uB984\uC5D0 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC5B4\uC694! +gb.selectAccessRestriction = \uC811\uC18D \uAD8C\uD55C\uC744 \uC120\uD0DD\uD558\uC138\uC694! +gb.selectFederationStrategy = \uD398\uB354\uB808\uC774\uC158 \uC815\uCC45\uC744 \uC120\uD0DD\uD558\uC138\uC694! +gb.pleaseSetTeamName = \uD300\uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694! +gb.teamNameUnavailable = ''{0}'' \uD300\uC740 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC5B4\uC694. +gb.teamMustSpecifyRepository = \uD300\uC740 \uC801\uC5B4\uB3C4 \uD558\uB098\uC758 \uC800\uC7A5\uC18C\uB97C \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4. +gb.teamCreated = \uC0C8\uB85C\uC6B4 \uD300 ''{0}'' \uC0DD\uC131 \uC644\uB8CC. +gb.pleaseSetUsername = \uC720\uC800\uB124\uC784\uC744 \uC785\uB825\uD558\uC138\uC694! +gb.usernameUnavailable = ''{0}'' \uC720\uC800\uB124\uC784\uC740 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC5B4\uC694. +gb.combinedMd5Rename = Gitblit \uC740 combined-md5 \uD574\uC2F1 \uD328\uC2A4\uC6CC\uB4DC\uB85C \uC124\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uACC4\uC815 \uC774\uB984 \uBCC0\uACBD \uC2DC \uC0C8 \uD328\uC2A4\uC6CC\uB4DC\uB97C \uC785\uB825\uD574\uC57C \uD569\uB2C8\uB2E4. +gb.userCreated = \uC0C8\uB85C\uC6B4 \uC720\uC800 ''{0}'' \uC0DD\uC131 \uC644\uB8CC. +gb.couldNotFindFederationRegistration = \uD398\uB354\uB808\uC774\uC158 \uB4F1\uB85D\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4! +gb.failedToFindGravatarProfile = {0} \uC758 Gravatar \uD504\uB85C\uD30C\uC77C \uCC3E\uAE30 \uC2E4\uD328 +gb.branchStats = {2} \uC548\uC5D0 {0} \uCEE4\uBC0B {1} \uD0DC\uADF8 +gb.repositoryNotSpecified = \uC800\uC7A5\uC18C\uAC00 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC74C! +gb.repositoryNotSpecifiedFor = {0} \uB97C \uC704\uD55C \uC800\uC7A5\uC18C\uAC00 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC74C! +gb.canNotLoadRepository = \uC800\uC7A5\uC18C\uB97C \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC74C +gb.commitIsNull = \uB110 \uCEE4\uBC0B +gb.unauthorizedAccessForRepository = \uC800\uC7A5\uC18C\uC5D0 \uC811\uADFC \uD5C8\uC6A9\uB418\uC9C0 \uC54A\uC74C +gb.failedToFindCommit = \uCEE4\uBC0B\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC74C \"{0}\" in {1} for {2} \uD398\uC774\uC9C0! +gb.couldNotFindFederationProposal = \uD398\uB354\uB808\uC774\uC158 \uC81C\uC548\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4! +gb.invalidUsernameOrPassword = \uC798\uBABB\uB41C \uC720\uC800\uB124\uC784 \uB610\uB294 \uD328\uC2A4\uC6CC\uB4DC! +gb.OneProposalToReview = \uB9AC\uBDF0\uB97C \uAE30\uB2E4\uB9AC\uACE0 \uC788\uB294 1\uAC1C\uC758 \uD398\uB354\uB808\uC774\uC158 \uC81C\uC548\uC774 \uC788\uC2B5\uB2C8\uB2E4. +gb.nFederationProposalsToReview = \uB9AC\uBDF0\uB97C \uAE30\uB2E4\uB9AC\uACE0 \uC788\uB294 {0} \uAC1C\uC758 \uD398\uB354\uB808\uC774\uC158 \uC81C\uC548\uC774 \uC788\uC2B5\uB2C8\uB2E4. +gb.couldNotFindTag = \uD0DC\uADF8 {0} \uB97C(\uC744) \uCC3E\uC744 \uC218 \uC5C6\uC74C +gb.couldNotCreateFederationProposal = \uD398\uB354\uB808\uC774\uC158 \uC81C\uC548 \uC0DD\uC131 \uC2E4\uD328! +gb.pleaseSetGitblitUrl = Gitblit url \uC744 \uC785\uB825\uD558\uC138\uC694! +gb.pleaseSetDestinationUrl = \uB2F9\uC2E0\uC758 \uC81C\uC548\uC5D0 \uB300\uD55C \uB300\uC0C1 url \uC744 \uC785\uB825\uD558\uC138\uC694! +gb.proposalReceived = {0} \uC758 \uC81C\uC548 \uC131\uACF5\uC801 \uC218\uC2E0 +gb.noGitblitFound = \uC8C4\uC1A1\uD569\uB2C8\uB2E4, Gitblit \uC778\uC2A4\uD134\uC2A4 {1} \uC5D0\uC11C {0} \uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. +gb.noProposals = \uC8C4\uC1A1\uD569\uB2C8\uB2E4, \uC774\uBC88\uC5D0\uB294 {0} \uC758 \uC81C\uC548\uC744 \uC218\uC6A9\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. +gb.noFederation = \uC8C4\uC1A1\uD569\uB2C8\uB2E4, {0} \uC5D0\uB294 \uD398\uB354\uB808\uC774\uC158 \uC124\uC815\uB41C Gitblit \uC778\uC2A4\uD134\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. +gb.proposalFailed = \uC8C4\uC1A1\uD569\uB2C8\uB2E4, {0} \uC5D0\uB294 \uC81C\uC548 \uB370\uC774\uD130\uB97C \uBC1B\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. +gb.proposalError = \uC8C4\uC1A1\uD569\uB2C8\uB2E4, {0} \uC5D0 \uB300\uD55C \uC624\uB958 \uBC1C\uC0DD \uBCF4\uACE0 +gb.failedToSendProposal = \uC81C\uC548 \uBCF4\uB0B4\uAE30 \uC2E4\uD328! +gb.userServiceDoesNotPermitAddUser = {0} \uC0C8\uB85C\uC6B4 \uC720\uC800\uB97C \uCD94\uAC00\uD560 \uC218 \uC5C6\uC74C! +gb.userServiceDoesNotPermitPasswordChanges = {0} \uD328\uC2A4\uC6CC\uB4DC\uB97C \uBCC0\uACBD\uD560 \uC218 \uC5C6\uC74C! +gb.displayName = \uD45C\uC2DC\uB418\uB294 \uC774\uB984 +gb.emailAddress = \uC774\uBA54\uC77C \uC8FC\uC18C +gb.errorAdminLoginRequired = \uAD00\uB9AC\uB97C \uC704\uD574\uC11C\uB294 \uB85C\uADF8\uC778\uC774 \uD544\uC694 +gb.errorOnlyAdminMayCreateRepository = \uAD00\uB9AC\uC790\uB9CC \uC800\uC7A5\uC18C\uB97C \uB9CC\uB4E4\uC218 \uC788\uC74C +gb.errorOnlyAdminOrOwnerMayEditRepository = \uAD00\uB9AC\uC790\uC640 \uC18C\uC720\uC790\uB9CC \uC800\uC7A5\uC18C\uB97C \uC218\uC815\uD560 \uC218 \uC788\uC74C +gb.errorAdministrationDisabled = \uAD00\uB9AC\uAE30\uB2A5 \uBE44\uD65C\uC131\uD654\uB428 +gb.lastNDays = {0} \uC77C\uC804 +gb.completeGravatarProfile = Gravatar.com \uC5D0 \uD504\uB85C\uD30C\uC77C \uC0DD\uC131\uB428 +gb.none = none +gb.line = \uB77C\uC778 +gb.content = \uB0B4\uC6A9 +gb.empty = empty +gb.inherited = \uC0C1\uC18D +gb.deleteRepository = \"{0}\" \uC800\uC7A5\uC18C\uB97C \uC0AD\uC81C\uD560\uAE4C\uC694? +gb.repositoryDeleted = ''{0}'' \uC800\uC7A5\uC18C \uC0AD\uC81C\uB428. +gb.repositoryDeleteFailed = ''{0}'' \uC800\uC7A5\uC18C \uC0AD\uC81C \uC2E4\uD328! +gb.deleteUser = \"{0}\" \uC0AC\uC6A9\uC790 \uC0AD\uC81C? +gb.userDeleted = ''{0}'' \uC0AC\uC6A9\uC790 \uC0AD\uC81C\uB428. +gb.userDeleteFailed = ''{0}'' \uC0AC\uC6A9\uC790 \uC0AD\uC81C \uC2E4\uD328! +gb.time.justNow = \uC9C0\uAE08 +gb.time.today = \uC624\uB298 +gb.time.yesterday = \uC5B4\uC81C +gb.time.minsAgo = {0} \uBD84 \uC804 +gb.time.hoursAgo = {0} \uC2DC\uAC04 \uC804 +gb.time.daysAgo = {0} \uC77C \uC804 +gb.time.weeksAgo = {0} \uC8FC \uC804 +gb.time.monthsAgo = {0} \uB2EC \uC804 +gb.time.oneYearAgo = 1 \uB144 \uC804 +gb.time.yearsAgo = {0} \uB144 \uC804 +gb.duration.oneDay = 1 \uC77C +gb.duration.days = {0} \uC77C +gb.duration.oneMonth = 1 \uAC1C\uC6D4 +gb.duration.months = {0} \uAC1C\uC6D4 +gb.duration.oneYear = 1 \uB144 +gb.duration.years = {0} \uB144 +gb.authorizationControl = \uC778\uC99D \uC81C\uC5B4 +gb.allowAuthenticatedDescription = \uBAA8\uB4E0 \uC778\uC99D\uB41C \uC720\uC800\uC5D0\uAC8C \uAD8C\uD55C \uBD80\uC5EC +gb.allowNamedDescription = \uC774\uB984\uC73C\uB85C \uC720\uC800\uB098 \uD300\uC5D0\uAC8C \uAD8C\uD55C \uBD80\uC5EC +gb.markdownFailure = \uB9C8\uD06C\uB2E4\uC6B4 \uCEE8\uD150\uD2B8 \uD30C\uC2F1 \uC624\uB958! +gb.clearCache = \uCE90\uC2DC \uC9C0\uC6B0\uAE30 +gb.projects = \uD504\uB85C\uC81D\uD2B8\uB4E4 +gb.project = \uD504\uB85C\uC81D\uD2B8 +gb.allProjects = \uBAA8\uB4E0 \uD504\uB85C\uC81D\uD2B8 +gb.copyToClipboard = \uD074\uB9BD\uBCF4\uB4DC\uC5D0 \uBCF5\uC0AC +gb.fork = \uD3EC\uD06C +gb.forks = \uD3EC\uD06C +gb.forkRepository = fork {0}? +gb.repositoryForked = {0} \uD3EC\uD06C\uB428 +gb.repositoryForkFailed= \uD3EC\uD06C\uC2E4\uD328 +gb.personalRepositories = \uAC1C\uC778 \uC800\uC7A5\uC18C +gb.allowForks = \uD3EC\uD06C \uD5C8\uC6A9 +gb.allowForksDescription = \uC774 \uC800\uC7A5\uC18C\uB97C \uC778\uC99D\uB41C \uC720\uC800\uC5D0\uAC70 \uD3EC\uD06C \uD5C8\uC6A9 +gb.forkedFrom = forked from +gb.canFork = \uD3EC\uD06C \uAC00\uB2A5 +gb.canForkDescription = \uD5C8\uC6A9\uB41C \uC800\uC7A5\uC18C\uB97C \uAC1C\uC778 \uC800\uC7A5\uC18C\uC5D0 \uD3EC\uD06C\uD560 \uC218 \uC788\uC74C +gb.myFork = \uB0B4 \uD3EC\uD06C \uBCF4\uAE30 +gb.forksProhibited = \uD3EC\uD06C \uCC28\uB2E8\uB428 +gb.forksProhibitedWarning = \uC774 \uC800\uC7A5\uC18C\uB294 \uD3EC\uD06C \uCC28\uB2E8\uB418\uC5B4 \uC788\uC74C +gb.noForks = {0} \uB294 \uD3EC\uD06C \uC5C6\uC74C +gb.forkNotAuthorized = \uC8C4\uC1A1\uD569\uB2C8\uB2E4. {0} \uD3EC\uD06C\uC5D0 \uC811\uC18D \uC778\uC99D\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. +gb.forkInProgress = \uD504\uD06C \uC9C4\uD589 \uC911 +gb.preparingFork = \uD3EC\uD06C \uC900\uBE44 \uC911... +gb.isFork = \uD3EC\uD06C\uD55C +gb.canCreate = \uC0DD\uC131 \uAC00\uB2A5 +gb.canCreateDescription = \uAC1C\uC778 \uC800\uC7A5\uC18C\uB97C \uB9CC\uB4E4 \uC218 \uC788\uC74C +gb.illegalPersonalRepositoryLocation = \uAC1C\uC778 \uC800\uC7A5\uC18C\uB294 \uBC18\uB4DC\uC2DC \"{0}\" \uC5D0 \uC704\uCE58\uD574\uC57C \uD569\uB2C8\uB2E4. +gb.verifyCommitter = \uCEE4\uBBF8\uD130 \uD655\uC778 +gb.verifyCommitterDescription = \uCEE4\uBBF8\uD130 ID \uB294 Gitblit ID \uC640 \uB9E4\uCE58\uB418\uC5B4\uC57C \uD568 +gb.verifyCommitterNote = \uBAA8\uB4E0 \uBA38\uC9C0\uB294 \uCEE4\uBBF8\uD130 ID \uB97C \uC801\uC6A9\uD558\uAE30 \uC704\uD574 "--no-ff" \uC635\uC158 \uD544\uC694 +gb.repositoryPermissions = \uC800\uC7A5\uC18C \uAD8C\uD55C +gb.userPermissions = \uC720\uC800 \uAD8C\uD55C +gb.teamPermissions = \uD300 \uAD8C\uD55C +gb.add = \uCD94\uAC00 +gb.noPermission = \uC774 \uAD8C\uD55C \uC0AD\uC81C +gb.excludePermission = {0} (\uC81C\uC678) +gb.viewPermission = {0} (\uBCF4\uAE30) +gb.clonePermission = {0} (\uD074\uB860) +gb.pushPermission = {0} (\uD478\uC2DC) +gb.createPermission = {0} (\uD478\uC2DC, ref \uC0DD\uC131) +gb.deletePermission = {0} (\uD478\uC2DC, ref \uC0DD\uC131+\uC0AD\uC81C) +gb.rewindPermission = {0} (\uD478\uC2DC, ref \uC0DD\uC131+\uC0AD\uC81C+\uB418\uB3CC\uB9AC\uAE30) +gb.permission = \uAD8C\uD55C +gb.regexPermission = \uC774 \uAD8C\uD55C\uC740 \uC815\uADDC\uC2DD \"{0}\" \uB85C\uBD80\uD130 \uC124\uC815\uB428 +gb.accessDenied = \uC811\uC18D \uAC70\uBD80 +gb.busyCollectingGarbage = \uC8C4\uC1A1\uD569\uB2C8\uB2E4. Gitblit \uC740 \uAC00\uBE44\uC9C0 \uCEEC\uB809\uC158 \uC911\uC785\uB2C8\uB2E4. {0} +gb.gcPeriod = GC \uC8FC\uAE30 +gb.gcPeriodDescription = \uAC00\uBE44\uC9C0 \uD074\uB809\uC158\uAC04\uC758 \uC2DC\uAC04 \uAC04\uACA9 +gb.gcThreshold = GC \uAE30\uC900\uC810 +gb.gcThresholdDescription = \uC870\uAE30 \uAC00\uBE44\uC9C0 \uCEEC\uB809\uC158\uC744 \uBC1C\uC0DD\uC2DC\uD0A4\uAE30 \uC704\uD55C \uC624\uBE0C\uC81D\uD2B8\uB4E4\uC758 \uCD5C\uC18C \uC804\uCCB4 \uD06C\uAE30 +gb.ownerPermission = \uC800\uC7A5\uC18C \uC624\uB108 +gb.administrator = \uAD00\uB9AC\uC790 +gb.administratorPermission = Gitblit \uAD00\uB9AC\uC790 +gb.team = \uD300 +gb.teamPermission = \"{0}\" \uD300 \uBA64\uBC84\uC5D0 \uAD8C\uD55C \uC124\uC815\uB428 +gb.missing = \uB204\uB77D! +gb.missingPermission = \uC774 \uAD8C\uD55C\uC744 \uC704\uD55C \uC800\uC7A5\uC18C \uB204\uB77D! +gb.mutable = \uAC00\uBCC0 +gb.specified = \uC9C0\uC815\uB41C +gb.effective = \uD6A8\uACFC\uC801 +gb.organizationalUnit = \uC870\uC9C1 +gb.organization = \uAE30\uAD00 +gb.locality = \uC704\uCE58 +gb.stateProvince = \uB3C4 \uB610\uB294 \uC8FC +gb.countryCode = \uAD6D\uAC00\uCF54\uB4DC +gb.properties = \uC18D\uC131 +gb.issued = \uBC1C\uAE09\uB428 +gb.expires = \uB9CC\uB8CC +gb.expired = \uB9CC\uB8CC\uB428 +gb.expiring = \uB9CC\uB8CC\uC911 +gb.revoked = \uD3D0\uAE30\uB428 +gb.serialNumber = \uC77C\uB828\uBC88\uD638 +gb.certificates = \uC778\uC99D\uC11C +gb.newCertificate = \uC0C8 \uC778\uC99D\uC11C +gb.revokeCertificate = \uC778\uC99D\uC11C \uD3D0\uAE30 +gb.sendEmail = \uBA54\uC77C \uBCF4\uB0B4\uAE30 +gb.passwordHint = \uD328\uC2A4\uC6CC\uB4DC \uD78C\uD2B8 +gb.ok = ok +gb.invalidExpirationDate = \uB9D0\uB8CC\uC77C\uC790 \uC624\uB958! +gb.passwordHintRequired = \uD328\uC2A4\uC6CC\uB4DC \uD78C\uD2B8 \uD544\uC218! +gb.viewCertificate = \uC778\uC99D\uC11C \uBCF4\uAE30 +gb.subject = \uC774\uB984 +gb.issuer = \uBC1C\uAE09\uC790 +gb.validFrom = \uC720\uD6A8\uAE30\uAC04 (\uC2DC\uC791) +gb.validUntil = \uC720\uD6A8\uAE30\uAC04 (\uB05D) +gb.publicKey = \uACF5\uAC1C\uD0A4 +gb.signatureAlgorithm = \uC11C\uBA85 \uC54C\uACE0\uB9AC\uC998 +gb.sha1FingerPrint = SHA-1 \uC9C0\uBB38 \uC54C\uACE0\uB9AC\uC998 +gb.md5FingerPrint = MD5 \uC9C0\uBB38 \uC54C\uACE0\uB9AC\uC998 +gb.reason = \uC774\uC720 +gb.revokeCertificateReason = \uC778\uC99D\uC11C \uD574\uC9C0\uC774\uC720\uB97C \uC120\uD0DD\uD558\uC138\uC694 +gb.unspecified = \uD45C\uC2DC\uD558\uC9C0 \uC54A\uC74C +gb.keyCompromise = \uD0A4 \uC190\uC0C1 +gb.caCompromise = CA \uC190\uC0C1 +gb.affiliationChanged = \uAD00\uACC4 \uBCC0\uACBD\uB428 +gb.superseded = \uB300\uCCB4\uB428 +gb.cessationOfOperation = \uC6B4\uC601 \uC911\uC9C0 +gb.privilegeWithdrawn = \uAD8C\uD55C \uCCA0\uD68C\uB428 +gb.time.inMinutes = {0} \uBD84 +gb.time.inHours = {0} \uC2DC\uAC04 +gb.time.inDays = {0} \uC77C +gb.hostname = \uD638\uC2A4\uD2B8\uBA85 +gb.hostnameRequired = \uD638\uC2A4\uD2B8\uBA85\uC744 \uC785\uB825\uD558\uC138\uC694 +gb.newSSLCertificate = \uC0C8 \uC11C\uBC84 SSL \uC778\uC99D\uC11C +gb.newCertificateDefaults = \uC0C8 \uC778\uC99D\uC11C \uAE30\uBCF8 +gb.duration = \uAE30\uAC04 +gb.certificateRevoked = \uC778\uC99D\uC11C {0,number,0} \uB294 \uD3D0\uAE30\uB418\uC5C8\uC2B5\uB2C8\uB2E4 +gb.clientCertificateGenerated = {0} \uC744(\uB97C) \uC704\uD55C \uC0C8\uB85C\uC6B4 \uD074\uB77C\uC774\uC5B8\uD2B8 \uC778\uC99D\uC11C \uC0DD\uC131 \uC131\uACF5 +gb.sslCertificateGenerated = {0} \uC744(\uB97C) \uC704\uD55C \uC0C8\uB85C\uC6B4 \uC11C\uBC84 SSL \uC778\uC99D\uC11C \uC0DD\uC131 \uC131\uACF5 +gb.newClientCertificateMessage = \uB178\uD2B8:\n'\uD328\uC2A4\uC6CC\uB4DC' \uB294 \uC720\uC800\uC758 \uD328\uC2A4\uC6CC\uB4DC\uAC00 \uC544\uB2C8\uB77C \uC720\uC800\uC758 \uD0A4\uC2A4\uD1A0\uC5B4 \uB97C \uBCF4\uD638\uD558\uAE30 \uC704\uD55C \uAC83\uC785\uB2C8\uB2E4. \uC774 \uD328\uC2A4\uC6CC\uB4DC\uB294 \uC800\uC7A5\uB418\uC9C0 \uC54A\uC73C\uBBC0\uB85C \uC0AC\uC6A9\uC790 README \uC9C0\uCE68\uC5D0 \uD3EC\uD568\uB420 '\uD78C\uD2B8' \uB97C \uBC18\uB4DC\uC2DC \uC785\uB825\uD574\uC57C \uD569\uB2C8\uB2E4. +gb.certificate = \uC778\uC99D\uC11C +gb.emailCertificateBundle = \uC774\uBA54\uC77C \uD074\uB77C\uC774\uC5B8\uD2B8 \uC778\uC99D\uC11C \uBC88\uB4E4 +gb.pleaseGenerateClientCertificate = {0} \uC744(\uB97C) \uC704\uD55C \uD074\uB77C\uC774\uC5B8\uD2B8 \uC778\uC99D\uC11C\uB97C \uC0DD\uC131\uD558\uC138\uC694 +gb.clientCertificateBundleSent = {0} \uC744(\uB97C) \uC704\uD55C \uD074\uB77C\uC774\uC5B8\uD2B8 \uC778\uC99D\uC11C \uBC88\uB4E4 \uBC1C\uC1A1\uB428 +gb.enterKeystorePassword = Gitblit \uD0A4\uC2A4\uD1A0\uC5B4 \uD328\uC2A4\uC6CC\uB4DC\uB97C \uC785\uB825\uD558\uC138\uC694 +gb.warning = \uACBD\uACE0 +gb.jceWarning = \uC790\uBC14 \uC2E4\uD589\uD658\uACBD\uC5D0 \"JCE Unlimited Strength Jurisdiction Policy\" \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n\uC774\uAC83\uC740 \uD0A4\uC800\uC7A5\uC18C \uC554\uD638\uD654\uC5D0 \uC0AC\uC6A9\uB418\uB294 \uD328\uC2A4\uC6CC\uB4DC\uC758 \uAE38\uC774\uB294 7\uC790\uB85C \uC81C\uD55C\uD569\uB2C8\uB2E4.\n\uC774 \uC815\uCC45 \uD30C\uC77C\uC740 Oracle \uC5D0\uC11C \uC120\uD0DD\uC801\uC73C\uB85C \uB2E4\uC6B4\uB85C\uB4DC\uD574\uC57C \uD569\uB2C8\uB2E4.\n\n\uBB34\uC2DC\uD558\uACE0 \uC778\uC99D\uC11C \uC778\uD504\uB77C\uB97C \uC0DD\uC131\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?\n\n\uC544\uB2C8\uC624(No) \uB77C\uACE0 \uB2F5\uD558\uBA74 \uC815\uCC45\uD30C\uC77C\uC744 \uB2E4\uC6B4\uBC1B\uC744 \uC218 \uC788\uB294 Oracle \uB2E4\uC6B4\uB85C\uB4DC \uD398\uC774\uC9C0\uB97C \uBE0C\uB77C\uC6B0\uC800\uB85C \uC548\uB0B4\uD560 \uAC83\uC785\uB2C8\uB2E4. +gb.maxActivityCommits = \uCD5C\uB300 \uC561\uD2F0\uBE44\uD2F0 \uCEE4\uBC0B +gb.maxActivityCommitsDescription = \uC561\uD2F0\uBE44\uD2F0 \uD398\uC774\uC9C0\uC5D0 \uD45C\uC2DC\uD560 \uCD5C\uB300 \uCEE4\uBC0B \uC218 +gb.noMaximum = \uBB34\uC81C\uD55C +gb.attributes = \uC18D\uC131 +gb.serveCertificate = \uC774 \uC778\uC99D\uC11C\uB85C https \uC81C\uACF5 +gb.sslCertificateGeneratedRestart = {0} \uC744(\uB97C) \uC704\uD55C \uC0C8 \uC11C\uBC84 SSL \uC778\uC99D\uC11C\uB97C \uC131\uACF5\uC801\uC73C\uB85C \uC0DD\uC131\uD558\uC600\uC2B5\uB2C8\uB2E4. \n\uC0C8 \uC778\uC99D\uC11C\uB97C \uC0AC\uC6A9\uD558\uB824\uBA74 Gitblit \uC744 \uC7AC\uC2DC\uC791 \uD574\uC57C \uD569\uB2C8\uB2E4.\n\n'--alias' \uD30C\uB77C\uBBF8\uD130\uB85C \uC2E4\uD589\uD55C\uB2E4\uBA74 ''--alias {0}'' \uB85C \uC124\uC815\uD574\uC57C \uD569\uB2C8\uB2E4. +gb.validity = \uC720\uD6A8\uC131 +gb.siteName = \uC0AC\uC774\uD2B8 \uC774\uB984 +gb.siteNameDescription = \uC11C\uBC84\uC758 \uC9E6\uC740 \uC124\uBA85\uC774 \uD3EC\uD568\uB41C \uC774\uB984 +gb.excludeFromActivity = \uC561\uD2F0\uBE44\uD2F0 \uD398\uC774\uC9C0\uC5D0\uC11C \uC81C\uC678 +gb.sessionEnded = Session has been closed +gb.closeBrowser = Please close the browser to properly end the session. diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties new file mode 100644 index 00000000..f1281e14 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties @@ -0,0 +1,445 @@ +gb.repository = repositorie
+gb.owner = eigenaar
+gb.description = omschrijving
+gb.lastChange = laatste wijziging
+gb.refs = refs
+gb.tag = tag
+gb.tags = tags
+gb.author = auteur
+gb.committer = committer
+gb.commit = commit
+gb.tree = tree
+gb.parent = parent
+gb.url = URL
+gb.history = historie
+gb.raw = raw
+gb.object = object
+gb.ticketId = ticket id
+gb.ticketAssigned = toegewezen
+gb.ticketOpenDate = open datum
+gb.ticketState = status
+gb.ticketComments = commentaar
+gb.view = view
+gb.local = local
+gb.remote = remote
+gb.branches = branches
+gb.patch = patch
+gb.diff = diff
+gb.log = log
+gb.moreLogs = meer commits...
+gb.allTags = alle tags...
+gb.allBranches = alle branches...
+gb.summary = samenvatting
+gb.ticket = ticket
+gb.newRepository = nieuwe repositorie
+gb.newUser = nieuwe gebruiker
+gb.commitdiff = commitdiff
+gb.tickets = tickets
+gb.pageFirst = eerste
+gb.pagePrevious = vorige
+gb.pageNext = volgende
+gb.head = HEAD
+gb.blame = blame
+gb.login = aanmelden
+gb.logout = afmelden
+gb.username = gebruikersnaam
+gb.password = wachtwoord
+gb.tagger = tagger
+gb.moreHistory = meer historie...
+gb.difftocurrent = diff naar current
+gb.search = zoeken
+gb.searchForAuthor = Zoeken naar commits authored door
+gb.searchForCommitter = Zoeken naar commits committed door
+gb.addition = additie
+gb.modification = wijziging
+gb.deletion = verwijdering
+gb.rename = hernoem
+gb.metrics = metrieken
+gb.stats = stats
+gb.markdown = markdown
+gb.changedFiles = gewijzigde bestanden
+gb.filesAdded = {0} bestanden toegevoegd
+gb.filesModified = {0} bestanden gewijzigd
+gb.filesDeleted = {0} bestanden verwijderd
+gb.filesCopied = {0} bestanden gekopieerd
+gb.filesRenamed = {0} bestanden hernoemd
+gb.missingUsername = Ontbrekende Gebruikersnaam
+gb.edit = edit
+gb.searchTypeTooltip = Selecteer Zoek Type
+gb.searchTooltip = Zoek {0}
+gb.delete = verwijder
+gb.docs = docs
+gb.accessRestriction = toegangsbeperking
+gb.name = naam
+gb.enableTickets = enable tickets
+gb.enableDocs = enable docs
+gb.save = opslaan
+gb.showRemoteBranches = toon remote branches
+gb.editUsers = wijzig gebruikers
+gb.confirmPassword = bevestig wachtwoord
+gb.restrictedRepositories = restricted repositories
+gb.canAdmin = kan beheren
+gb.notRestricted = anoniem view, clone, & push
+gb.pushRestricted = geauthenticeerde push
+gb.cloneRestricted = geauthenticeerde clone & push
+gb.viewRestricted = geauthenticeerde view, clone, & push
+gb.useTicketsDescription = readonly, gedistribueerde Ticgit issues
+gb.useDocsDescription = enumereer Markdown documentatie in repositorie
+gb.showRemoteBranchesDescription = toon remote branches
+gb.canAdminDescription = kan Gitblit server beheren
+gb.permittedUsers = toegestane gebruikers
+gb.isFrozen = is bevroren
+gb.isFrozenDescription = weiger push operaties
+gb.zip = zip
+gb.showReadme = toon readme
+gb.showReadmeDescription = toon een \"readme\" Markdown bestand in de samenvattingspagina
+gb.nameDescription = gebruik '/' voor het groeperen van repositories. bijv. libraries/mycoollib.git
+gb.ownerDescription = de eigenaar mag repository instellingen wijzigen
+gb.blob = blob
+gb.commitActivityTrend = commit activiteit trend
+gb.commitActivityDOW = commit activiteit per dag van de week
+gb.commitActivityAuthors = primaire auteurs op basis van commit activiteit
+gb.feed = feed
+gb.cancel = afbreken
+gb.changePassword = wijzig wachtwoord
+gb.isFederated = is gefedereerd
+gb.federateThis = federeer deze repositorie
+gb.federateOrigin = federeer deze origin
+gb.excludeFromFederation = uitsluiten van federatie
+gb.excludeFromFederationDescription = sluit gefedereerde Gitblit instances uit van het pullen van dit account
+gb.tokens = federatie tokens
+gb.tokenAllDescription = alle repositories, gebruikers, & instellingen
+gb.tokenUnrDescription = alle repositories & gebruikers
+gb.tokenJurDescription = alle repositories
+gb.federatedRepositoryDefinitions = repositorie definities
+gb.federatedUserDefinitions = gebruikersdefinities
+gb.federatedSettingDefinitions = instellingendefinities
+gb.proposals = federatie voorstellen
+gb.received = ontvangen
+gb.type = type
+gb.token = token
+gb.repositories = repositories
+gb.proposal = voorstel
+gb.frequency = frequentie
+gb.folder = map
+gb.lastPull = laatste pull
+gb.nextPull = volgende pull
+gb.inclusions = inclusies
+gb.exclusions = exclusies
+gb.registration = registratie
+gb.registrations = federatie registraties
+gb.sendProposal = voorstel
+gb.status = status
+gb.origin = origin
+gb.headRef = default branch (HEAD)
+gb.headRefDescription = wijzig de ref waar HEAD naar linkt naar bijv. refs/heads/master
+gb.federationStrategy = federatie strategie
+gb.federationRegistration = federatie registratie
+gb.federationResults = federatie pull resultaten
+gb.federationSets = federatie sets
+gb.message = melding
+gb.myUrlDescription = de publiek toegankelijke url voor uw Gitblit instantie
+gb.destinationUrl = zend naar
+gb.destinationUrlDescription = de url van de Gitblit instantie voor het verzenden van uw voorstel
+gb.users = gebruikers
+gb.federation = federatie
+gb.error = fout
+gb.refresh = ververs
+gb.browse = blader
+gb.clone = clone
+gb.filter = filter
+gb.create = maak
+gb.servers = servers
+gb.recent = recent
+gb.available = beschikbaar
+gb.selected = geselecteerd
+gb.size = grootte
+gb.downloading = downloading
+gb.loading = laden
+gb.starting = starten
+gb.general = algemeen
+gb.settings = instellingen
+gb.manage = beheer
+gb.lastLogin = laatste login
+gb.skipSizeCalculation = geen berekening van de omvang
+gb.skipSizeCalculationDescription = geen berekening van de repositoriegrootte (beperkt laadtijd pagina)
+gb.skipSummaryMetrics = geen metrieken samenvatting
+gb.skipSummaryMetricsDescription = geen berekening van metrieken op de samenvattingspagina (beperkt laadtijd pagina)
+gb.accessLevel = toegangsniveau
+gb.default = standaard
+gb.setDefault = instellen als standaard
+gb.since = sinds
+gb.status = status
+gb.bootDate = boot datum
+gb.servletContainer = servlet container
+gb.heapMaximum = maximum heap
+gb.heapAllocated = toegewezen heap
+gb.heapUsed = gebruikte heap
+gb.free = beschikbaar
+gb.version = versie
+gb.releaseDate = release datum
+gb.date = datum
+gb.activity = activiteit
+gb.subscribe = aboneer
+gb.branch = branch
+gb.maxHits = max hits
+gb.recentActivity = recente activiteit
+gb.recentActivityStats = laatste {0} dagen / {1} commits door {2} auteurs
+gb.recentActivityNone = laatste {0} dagen / geen
+gb.dailyActivity = dagelijkse activiteit
+gb.activeRepositories = actieve repositories
+gb.activeAuthors = actieve auteurs
+gb.commits = commits
+gb.teams = teams
+gb.teamName = teamnaam
+gb.teamMembers = teamleden
+gb.teamMemberships = teamlidmaatschappen
+gb.newTeam = nieuw team
+gb.permittedTeams = toegestane teams
+gb.emptyRepository = lege repositorie
+gb.repositoryUrl = repositorie url
+gb.mailingLists = mailing lijsten
+gb.preReceiveScripts = pre-receive scripts
+gb.postReceiveScripts = post-receive scripts
+gb.hookScripts = hook scripts
+gb.customFields = custom velden
+gb.customFieldsDescription = custom velden beschikbaar voor Groovy hooks
+gb.accessPermissions = toegangsrechten
+gb.filters = filters
+gb.generalDescription = algemene instellingen
+gb.accessPermissionsDescription = beperk toegang voor gebruikers en teams
+gb.accessPermissionsForUserDescription = stel teamlidmaatschappen in of geef toegang tot specifieke besloten repositories
+gb.accessPermissionsForTeamDescription = stel teamlidmaatschappen in en geef toegang tot specifieke besloten repositories
+gb.federationRepositoryDescription = deel deze repositorie met andere Gitblit servers
+gb.hookScriptsDescription = run Groovy scripts bij pushes naar deze Gitblit server
+gb.reset = reset
+gb.pages = paginas
+gb.workingCopy = werkkopie
+gb.workingCopyWarning = deze repositorie heeft een werkkopie en kan geen pushes ontvangen
+gb.query = query
+gb.queryHelp = Standaard query syntax wordt ondersteund.<p/><p/>Zie aub <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> voor informatie.
+gb.queryResults = resultaten {0} - {1} ({2} hits)
+gb.noHits = geen hits
+gb.authored = authored
+gb.committed = committed
+gb.indexedBranches = geïndexeerde branches
+gb.indexedBranchesDescription = kies de branches voor opname in uw Lucene index
+gb.noIndexedRepositoriesWarning = geen van uw repositories is geconfigureerd voor Lucene indexering
+gb.undefinedQueryWarning = query is niet gedefinieerd!
+gb.noSelectedRepositoriesWarning = kies aub één of meerdere repositories!
+gb.luceneDisabled = Lucene indexering staat uit
+gb.failedtoRead = Lezen is mislukt
+gb.isNotValidFile = is geen valide bestand
+gb.failedToReadMessage = Het lezen van de standaard boodschap van {0} is mislukt!
+gb.passwordsDoNotMatch = Wachtwoorden komen niet overeen!
+gb.passwordTooShort = Wachtwoord is te kort. Minimum lengte is {0} karakters.
+gb.passwordChanged = Wachtwoord succesvol gewijzigd.
+gb.passwordChangeAborted = Wijziging wachtwoord afgebroken.
+gb.pleaseSetRepositoryName = Vul aub een repositorie naam in!
+gb.illegalLeadingSlash = Leidende root folder referenties (/) zijn niet toegestaan.
+gb.illegalRelativeSlash = Relatieve folder referenties (../) zijn niet toegestaan.
+gb.illegalCharacterRepositoryName = Illegaal karakter ''{0}'' in repositorie naam!
+gb.selectAccessRestriction = Stel aub een toegangsbeperking in!
+gb.selectFederationStrategy = Selecteer aub een federatie strategie!
+gb.pleaseSetTeamName = Vul aub een teamnaam in!
+gb.teamNameUnavailable = Teamnaam ''{0}'' is niet beschikbaar.
+gb.teamMustSpecifyRepository = Een team moet minimaal één repositorie specificeren.
+gb.teamCreated = Nieuw team ''{0}'' successvol aangemaakt.
+gb.pleaseSetUsername = Vul aub een gebruikersnaam in!
+gb.usernameUnavailable = Gebruikersnaam ''{0}'' is niet beschikbaar.
+gb.combinedMd5Rename = Gitblit is geconfigureerd voor combined-md5 wachtwoord hashing. U moet een nieuw wachtwoord opgeven bij het hernoemen van een account.
+gb.userCreated = Nieuwe gebruiker ''{0}'' succesvol aangemaakt.
+gb.couldNotFindFederationRegistration = Kon de federatie registratie niet vinden!
+gb.failedToFindGravatarProfile = Kon het Gravatar profiel voor {0} niet vinden
+gb.branchStats = {0} commits en {1} tags in {2}
+gb.repositoryNotSpecified = Repositorie niet gespecificeerd!
+gb.repositoryNotSpecifiedFor = Repositorie niet gespecificeerd voor {0}!
+gb.canNotLoadRepository = Kan repositorie niet laden
+gb.commitIsNull = Commit is null
+gb.unauthorizedAccessForRepository = Niet toegestane toegang tot repositorie
+gb.failedToFindCommit = Het vinden van commit \"{0}\" in {1} voor {2} pagina is mislukt!
+gb.couldNotFindFederationProposal = Kon federatievoorstel niet vinden!
+gb.invalidUsernameOrPassword = Onjuiste gebruikersnaam of wachtwoord!
+gb.OneProposalToReview = Er is 1 federatie voorstel dat wacht op review.
+gb.nFederationProposalsToReview = Er zijn {0} federatie verzoeken die wachten op review.
+gb.couldNotFindTag = Kon tag {0} niet vinden
+gb.couldNotCreateFederationProposal = Kon geen federatie voorstel maken!
+gb.pleaseSetGitblitUrl = Vul aub uw Gitblit url in!
+gb.pleaseSetDestinationUrl = Vul aub een bestemmings-url in voor uw voorstel!
+gb.proposalReceived = Voorstel correct ontvangen door {0}.
+gb.noGitblitFound = Sorry, {0} kon geen Gitblit instance vinden op {1}.
+gb.noProposals = Sorry, {0} accepteert geen voorstellen op dit moment.
+gb.noFederation = Sorry, {0} is niet geconfigureerd voor het federeren met een Gitblit instance.
+gb.proposalFailed = Sorry, {0} ontving geen voorstelgegevens!
+gb.proposalError = Sorry, {0} rapporteert dat een onverwachte fout is opgetreden!
+gb.failedToSendProposal = Voorstel verzenden is niet gelukt!
+gb.userServiceDoesNotPermitAddUser = {0} staat het toevoegen van een gebruikersaccount niet toe!
+gb.userServiceDoesNotPermitPasswordChanges = {0} staat wachtwoord wijzigingen niet toe!
+gb.displayName = display naam
+gb.emailAddress = emailadres
+gb.errorAdminLoginRequired = Aanmelden vereist voor beheerwerk
+gb.errorOnlyAdminMayCreateRepository = Alleen een beheerder kan een repositorie maken
+gb.errorOnlyAdminOrOwnerMayEditRepository = Alleen een beheerder of de eigenaar kan een repositorie wijzigen
+gb.errorAdministrationDisabled = Beheer is uitgeschakeld
+gb.lastNDays = laatste {0} dagen
+gb.completeGravatarProfile = Completeer profiel op Gravatar.com
+gb.none = geen
+gb.line = regel
+gb.content = inhoud
+gb.empty = leeg
+gb.inherited = geërfd
+gb.deleteRepository = Verwijder repositorie \"{0}\"?
+gb.repositoryDeleted = Repositorie ''{0}'' verwijderd.
+gb.repositoryDeleteFailed = Verwijdering van repositorie ''{0}'' mislukt!
+gb.deleteUser = Verwijder gebruiker \"{0}\"?
+gb.userDeleted = Gebruiker ''{0}'' verwijderd.
+gb.userDeleteFailed = Verwijdering van gebruiker ''{0}'' mislukt!
+gb.time.justNow = net
+gb.time.today = vandaag
+gb.time.yesterday = gisteren
+gb.time.minsAgo = {0} minuten geleden
+gb.time.hoursAgo = {0} uren geleden
+gb.time.daysAgo = {0} dagen geleden
+gb.time.weeksAgo = {0} weken geleden
+gb.time.monthsAgo = {0} maanden geleden
+gb.time.oneYearAgo = 1 jaar geleden
+gb.time.yearsAgo = {0} jaren geleden
+gb.duration.oneDay = 1 dag
+gb.duration.days = {0} dagen
+gb.duration.oneMonth = 1 maand
+gb.duration.months = {0} maanden
+gb.duration.oneYear = 1 jaar
+gb.duration.years = {0} jaren
+gb.authorizationControl = authorisatiebeheer
+gb.allowAuthenticatedDescription = ken RW+ rechten toe aan alle geautoriseerde gebruikers
+gb.allowNamedDescription = ken verfijnde rechten toe aan genoemde gebruikers of teams
+gb.markdownFailure = Het parsen van Markdown content is mislukt!
+gb.clearCache = maak cache leeg
+gb.projects = projecten
+gb.project = project
+gb.allProjects = alle projecten
+gb.copyToClipboard = kopieer naar clipboard
+gb.fork = fork
+gb.forks = forks
+gb.forkRepository = fork {0}?
+gb.repositoryForked = {0} is geforked
+gb.repositoryForkFailed= fork is mislukt
+gb.personalRepositories = personlijke repositories
+gb.allowForks = sta forks toe
+gb.allowForksDescription = sta geauthoriseerde gebruikers toe om deze repositorie te forken
+gb.forkedFrom = geforked vanaf
+gb.canFork = kan geforked worden
+gb.canForkDescription = kan geauthoriseerde repositories forken naar persoonlijke repositories
+gb.myFork = toon mijn fork
+gb.forksProhibited = forks niet toegestaan
+gb.forksProhibitedWarning = deze repositorie staat forken niet toe
+gb.noForks = {0} heeft geen forks
+gb.forkNotAuthorized = sorry, u bent niet geautoriseerd voor het forken van {0}
+gb.forkInProgress = bezig met forken
+gb.preparingFork = bezig met het maken van uw fork...
+gb.isFork = is een fork
+gb.canCreate = mag maken
+gb.canCreateDescription = mag persoonlijke repositories maken
+gb.illegalPersonalRepositoryLocation = uw persoonlijke repositorie moet te vinden zijn op \"{0}\"
+gb.verifyCommitter = controleer committer
+gb.verifyCommitterDescription = vereis dat committer identiteit overeen komt met pushing Gitblt gebruikersaccount
+gb.verifyCommitterNote = alle merges vereisen "--no-ff" om committer identiteit af te dwingen
+gb.repositoryPermissions = repository rechten
+gb.userPermissions = gebruikersrechten
+gb.teamPermissions = teamrechten
+gb.add = toevoegen
+gb.noPermission = VERWIJDER DIT RECHT
+gb.excludePermission = {0} (exclude)
+gb.viewPermission = {0} (view)
+gb.clonePermission = {0} (clone)
+gb.pushPermission = {0} (push)
+gb.createPermission = {0} (push, ref creëer)
+gb.deletePermission = {0} (push, ref creëer+verwijdering)
+gb.rewindPermission = {0} (push, ref creëer+verwijdering+rewind)
+gb.permission = recht
+gb.regexPermission = dit recht is gezet vanaf de reguliere expressie \"{0}\"
+gb.accessDenied = toegang geweigerd
+gb.busyCollectingGarbage = sorry, Gitblit is bezig met opruimen in {0}
+gb.gcPeriod = opruim periode
+gb.gcPeriodDescription = tijdsduur tussen opruimacties
+gb.gcThreshold = opruim drempel
+gb.gcThresholdDescription = minimum totaalomvang van losse objecten voor het starten van opruimactie
+gb.ownerPermission = repositorie eigenaar
+gb.administrator = beheer
+gb.administratorPermission = Gitblit beheerder
+gb.team = team
+gb.teamPermission = permissie ingesteld via \"{0}\" teamlidmaatschap
+gb.missing = ontbrekend!
+gb.missingPermission = de repositorie voor deze permissie ontbreekt!
+gb.mutable = te wijzigen
+gb.specified = gespecificeerd
+gb.effective = geldig
+gb.organizationalUnit = organisatie eenheid
+gb.organization = organisatie
+gb.locality = localiteit
+gb.stateProvince = staat of provincie
+gb.countryCode = landcode
+gb.properties = eigenschappen
+gb.issued = uitgegeven
+gb.expires = verloopt op
+gb.expired = verlopen
+gb.expiring = verloopt
+gb.revoked = ingetrokken
+gb.serialNumber = serie nummer
+gb.certificates = certificaten
+gb.newCertificate = nieuwe certificaten
+gb.revokeCertificate = trek certificaat in
+gb.sendEmail = zend email
+gb.passwordHint = wachtwoord hint
+gb.ok = ok
+gb.invalidExpirationDate = ongeldige verloopdatum!
+gb.passwordHintRequired = wachtwoord hint vereist!
+gb.viewCertificate = toon certificaat
+gb.subject = onderwerp
+gb.issuer = issuer
+gb.validFrom = geldig vanaf
+gb.validUntil = geldig tot
+gb.publicKey = publieke sleutel
+gb.signatureAlgorithm = signature algoritme
+gb.sha1FingerPrint = SHA-1 Fingerprint
+gb.md5FingerPrint = MD5 Fingerprint
+gb.reason = reden
+gb.revokeCertificateReason = Kies aub een reden voor het intrekken van het certificaat
+gb.unspecified = niet gespecificeerd
+gb.keyCompromise = sleutel gecompromitteerd
+gb.caCompromise = CA gecompromitteerd
+gb.affiliationChanged = affiliatie gewijzigd
+gb.superseded = opgevolgd
+gb.cessationOfOperation = gestaakt
+gb.privilegeWithdrawn = privilege ingetrokken
+gb.time.inMinutes = in {0} minuten
+gb.time.inHours = in {0} uren
+gb.time.inDays = in {0} dagen
+gb.hostname = hostnaam
+gb.hostnameRequired = Vul aub een hostnaam in
+gb.newSSLCertificate = nieuw server SSL certificaat
+gb.newCertificateDefaults = nieuw certificaat defaults
+gb.duration = duur
+gb.certificateRevoked = Certificaat {0,number,0} is ingetrokken
+gb.clientCertificateGenerated = Nieuw client certificaat voor {0} succesvol gegenereerd
+gb.sslCertificateGenerated = Nieuw server SSL certificaat voor {0} succesvol gegenereerd
+gb.newClientCertificateMessage = MERK OP:\nHet 'wachtwoord' is niet het wachtwoord van de gebruiker. Het is het wachtwoord voor het afschermen van de sleutelring van de gebruiker. Dit wachtwoord wordt niet opgeslagen dus moet u ook een 'hint' invullen die zal worden opgenomen in de README instructies van de gebruiker.
+gb.certificate = certificaat
+gb.emailCertificateBundle = email client certificaat bundel
+gb.pleaseGenerateClientCertificate = Genereer aub een client certificaat voor {0}
+gb.clientCertificateBundleSent = Client certificaat bundel voor {0} verzonden
+gb.enterKeystorePassword = Vul aub het Gitblit keystore wachtwoord in
+gb.warning = waarschuwing
+gb.jceWarning = Uw Java Runtime Environment heeft geen \"JCE Unlimited Strength Jurisdiction Policy\" bestanden.\nDit zal de lengte van wachtwoorden voor het eventueel versleutelen van uw keystores beperken tot 7 karakters.\nDeze policy bestanden zijn een optionele download van Oracle.\n\nWilt u toch doorgaan en de certificaat infrastructuur genereren?\n\nNee antwoorden zal uw browser doorsturen naar de downloadpagina van Oracle zodat u de policybestanden kunt downloaden.
+gb.maxActivityCommits = maximum activiteit commits
+gb.maxActivityCommitsDescription = maximum aantal commits om bij te dragen aan de Activiteitspagina
+gb.noMaximum = geen maximum
+gb.attributes = attributen
+gb.serveCertificate = gebruik deze certificaten voor https
+gb.sslCertificateGeneratedRestart = Nieuwe SSL certificaten voor {0} succesvol gegenereerd.\nU dient Gitblit te herstarten om de nieuwe certificaten te gebruiken.\n\nAls u opstart met de '--alias' parameter moet u die wijzigen naar ''--alias {0}''.
+gb.validity = geldigheid
+gb.siteName = site naam
+gb.siteNameDescription = korte, verduidelijkende naam van deze server
+gb.excludeFromActivity = sluit uit van activiteitspagina
+gb.sessionEnded = Sessie is afgesloten
+gb.closeBrowser = Sluit de browser af om de sessie helemaal te beeindigen.
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_pl.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_pl.properties new file mode 100644 index 00000000..b75e8f81 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_pl.properties @@ -0,0 +1,323 @@ +gb.repository = Repozytorium +gb.owner = W\u0142a\u015Bciciel +gb.description = Opis +gb.lastChange = Ostatnia zmiana +gb.refs = Refs +gb.tag = Tag +gb.tags = Tagi +gb.author = Autor +gb.committer = Wgrywaj\u0105cy +gb.commit = Commit +gb.tree = Drzewo +gb.parent = Rodzic +gb.url = URL +gb.history = Historia +gb.raw = Raw +gb.object = Obiekt +gb.ticketId = Id ticketu +gb.ticketAssigned = Przydzielony +gb.ticketOpenDate = Data otwarcia +gb.ticketState = Status +gb.ticketComments = Komentarze +gb.view = Widok +gb.local = Lokalne +gb.remote = Zdalne +gb.branches = Rozga\u0142\u0119zienia +gb.patch = \u0141atki +gb.diff = R\u00F3\u017Cnice +gb.log = Log +gb.moreLogs = Wi\u0119cej log\u00F3w... +gb.allTags = Wszystkie tagi... +gb.allBranches = Wszystkie rozga\u0142\u0119zienia... +gb.summary = Podsumowanie +gb.ticket = Ticket +gb.newRepository = Nowe repozytorium +gb.newUser = Nowy u\u017Cytkownik +gb.commitdiff = Diff zmiany +gb.tickets = Tickets +gb.pageFirst = Pierwsza strona +gb.pagePrevious = Poprzednia strona +gb.pageNext = Nast\u0119pna strona +gb.head = HEAD +gb.blame = Blame +gb.login = Zaloguj +gb.logout = Wyloguj +gb.username = U\u017Cytkownik +gb.password = Has\u0142o +gb.tagger = Taguj\u0105cy +gb.moreHistory = Wi\u0119cej historii... +gb.difftocurrent = Por\u00F3wnaj z obecnym +gb.search = Szukaj +gb.searchForAuthor = Szukaj po autorze +gb.searchForCommitter = Szukaj po wgrywaj\u0105cym +gb.addition = Dodane +gb.modification = Zmodyfikowane +gb.deletion = Usuni\u0119te +gb.rename = Zmiana nazwy +gb.metrics = Metryki +gb.stats = Statystyki +gb.markdown = Markdown +gb.changedFiles = Zmienione pliki +gb.filesAdded = {0} plik\u00F3w dodano +gb.filesModified = {0} plik\u00F3w zmieniono +gb.filesDeleted = {0} plik\u00F3w usuni\u0119to +gb.filesCopied = {0} plik\u00F3w skopiowano +gb.filesRenamed = {0} plik\u00F3w przemianowano +gb.missingUsername = Brak nazwy u\u017Cytkownika +gb.edit = Edytuj +gb.searchTypeTooltip = Szukaj typu +gb.searchTooltip = Szukaj {0} +gb.delete = Usu\u0144 +gb.docs = Dokumentacja +gb.accessRestriction = Uprawnienia dost\u0119pu +gb.name = Nazwa +gb.enableTickets = Uaktywnij tickety +gb.enableDocs = Uaktywnij dokumentacj\u0119 +gb.save = Zapisz +gb.showRemoteBranches = Poka\u017C zdalne rozga\u0142\u0119zienia +gb.editUsers = Edytuj u\u017Cytkownika +gb.confirmPassword = Potwierd\u017A has\u0142o +gb.restrictedRepositories = Chronione repozytoria +gb.canAdmin = Mo\u017Ce administrowa\u0107 +gb.notRestricted = Anonimowy podgl\u0105d, klonowanie i zapis +gb.pushRestricted = Uwierzytelniony zapis +gb.cloneRestricted = Uwierzytelnione klonowanie i zapis +gb.viewRestricted = Uwierzytelniony podgl\u0105d, klonowanie i zapis +gb.useTicketsDescription = Rozproszone zg\u0142oszenia Ticgit +gb.useDocsDescription = Parsuj znaczniki Markdown w repozytorium +gb.showRemoteBranchesDescription = Poka\u017C zdalne rozga\u0142\u0119zienia +gb.canAdminDescription = Mo\u017Ce administrowa\u0107 serwerem Gitblit +gb.permittedUsers = Uprawnieni u\u017Cytkownicy +gb.isFrozen = jest zamro\u017Cony +gb.isFrozenDescription = Odrzucaj operacje zapisu +gb.zip = zip +gb.showReadme = Poka\u017C readme +gb.showReadmeDescription = Poka\u017C sparsowany \"readme\" na stronie podsumowania +gb.nameDescription = u\u017Cyj '/' do grupowania repozytori\u00F3w, np. libraries/server-lib.git +gb.ownerDescription = W\u0142a\u015Bciciel mo\u017Ce edytowa\u0107 ustawienia repozytorium +gb.blob = blob +gb.commitActivityTrend = Aktywno\u015B\u0107 zmian +gb.commitActivityDOW = Aktywno\u015B\u0107 zmian wed\u0142ug dnia tygodnia +gb.commitActivityAuthors = G\u0142\u00F3wni aktywni autorzy +gb.feed = feed +gb.cancel = Anuluj +gb.changePassword = Zmie\u0144 has\u0142o +gb.isFederated = Jest sfederowany +gb.federateThis = Federuj to repozytorium +gb.federateOrigin = Federuj origin +gb.excludeFromFederation = Wy\u0142\u0105cz z federacji +gb.excludeFromFederationDescription = Blokuj sfederowane instancje Gitblit od pobierania tego konta +gb.tokens = Tokeny federacji +gb.tokenAllDescription = Wszystkie repozytoria, u\u017Cytkownicy i ustawienia +gb.tokenUnrDescription = Wszystkie repozytoria i u\u017Cytkownicy +gb.tokenJurDescription = Wszystkie repozytoria +gb.federatedRepositoryDefinitions = Definicje repozytori\u00F3w +gb.federatedUserDefinitions = Definicje u\u017Cytkownik\u00F3w +gb.federatedSettingDefinitions = Definicje ustawie\u0144 +gb.proposals = Propozycje federacji +gb.received = Otrzymane +gb.type = Typ +gb.token = Token +gb.repositories = Repozytoria +gb.proposal = Propozycja +gb.frequency = Cz\u0119stotliwo\u015B\u0107 +gb.folder = Folder +gb.lastPull = Ostatnie pobranie +gb.nextPull = Nast\u0119pne pobranie +gb.inclusions = Do\u0142\u0105czenia +gb.exclusions = Wy\u0142\u0105czenia +gb.registration = Rejestracja +gb.registrations = Sfederowane rejestracje +gb.sendProposal = Zaproponuj +gb.status = Status +gb.origin = origin +gb.headRef = Domy\u015Blne rozga\u0142\u0119zienie (HEAD) +gb.headRefDescription = Zmie\u0144 ref aby wskazywa\u0142o na to co HEAD np. refs/heads/master +gb.federationStrategy = Strategia federowania +gb.federationRegistration = Rejestracja federowania +gb.federationResults = Wyniki sfederowanego pobierania +gb.federationSets = Zbiory federacji +gb.message = Wiadomo\u015B\u0107 +gb.myUrlDescription = Zewn\u0119trznie widoczy url do tej instancji Gitblit +gb.destinationUrl = Wy\u015Blij do +gb.destinationUrlDescription = Url instacji Gitblit, gdzie chcesz wys\u0142a\u0107 swoj\u0105 propozycj\u0119 +gb.users = U\u017Cytkownicy +gb.federation = Federacja +gb.error = B\u0142\u0105d +gb.refresh = Od\u015Bwie\u017C +gb.browse = Przegl\u0105daj +gb.clone = Klonuj +gb.filter = Filtr +gb.create = Stw\u00F3rz +gb.servers = Serwery +gb.recent = Ostatnie +gb.available = Dost\u0119pne +gb.selected = Wybrane +gb.size = Rozmiar +gb.downloading = Pobieranie +gb.loading = \u0141adowanie +gb.starting = Startowanie +gb.general = Og\u00F3lne +gb.settings = Ustawienia +gb.manage = Zarz\u0105dzaj +gb.lastLogin = Ostatni login +gb.skipSizeCalculation = Pomi\u0144 obliczanie rozmiaru +gb.skipSizeCalculationDescription = Nie obliczaj rozmiaru repozytorium (przyspiesza \u0142adowanie strony) +gb.skipSummaryMetrics = Pomi\u0144 obliczanie metryk +gb.skipSummaryMetricsDescription = Nie obliczaj metryk na stronie podsumowania (przyspiesza \u0142adowanie strony) +gb.accessLevel = Poziom dost\u0119pu +gb.default = Domy\u015Blny +gb.setDefault = Ustaw domy\u015Blny +gb.since = Od +gb.status = Status +gb.bootDate = Data uruchomienia +gb.servletContainer = Kontener serwlet\u00F3w +gb.heapMaximum = Maksymalny stos +gb.heapAllocated = Przydzielony stos +gb.heapUsed = U\u017Cywany stos +gb.free = Wolne +gb.version = Wersja +gb.releaseDate = Data wydania +gb.date = Data +gb.activity = Aktywno\u015B\u0107 +gb.subscribe = Subskrybuj +gb.branch = Rozga\u0142\u0119zienie +gb.maxHits = Maks. ilo\u015B\u0107 dost\u0119pu +gb.recentActivity = Ostatnia aktywno\u015B\u0107 +gb.recentActivityStats = Ostatnich {0} dni / {1} zmian przez {2} autor\u00F3w +gb.recentActivityNone = Ostatnich {0} dni / brak +gb.dailyActivity = Dzienna aktywno\u015B\u0107 +gb.activeRepositories = Aktywne repozytoria +gb.activeAuthors = Aktywni u\u017Cytkownicy +gb.commits = Zmiany +gb.teams = Zespo\u0142y +gb.teamName = Nazwa zespo\u0142u +gb.teamMembers = Cz\u0142onkowie zespo\u0142u +gb.teamMemberships = Cz\u0142onkostwo zespo\u0142u +gb.newTeam = Nowy zesp\u00F3\u0142 +gb.permittedTeams = Uprawnione zespo\u0142y +gb.emptyRepository = Puste repozytorium +gb.repositoryUrl = Url repozytorium +gb.mailingLists = Lista mailingowa +gb.preReceiveScripts = Skrypty przed odbiorem zmian +gb.postReceiveScripts = Skrypty po odbiorze zmian +gb.hookScripts = Wpi\u0119te haki +gb.customFields = Niestandardowe pola +gb.customFieldsDescription = Niestandardowe pola dost\u0119pne dla hak\u00F3w Groovy +gb.accessPermissions = Uprawnienia dot\u0119pu +gb.filters = Filtry +gb.generalDescription = Wsp\u00F3lne ustawienia +gb.accessPermissionsDescription = Ogranicz dost\u0119p u\u017Cytkownikom i zespo\u0142om +gb.accessPermissionsForUserDescription = Ustal cz\u0142onkostwo w zespo\u0142ach lub udziel dost\u0119p do specyficzynch repozytori\u00F3w +gb.accessPermissionsForTeamDescription = Ustal cz\u0142onk\u00F3w zespo\u0142u i udziel dost\u0119p do specyficzynch repozytori\u00F3w +gb.federationRepositoryDescription = Udost\u0119pnij to repozytorium innym serwerom Gitblit +gb.hookScriptsDescription = Uruchamiaj skrypty Groovy w momencie wgrania zmian na ten serwer +gb.reset = Resetuj +gb.pages = Strony +gb.workingCopy = Kopia robocza +gb.workingCopyWarning = To repozytorium ma kopi\u0119 robocz\u0105 i nie mo\u017Ce otrzymywa\u0107 zmian +gb.query = Szukaj +gb.queryHelp = Standardowa sk\u0142adnia wyszukiwa\u0144 jest wspierana.<p/><p/>Na stronie <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> dost\u0119pne s\u0105 dalsze szczeg\u00F3\u0142y. +gb.queryResults = Wyniki {0} - {1} ({2} wynik\u00F3w) +gb.noHits = Brak wynik\u00F3w +gb.authored = utworzy\u0142 +gb.committed = wgra\u0142 +gb.indexedBranches = Indeksowane rozga\u0142\u0119zienia +gb.indexedBranchesDescription = Wybierz rozga\u0142\u0119zienia do w\u0142\u0105czenia do indeksu Lucene +gb.noIndexedRepositoriesWarning = \u017Badne z rozga\u0142\u0119zie\u0144 w repozytorium nie jest dost\u0119pne dla Lucene +gb.undefinedQueryWarning = Wyszukanie nie zdefiniowane! +gb.noSelectedRepositoriesWarning = Wska\u017C jedno lub wi\u0119cej repozytori\u00F3w! +gb.luceneDisabled = Indeksowanie Lucene jest wy\u0142\u0105czone. +gb.failedtoRead = B\u0142\u0105d podczas odczytu +gb.isNotValidFile = nie jest poprawnym plikiem. +gb.failedToReadMessage = B\u0142\u0105d podczas pdczytu domy\u015Blnego komunikatu z {0}! +gb.passwordsDoNotMatch = Brak zgodno\u015Bci has\u0142a! +gb.passwordTooShort = Has\u0142o za kr\u00F3tkie. Minimalna d\u0142ugo\u015B\u0107 to {0} znak\u00F3w. +gb.passwordChanged = Pomy\u015Blnie zmieniono has\u0142o. +gb.passwordChangeAborted = Zmiania has\u0142a porzucona. +gb.pleaseSetRepositoryName = Wska\u017C nazw\u0119 repozytorium! +gb.illegalLeadingSlash = Poprzedzaj\u0105cy g\u0142\u00F3wny folder znaki (/) s\u0105 niedozwolone. +gb.illegalRelativeSlash = Wzgl\u0119dne odwo\u0142ania do folder\u00F3w (../) s\u0105 niedozwolone. +gb.illegalCharacterRepositoryName = Zabronionu znak ''{0}'' w nazwie repozytorium! +gb.selectAccessRestriction = Wska\u017C ograniczenia dost\u0119pu! +gb.selectFederationStrategy = Wska\u017C strategi\u0119 federacji! +gb.pleaseSetTeamName = Wpisz nazw\u0119 zespo\u0142u! +gb.teamNameUnavailable = Nazwa zespo\u0142u ''{0}'' jest niedost\u0119pna. +gb.teamMustSpecifyRepository = Zesp\u00F3\u0142 musi posiada\u0107 conajmniej jedno repozytorium. +gb.teamCreated = Zesp\u00F3\u0142 ''{0}'' zosta\u0142 utworzony. +gb.pleaseSetUsername = Wpisz nazw\u0119 u\u017Cytkownika! +gb.usernameUnavailable = Nazwa u\u017Cytkownika''{0}'' jest niedost\u0119pna. +gb.combinedMd5Rename = Gitblit jest skonfigurowany na po\u0142\u0105czone haszowanie hase\u0142 md5. Musisz wpisa\u0107 nowe has\u0142o przy zmianie nazwy konta. +gb.userCreated = U\u017Cytkownik ''{0}'' zosta\u0142 utworzony. +gb.couldNotFindFederationRegistration = Nie mo\u017Cna znale\u017A\u0107 rejestracji federacji! +gb.failedToFindGravatarProfile = B\u0142\u0105d podczas dopasowania profilu Gravatar dla {0} +gb.branchStats = {0} zmian oraz {1} tag\u00F3w w {2} +gb.repositoryNotSpecified = Repozytorium nie wskazane! +gb.repositoryNotSpecifiedFor = Repozytorium nie wskazane dla {0}! +gb.canNotLoadRepository = Nie mo\u017Cna za\u0142adowa\u0107 repozytorium +gb.commitIsNull = Zmiana jest nullem +gb.unauthorizedAccessForRepository = Nieuwierzytelniony dost\u0119p do repozytorium +gb.failedToFindCommit = B\u0142\u0105d podczas wyszukania zmiany \"{0}\" w {1} dla {2} strony! +gb.couldNotFindFederationProposal = Nie mo\u017Cna odnale\u017A\u0107 propozycji federacji! +gb.invalidUsernameOrPassword = B\u0142\u0119dny u\u017Cytkownik lub has\u0142o! +gb.OneProposalToReview = Jest 1 oczekuj\u0105ca propozycja federacji. +gb.nFederationProposalsToReview = Jest {0} oczekuj\u0105cych propozycji federacji. +gb.couldNotFindTag = Nie mo\u017Cna odnale\u017A\u0107 taga {0} +gb.couldNotCreateFederationProposal = Nie mo\u017Cna utworzy\u0107 propozycji federacji! +gb.pleaseSetGitblitUrl = Wpisz url serwera Gitblit! +gb.pleaseSetDestinationUrl = Wpisz url, gdzie ma trafi\u0107 propozycja! +gb.proposalReceived = Odebrano propozycj\u0119 od {0}. +gb.noGitblitFound = Przepraszamy, {0} nie mo\u017Cna odnale\u017A\u0107 instancji Gitblit pod {1}. +gb.noProposals = Przepraszamy, {0} nie akceptuje obecnie propozycji. +gb.noFederation = Przepraszamy, {0} nie jest skonfigurowany do federacji z jakimikolwiek instancjami Gitblit. +gb.proposalFailed = Przepraszamy, {0} nie otrzyma\u0142 \u017Cadnych danych propozycji! +gb.proposalError = Przepraszamy, {0} informuje o nieoczekiwanym b\u0142\u0119dzie! +gb.failedToSendProposal = B\u0142\u0105d podczas wysy\u0142ania propozycji! +gb.userServiceDoesNotPermitAddUser = {0} nie zezwala na utworzenie nowego u\u017Cytkownika! +gb.userServiceDoesNotPermitPasswordChanges = {0} nie zezwala na zmian\u0119 has\u0142a! +gb.displayName = Wy\u015Bwietlana nazwa +gb.emailAddress = Adres email +gb.errorAdminLoginRequired = Administracja wymaga zalogowania +gb.errorOnlyAdminMayCreateRepository = Tylko administrator mo\u017Ce utworzy\u0107 repozytorium +gb.errorOnlyAdminOrOwnerMayEditRepository = Tylko administrator lub w\u0142a\u015Bciciel mo\u017Ce edytowa\u0107 repozytorium. +gb.errorAdministrationDisabled = Administracja jest wy\u0142\u0105czona +gb.lastNDays = Ostatnich {0} dni +gb.completeGravatarProfile = Pe\u0142ny profil na Gravatar.com +gb.none = Brak +gb.line = Linia +gb.content = Zawarto\u015B\u0107 +gb.empty = Pusty +gb.inherited = Odziedziczony +gb.deleteRepository = Usun\u0105\u0107 repozytorium \"{0}\"? +gb.repositoryDeleted = Repozytorium ''{0}'' usuni\u0119te. +gb.repositoryDeleteFailed = B\u0142\u0105d podczas usuwania repozytorium ''{0}''! +gb.deleteUser = Usun\u0105\u0107 u\u017Cytkownika \"{0}\"? +gb.userDeleted = U\u017Cytkownik ''{0}'' usuni\u0119ty. +gb.userDeleteFailed = B\u0142\u0105d podczas usuwania u\u017Cytkownika ''{0}''! +gb.time.justNow = Przed chwil\u0105 +gb.time.today = Dzisiaj +gb.time.yesterday = Wczoraj +gb.time.minsAgo = {0} minut temu +gb.time.hoursAgo = {0} godzin temu +gb.time.daysAgo = {0} dni temu +gb.time.weeksAgo = {0} tygodni temu +gb.time.monthsAgo = {0} miesi\u0119cy temu +gb.time.oneYearAgo = Rok temu +gb.time.yearsAgo = {0} lat temu +gb.duration.oneDay = Dzie\u0144 temu +gb.duration.days = {0} dni +gb.duration.oneMonth = Miesi\u0105c +gb.duration.months = {0} miesi\u0119cy +gb.duration.oneYear = rok +gb.duration.years = {0} lat +gb.authorizationControl = kontrola autoryzacji +gb.allowAuthenticatedDescription = udziel ograniczonego dost\u0119pu wszystkim uwierzytelnionym u\u017Cytkownikom +gb.allowNamedDescription = udziel ograniczonego dost\u0119pu nazwanym u\u017Cytkownikom lub zespo\u0142om +gb.markdownFailure = Nieudane parsowanie znacznik\u00F3w Markdown! +gb.clearCache = Wyczy\u015B\u0107 cache +gb.projects = Projekty +gb.project = Projekt +gb.allProjects = Wszystkie projekty +gb.copyToClipboard = Kopiuj do schowka +gb.sessionEnded = Session has been closed +gb.closeBrowser = Please close the browser to properly end the session.
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_pt_BR.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_pt_BR.properties new file mode 100644 index 00000000..a02d2ffa --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_pt_BR.properties @@ -0,0 +1,447 @@ +gb.repository = repositório
+gb.owner = proprietário
+gb.description = descrição
+gb.lastChange = última alteração
+gb.refs = refs
+gb.tag = tag
+gb.tags = tags
+gb.author = autor
+gb.committer = committer
+gb.commit = commit
+gb.tree = árvore
+gb.parent = parent
+gb.url = URL
+gb.history = histórico
+gb.raw = raw
+gb.object = object
+gb.ticketId = ticket id
+gb.ticketAssigned = atribuído
+gb.ticketOpenDate = data da abertura
+gb.ticketState = estado
+gb.ticketComments = comentários
+gb.view = visualizar
+gb.local = local
+gb.remote = remote
+gb.branches = branches
+gb.patch = patch
+gb.diff = diff
+gb.log = log
+gb.moreLogs = mais commits...
+gb.allTags = todas as tags...
+gb.allBranches = todos os branches...
+gb.summary = resumo
+gb.ticket = ticket
+gb.newRepository = novo repositório
+gb.newUser = novo usuário
+gb.commitdiff = commitdiff
+gb.tickets = tickets
+gb.pageFirst = primeira
+gb.pagePrevious anterior
+gb.pageNext = próxima
+gb.head = HEAD
+gb.blame = blame
+gb.login = login
+gb.logout = logout
+gb.username = username
+gb.password = password
+gb.tagger = tagger
+gb.moreHistory = mais histórico...
+gb.difftocurrent = diff para a atual
+gb.search = pesquisar
+gb.searchForAuthor = Procurar por commits cujo autor é
+gb.searchForCommitter = Procurar por commits commitados por
+gb.addition = adicionados
+gb.modification = modificados
+gb.deletion = apagados
+gb.rename = renomear
+gb.metrics = métricas
+gb.stats = estatísticas
+gb.markdown = markdown
+gb.changedFiles = arquivos alterados
+gb.filesAdded = {0} arquivos adicionados
+gb.filesModified = {0} arquivos modificados
+gb.filesDeleted = {0} arquivos deletados
+gb.filesCopied = {0} arquivos copiados
+gb.filesRenamed = {0} arquivos renomeados
+gb.missingUsername = Faltando username
+gb.edit = editar
+gb.searchTypeTooltip = Selecione o Tipo de Pesquisa
+gb.searchTooltip = Pesquisar {0}
+gb.delete = deletar
+gb.docs = docs
+gb.accessRestriction = restrição de acesso
+gb.name = nome
+gb.enableTickets = ativar tickets
+gb.enableDocs = ativar documentação
+gb.save = salvar
+gb.showRemoteBranches = mostrar branches remotos
+gb.editUsers = editar usuários
+gb.confirmPassword = confirmar password
+gb.restrictedRepositories = repositórios restritos
+gb.canAdmin = pode administrar
+gb.notRestricted = visualização anônima, clone, & push
+gb.pushRestricted = push autênticado
+gb.cloneRestricted = clone & push autênticados
+gb.viewRestricted = view, clone, & push autênticados
+gb.useTicketsDescription = somente leitura, issues do Ticgit distribuídos
+gb.useDocsDescription = enumerar documentação Markdown no repositório
+gb.showRemoteBranchesDescription = mostrar branches remotos
+gb.canAdminDescription = pode administrar o server Gitblit
+gb.permittedUsers = usuários autorizados
+gb.isFrozen = está congelado
+gb.isFrozenDescription = proibir fazer push
+gb.zip = zip
+gb.showReadme = mostrar readme
+gb.showReadmeDescription = mostrar um arquivo \"leia-me\" na página de resumo
+gb.nameDescription = usar '/' para agrupar repositórios. e.g. libraries/mycoollib.git
+gb.ownerDescription = o proprietário pode editar configurações do repositório
+gb.blob = blob
+gb.commitActivityTrend = tendência dos commits
+gb.commitActivityDOW = commits por dia da semana
+gb.commitActivityAuthors = principais committers
+gb.feed = feed
+gb.cancel = cancelar
+gb.changePassword = alterar password
+gb.isFederated = está federado
+gb.federateThis = federar este repositório
+gb.federateOrigin = federar o origin
+gb.excludeFromFederation = excluir da federação
+gb.excludeFromFederationDescription = bloquear instâncias federadas do GitBlit de fazer pull desta conta
+gb.tokens = tokens de federação
+gb.tokenAllDescription = todos repositórios, usuários & configurações
+gb.tokenUnrDescription = todos repositórios & usuários
+gb.tokenJurDescription = todos repositórios
+gb.federatedRepositoryDefinitions = definições de repositório
+gb.federatedUserDefinitions = definições de usuários
+gb.federatedSettingDefinitions = definições de configurações
+gb.proposals = propostas de federações
+gb.received = recebidos
+gb.type = tipo
+gb.token = token
+gb.repositories = repositórios
+gb.proposal = propostas
+gb.frequency = frequência
+gb.folder = pasta
+gb.lastPull = último pull
+gb.nextPull = próximo pull
+gb.inclusions = inclusões
+gb.exclusions = excluões
+gb.registration = cadastro
+gb.registrations = cadastro de federações
+gb.sendProposal = enviar proposta
+gb.status = status
+gb.origin = origin
+gb.headRef = default branch (HEAD)
+gb.headRefDescription = alterar a ref o qual a HEAD aponta. e.g. refs/heads/master
+gb.federationStrategy = estratégia de federação
+gb.federationRegistration = cadastro de federações
+gb.federationResults = resultados dos pulls de federações
+gb.federationSets = ajustes de federações
+gb.message = mensagem
+gb.myUrlDescription = a url de acesso público para a instância Gitblit
+gb.destinationUrl = enviar para
+gb.destinationUrlDescription = a url da intância do Gitblit para enviar sua proposta
+gb.users = usuários
+gb.federation = federação
+gb.error = erro
+gb.refresh = atualizar
+gb.browse = navegar
+gb.clone = clonar
+gb.filter = filtrar
+gb.create = criar
+gb.servers = servidores
+gb.recent = recente
+gb.available = disponível
+gb.selected = selecionado
+gb.size = tamanho
+gb.downloading = downloading
+gb.loading = loading
+gb.starting = inciando
+gb.general = geral
+gb.settings = configurações
+gb.manage = administrar
+gb.lastLogin = último login
+gb.skipSizeCalculation = ignorar cálculo do tamanho
+gb.skipSizeCalculationDescription = não calcular o tamanho do repositório (reduz o tempo de load da página)
+gb.skipSummaryMetrics = ignorar resumo das métricas
+gb.skipSummaryMetricsDescription = não calcular métricas na página de resumo
+gb.accessLevel = acesso
+gb.default = default
+gb.setDefault = tornar default
+gb.since = desde
+gb.status = status
+gb.bootDate = data do boot
+gb.servletContainer = servlet container
+gb.heapMaximum = heap máximo
+gb.heapAllocated = alocar heap
+gb.heapUsed = usar heap
+gb.free = free
+gb.version = versão
+gb.releaseDate = data de release
+gb.date = data
+gb.activity = atividade
+gb.subscribe = inscrever
+gb.branch = branch
+gb.maxHits = hits máximos
+gb.recentActivity = atividade recente
+gb.recentActivityStats = últimos {0} dias / {1} commits por {2} autores
+gb.recentActivityNone = últimos {0} dias / nenhum
+gb.dailyActivity = atividade diária
+gb.activeRepositories = repositórios ativos
+gb.activeAuthors = autores ativos
+gb.commits = commits
+gb.teams = equipes
+gb.teamName = nome da equipe
+gb.teamMembers = membros
+gb.teamMemberships = filiações em equipes
+gb.newTeam = nova equipe
+gb.permittedTeams = equipes permitidas
+gb.emptyRepository = repositório vazio
+gb.repositoryUrl = url do repositório
+gb.mailingLists = listas de e-mails
+gb.preReceiveScripts = pre-receive scripts
+gb.postReceiveScripts = post-receive scripts
+gb.hookScripts = hook scripts
+gb.customFields = campos customizados
+gb.customFieldsDescription = campos customizados disponíveis para Groovy hooks
+gb.accessPermissions = permissões de acesso
+gb.filters = filtros
+gb.generalDescription = configurações comuns
+gb.accessPermissionsDescription = restringir acesso por usuários e equipes
+gb.accessPermissionsForUserDescription = ajustar filiações em equipes ou garantir acesso a repositórios específicos
+gb.accessPermissionsForTeamDescription = ajustar membros da equipe e garantir acesso a repositórios específicos
+gb.federationRepositoryDescription = compartilhar este repositório com outros servidores Gitblit
+gb.hookScriptsDescription = rodar scripts Groovy nos pushes para este servidor Gitblit
+gb.reset = reset
+gb.pages = páginas
+gb.workingCopy = working copy
+gb.workingCopyWarning = este repositório tem uma working copy e não pode receber pushes
+gb.query = query
+gb.queryHelp = Standard query syntax é suportada.<p/><p/>Por favor veja <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> para mais detalhes.
+gb.queryResults = resultados {0} - {1} ({2} hits)
+gb.noHits = sem hits
+gb.authored = foi autor de
+gb.committed = committed
+gb.indexedBranches = branches indexados
+gb.indexedBranchesDescription = selecione os branches para incluir nos seus índices Lucene
+gb.noIndexedRepositoriesWarning = nenhum dos seus repositórios foram configurados para indexação do Lucene
+gb.undefinedQueryWarning = a query não foi definida!
+gb.noSelectedRepositoriesWarning = por favor selecione um ou mais repositórios!
+gb.luceneDisabled = indexação do Lucene está desabilitada
+gb.failedtoRead = leitura falhou
+gb.isNotValidFile = não é um arquivo válido
+gb.failedToReadMessage = Falhou em ler mensagens default de {0}!
+gb.passwordsDoNotMatch = Passwords não conferem!
+gb.passwordTooShort = Password é muito curto. Tamanho mínimo são {0} caracteres.
+gb.passwordChanged = Password alterado com sucesso.
+gb.passwordChangeAborted = alteração do password foi abortada.
+gb.pleaseSetRepositoryName = Por favor ajuste o nome do repositório!
+gb.illegalLeadingSlash = Referências a diretórios raiz começando com (/) são proibidas.
+gb.illegalRelativeSlash = Referências a diretórios relativos (../) são proibidas.
+gb.illegalCharacterRepositoryName = Caractere ilegal ''{0}'' no nome do repositório!
+gb.selectAccessRestriction = Por favor selecione a restrição de acesso!
+gb.selectFederationStrategy = Por favor selecione a estratégia de federação!
+gb.pleaseSetTeamName = Por favor insira um nome de equipe!
+gb.teamNameUnavailable = O nome de equipe ''{0}'' está indisponível.
+gb.teamMustSpecifyRepository = Uma equipe deve especificar pelo menos um repositório.
+gb.teamCreated = Nova equipe ''{0}'' criada com sucesso.
+gb.pleaseSetUsername = Por favor entre com um username!
+gb.usernameUnavailable = Username ''{0}'' está indisponível.
+gb.combinedMd5Rename = Gitblit está configurado para usar um hash combinado-md5. Você deve inserir um novo password ao renamear a conta.
+gb.userCreated = Novo usuário ''{0}'' criado com sucesso.
+gb.couldNotFindFederationRegistration = Não foi possível localizar o registro da federação!
+gb.failedToFindGravatarProfile = Falhou em localizar um perfil Gravatar para {0}
+gb.branchStats = {0} commits e {1} tags em {2}
+gb.repositoryNotSpecified = Repositório não específicado!
+gb.repositoryNotSpecifiedFor = Repositório não específicado para {0}!
+gb.canNotLoadRepository = Não foi possível carregar o repositório
+gb.commitIsNull = Commit está nulo
+gb.unauthorizedAccessForRepository = Acesso não autorizado para o repositório
+gb.failedToFindCommit = Não foi possível achar o commit \"{0}\" em {1} para {2} página!
+gb.couldNotFindFederationProposal = Não foi possível localizar propostas de federação!
+gb.invalidUsernameOrPassword = username ou password inválido!
+gb.OneProposalToReview = Existe uma proposta de federação aguardando revisão.
+gb.nFederationProposalsToReview = Existem {0} propostas de federação aguardando revisão.
+gb.couldNotFindTag = Não foi possível localizar a tag {0}
+gb.couldNotCreateFederationProposal = Não foi possível criar uma proposta de federation!
+gb.pleaseSetGitblitUrl = Por favor insira sua url do Gitblit!
+gb.pleaseSetDestinationUrl = Por favor insira a url de destino para sua proposta!
+gb.proposalReceived = Proposta recebida com sucesso por {0}.
+gb.noGitblitFound = Desculpe, {0} não localizou uma instância do Gitblit em {1}.
+gb.noProposals = Desculpe, {0} não está aceitando propostas agora.
+gb.noFederation = Desculpe, {0} não está configurado com nenhuma intância do Gitblit.
+gb.proposalFailed = Desculpe, {0} não recebeu nenhum dado de proposta!
+gb.proposalError = Desculpe, {0} reportou que um erro inesperado ocorreu!
+gb.failedToSendProposal = Não foi possível enviar a proposta!
+gb.userServiceDoesNotPermitAddUser = {0} não permite adicionar uma conta de usuário!
+gb.userServiceDoesNotPermitPasswordChanges = {0} não permite alterações no password!
+gb.displayName = nome
+gb.emailAddress = e-mail
+gb.errorAdminLoginRequired = Administração requer um login
+gb.errorOnlyAdminMayCreateRepository = Somente umadministrador pode criar um repositório
+gb.errorOnlyAdminOrOwnerMayEditRepository = Somente umadministrador pode editar um repositório
+gb.errorAdministrationDisabled = Administração está desabilitada
+gb.lastNDays = últimos {0} dias
+gb.completeGravatarProfile = Profile completo em Gravatar.com
+gb.none = nenhum
+gb.line = linha
+gb.content = conteúdo
+gb.empty = vazio
+gb.inherited = herdado
+gb.deleteRepository = Deletar repositório \"{0}\"?
+gb.repositoryDeleted = Repositório ''{0}'' deletado.
+gb.repositoryDeleteFailed = Não foi possível apagar o repositório ''{0}''!
+gb.deleteUser = Deletar usuário \"{0}\"?
+gb.userDeleted = Usuário ''{0}'' deletado.
+gb.userDeleteFailed = Não foi possível apagar o usuário ''{0}''!
+gb.time.justNow = agora mesmo
+gb.time.today = hoje
+gb.time.yesterday = ontem
+gb.time.minsAgo = há {0} minutos
+gb.time.hoursAgo = há {0} horas
+gb.time.daysAgo = há {0} dias
+gb.time.weeksAgo = há {0} semanas
+gb.time.monthsAgo = há {0} meses
+gb.time.oneYearAgo = há 1 ano
+gb.time.yearsAgo = há {0} anos
+gb.duration.oneDay = 1 dia
+gb.duration.days = {0} dias
+gb.duration.oneMonth = 1 mês
+gb.duration.months = {0} meses
+gb.duration.oneYear = 1 ano
+gb.duration.years = {0} anos
+gb.authorizationControl = controle de autorização
+gb.allowAuthenticatedDescription = conceder permissão RW+ para todos os usuários autênticados
+gb.allowNamedDescription = conceder permissões refinadas para usuários escolhidos ou equipes
+gb.markdownFailure = Não foi possível converter conteúdo Markdown!
+gb.clearCache = limpar o cache
+gb.projects = projetos
+gb.project = projeto
+gb.allProjects = todos projetos
+gb.copyToClipboard = copiar para o clipboard
+gb.fork = fork
+gb.forks = forks
+gb.forkRepository = fork {0}?
+gb.repositoryForked = fork feito em {0}
+gb.repositoryForkFailed= não foi possível fazer fork
+gb.personalRepositories = repositórios pessoais
+gb.allowForks = permitir forks
+gb.allowForksDescription = permitir usuários autorizados a fazer fork deste repositório
+gb.forkedFrom = forked de
+gb.canFork = pode fazer fork
+gb.canForkDescription = pode fazer fork de repositórios autorizados para repositórios pessoais
+gb.myFork = visualizar meu fork
+gb.forksProhibited = forks proibidos
+gb.forksProhibitedWarning = este repositório proíbe forks
+gb.noForks = {0} não possui forks
+gb.forkNotAuthorized = desculpe, você não está autorizado a fazer fork de {0}
+gb.forkInProgress = fork em progresso
+gb.preparingFork = preparando seu fork...
+gb.isFork = é fork
+gb.canCreate = pode criar
+gb.canCreateDescription = pode criar repositórios pessoais
+gb.illegalPersonalRepositoryLocation = seu repositório pessoal deve estar localizado em \"{0}\"
+gb.verifyCommitter = verificar committer
+gb.verifyCommitterDescription = requer a identidade do committer para combinar com uma conta do Gitblt
+gb.verifyCommitterNote = todos os merges requerem "--no-ff" para impor a identidade do committer
+gb.repositoryPermissions = permissões de repositório
+gb.userPermissions = permissões de usuário
+gb.teamPermissions = permissões de equipe
+gb.add = add
+gb.noPermission = APAGAR ESTA PERMISSÃO
+gb.excludePermission = {0} (excluir)
+gb.viewPermission = {0} (visualizar)
+gb.clonePermission = {0} (clonar)
+gb.pushPermission = {0} (push)
+gb.createPermission = {0} (push, ref creation)
+gb.deletePermission = {0} (push, ref creation+deletion)
+gb.rewindPermission = {0} (push, ref creation+deletion+rewind)
+gb.permission = permissão
+gb.regexPermission = esta permissão foi configurada através da expressão regular \"{0}\"
+gb.accessDenied = acesso negado
+gb.busyCollectingGarbage = desculpe, o Gitblit está ocupado coletando lixo em {0}
+gb.gcPeriod = período do GC
+gb.gcPeriodDescription = duração entre as coletas de lixo
+gb.gcThreshold = limite do GC
+gb.gcThresholdDescription = tamanho total mínimo de objetos \"soltos\" que ativam a coleta de lixo
+gb.ownerPermission = proprietário do repositório
+gb.administrator = administrador
+gb.administratorPermission = administrador do Gitblit
+gb.team = equipe
+gb.teamPermission = permissão concedida pela filiação a equipe \"{0}\"
+gb.missing = faltando!
+gb.missingPermission = o repositório para esta permissão está faltando!
+gb.mutable = mutável
+gb.specified = específico
+gb.effective = efetivo
+gb.organizationalUnit = unidade organizacional
+gb.organization = organização
+gb.locality = localidade
+gb.stateProvince = estado ou província
+gb.countryCode = código do país
+gb.properties = propriedades
+gb.issued = emitido
+gb.expires = expira
+gb.expired = expirado
+gb.expiring = expirando
+gb.revoked = revogado
+gb.serialNumber = número serial
+gb.certificates = certificados
+gb.newCertificate = novo certificado
+gb.revokeCertificate = revogar certificado
+gb.sendEmail = enviar email
+gb.passwordHint = dica de password
+gb.ok = ok
+gb.invalidExpirationDate = data de expiração inválida!
+gb.passwordHintRequired = dica de password requerida!
+gb.viewCertificate = visualizar certificado
+gb.subject = assunto
+gb.issuer = emissor
+gb.validFrom = válido a partir de
+gb.validUntil = válido até
+gb.publicKey = chave pública
+gb.signatureAlgorithm = algoritmo de assinatura
+gb.sha1FingerPrint = digital SHA-1
+gb.md5FingerPrint = digital MD5
+gb.reason = razão
+gb.revokeCertificateReason = Por selecione a razão da revogação do certificado
+gb.unspecified = não específico
+gb.keyCompromise = comprometimento de chave
+gb.caCompromise = compromisso CA
+gb.affiliationChanged = afiliação foi alterada
+gb.superseded = substituídas
+gb.cessationOfOperation = cessação de funcionamento
+gb.privilegeWithdrawn = privilégio retirado
+gb.time.inMinutes = em {0} minutos
+gb.time.inHours = em {0} horas
+gb.time.inDays = em {0} dias
+gb.hostname = hostname
+gb.hostnameRequired = Por favor insira um hostname
+gb.newSSLCertificate = novo servidor de certificado SSL
+gb.newCertificateDefaults = novos padrões de certificação
+gb.duration = duração
+gb.certificateRevoked = Certificado {0, número, 0} foi revogado
+gb.clientCertificateGenerated = Novo certificado cliente para {0} foi gerado com sucesso
+gb.sslCertificateGenerated = Novo servidor de certificado SSL gerado com sucesso para {0}
+gb.newClientCertificateMessage = OBSERVAÇÃO:\nO 'password' não é o password do usuário mas sim o password usado para proteger a keystore. Este password não será salvo então você também inserir uma dica que será incluída nas instruções de LEIA-ME do usuário.
+gb.certificate = certificado
+gb.emailCertificateBundle = pacote certificado de cliente de email
+gb.pleaseGenerateClientCertificate = Por favor gere um certificado cliente para {0}
+gb.clientCertificateBundleSent = Pacote de certificado de cliente para {0} enviada
+gb.enterKeystorePassword = Por favor insira uma chave para keystore do Gitblit
+gb.warning = warning
+gb.jceWarning = Seu Java Runtime Environment não tem os arquivos \"JCE Unlimited Strength Jurisdiction Policy\".\nIsto irá limitar o tamanho dos passwords que você usará para encriptar suas keystores para 7 caracteres.\nEstes arquivos de políticas são um download opcional da Oracle.\n\nVocê gostaria de continuar e gerar os certificados de infraestrutura de qualquer forma?\n\nRespondendo "Não" irá redirecionar o seu browser para a página de downloads da Oracle, de onde você poderá fazer download desses arquivos.
+gb.maxActivityCommits = limitar exibição de commits
+gb.maxActivityCommitsDescription = quantidade máxima de commits para contribuir para a página de atividade
+gb.noMaximum = ilimitado
+gb.attributes = atributos
+gb.serveCertificate = servir https com este certificado
+gb.sslCertificateGeneratedRestart = Novo certificado SSL de servidor gerado com sucesso para {0}.\nVocê deve reiniciar o Gitblit para usar o novo certificado.\n\nSe você estiver executando com o parâmetro '--alias', você precisará alterá-lo para ''--alias {0}''.
+gb.validity = validade
+gb.siteName = nome do site
+gb.siteNameDescription = breve, mas ainda assim um nome descritivo para seu servidor
+gb.excludeFromActivity = excluir da página de atividades
+gb.isSparkleshared = repositório é Sparkleshared
+gb.owners = proprietários
+gb.sessionEnded = Session has been closed
+gb.closeBrowser = Please close the browser to properly end the session.
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_CN.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_CN.properties new file mode 100644 index 00000000..96e2067b --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_CN.properties @@ -0,0 +1,446 @@ +gb.repository = \u7248\u672c\u5e93 +gb.owner = \u7ba1\u7406\u5458 +gb.description = \u63cf\u8ff0 +gb.lastChange = \u6700\u8fd1\u4fee\u6539 +gb.refs = refs +gb.tag = \u6807\u7b7e +gb.tags = \u6807\u7b7e +gb.author = \u7528\u6237 +gb.committer = \u63d0\u4ea4\u8005 +gb.commit = \u63d0\u4ea4 +gb.tree = \u76ee\u5f55 +gb.parent = parent +gb.url = URL +gb.history = \u5386\u53f2\u4fe1\u606f +gb.raw = raw +gb.object = object +gb.ticketId = ticket id +gb.ticketAssigned = assigned +gb.ticketOpenDate = \u5f00\u542f\u65e5\u671f +gb.ticketState = \u72b6\u6001 +gb.ticketComments = \u8bc4\u8bba +gb.view = \u67e5\u770b +gb.local = \u672c\u5730 +gb.remote = \u8fdc\u7a0b +gb.branches = \u5206\u652f +gb.patch = patch +gb.diff = \u5bf9\u6bd4 +gb.log = \u65e5\u5fd7 +gb.moreLogs = \u66f4\u591a\u63d0\u4ea4... +gb.allTags = \u6240\u6709\u6807\u7b7e... +gb.allBranches = \u6240\u6709\u5206\u652f... +gb.summary = \u6982\u51b5 +gb.ticket = ticket +gb.newRepository = \u521b\u5efa\u7248\u672c\u5e93 +gb.newUser = \u6dfb\u52a0\u7528\u6237 +gb.commitdiff = \u5bf9\u6bd4\u63d0\u4ea4\u7684\u5185\u5bb9 +gb.tickets = tickets +gb.pageFirst = \u9996\u9875 +gb.pagePrevious = \u524d\u4e00\u9875 +gb.pageNext = \u4e0b\u4e00\u9875 +gb.head = HEAD +gb.blame = blame +gb.login = \u767b\u5f55 +gb.logout = \u6ce8\u9500 +gb.username = \u7528\u6237\u540d +gb.password = \u5bc6\u7801 +gb.tagger = \u6807\u8bb0\u8005 +gb.moreHistory = \u66f4\u591a\u7684\u5386\u53f2\u4fe1\u606f... +gb.difftocurrent = \u5bf9\u6bd4\u5f53\u524d +gb.search = \u641c\u7d22 +gb.searchForAuthor = \u6309\u4f5c\u8005\u641c\u7d22 commits +gb.searchForCommitter = \u6309\u63d0\u4ea4\u8005\u641c\u7d22 commits +gb.addition = \u6dfb\u52a0 +gb.modification = \u4fee\u6539 +gb.deletion = \u5220\u9664 +gb.rename = \u91cd\u547d\u540d +gb.metrics = metrics +gb.stats = \u7edf\u8ba1 +gb.markdown = markdown +gb.changedFiles = \u5df2\u4fee\u6539\u6587\u4ef6 +gb.filesAdded = {0}\u4e2a\u6587\u4ef6\u5df2\u6dfb\u52a0 +gb.filesModified = {0}\u4e2a\u6587\u4ef6\u5df2\u4fee\u6539 +gb.filesDeleted = {0}\u4e2a\u6587\u4ef6\u5df2\u5220\u9664 +gb.filesCopied = {0} \u6587\u4ef6\u5df2\u590d\u5236 +gb.filesRenamed = {0} \u6587\u4ef6\u5df2\u91cd\u547d\u540d +gb.missingUsername = \u7528\u6237\u540d\u4e0d\u5b58\u5728 +gb.edit = \u7f16\u8f91 +gb.searchTypeTooltip = \u9009\u62e9\u641c\u7d22\u7c7b\u578b +gb.searchTooltip = \u641c\u7d22 {0} +gb.delete = \u5220\u9664 +gb.docs = \u6587\u6863 +gb.accessRestriction = \u8bbf\u95ee\u9650\u5236 +gb.name = \u540d\u79f0 +gb.enableTickets = \u5141\u8bb8 tickets +gb.enableDocs = \u5141\u8bb8\u6587\u6863 +gb.save = \u4fdd\u5b58 +gb.showRemoteBranches = \u663e\u793a\u8fdc\u7a0b\u5206\u652f +gb.editUsers = \u7f16\u8f91\u7528\u6237 +gb.confirmPassword = \u786e\u8ba4\u5bc6\u7801 +gb.restrictedRepositories = \u7248\u672c\u5e93\u8bbe\u7f6e +gb.canAdmin = \u7ba1\u7406\u6743\u9650 +gb.notRestricted = anonymous view, clone, & push +gb.pushRestricted = authenticated push +gb.cloneRestricted = authenticated clone & push +gb.viewRestricted = authenticated view, clone, & push +gb.useTicketsDescription = distributed Ticgit issues +gb.useDocsDescription = \u5217\u51fa\u7248\u672c\u5e93\u5185\u6240\u6709 Markdown \u6587\u6863 +gb.showRemoteBranchesDescription = \u663e\u793a\u8fdc\u7a0b\u5206\u652f +gb.canAdminDescription = Gitblit \u670d\u52a1\u5668\u7ba1\u7406\u5458 +gb.permittedUsers = \u5141\u8bb8\u7528\u6237 +gb.isFrozen = \u88ab\u51bb\u7ed3 +gb.isFrozenDescription = \u7981\u6b62\u63a8\u9001\u64cd\u4f5c +gb.zip = zip +gb.showReadme = \u663e\u793areadme +gb.showReadmeDescription = \u5728\u6982\u51b5\u9875\u9762\u663e\u793a \\"readme\\" Markdown \u6587\u4ef6 +gb.nameDescription = \u4f7f\u7528 '/' \u5bf9\u7248\u672c\u5e93\u8fdb\u884c\u5206\u7ec4 \u4f8b\u5982. libraries/mycoollib.git +gb.ownerDescription = \u521b\u5efa\u8005\u53ef\u4ee5\u7f16\u8f91\u7248\u672c\u5e93\u5c5e\u6027 +gb.blob = blob +gb.commitActivityTrend = commit \u6d3b\u52a8\u8d8b\u52bf +gb.commitActivityDOW = \u6bcf\u5468 commit \u6d3b\u52a8 +gb.commitActivityAuthors = commit \u6d3b\u52a8\u4e3b\u8981\u7528\u6237 +gb.feed = feed +gb.cancel = \u53d6\u6d88 +gb.changePassword = \u4fee\u6539\u5bc6\u7801 +gb.isFederated = is federated +gb.federateThis = federate this repository +gb.federateOrigin = federate the origin +gb.excludeFromFederation = exclude from federation +gb.excludeFromFederationDescription = \u7981\u6b62\u5df2 federated \u7684 Gitblit \u5b9e\u4f8b\u4ece\u672c\u8d26\u6237\u62c9\u53d6 +gb.tokens = federation tokens +gb.tokenAllDescription = all repositories, users, & settings +gb.tokenUnrDescription = all repositories & users +gb.tokenJurDescription = all repositories +gb.federatedRepositoryDefinitions = \u7248\u672c\u5e93\u5b9a\u4e49 +gb.federatedUserDefinitions = \u7528\u6237\u5b9a\u4e49 +gb.federatedSettingDefinitions = \u8bbe\u7f6e\u5b9a\u4e49 +gb.proposals = federation proposals +gb.received = \u5df2\u63a5\u53d7 +gb.type = type +gb.token = token +gb.repositories = \u7248\u672c\u5e93 +gb.proposal = proposal +gb.frequency = \u9891\u7387 +gb.folder = \u6587\u4ef6\u5939 +gb.lastPull = \u4e0a\u4e00\u6b21\u62c9\u53d6 +gb.nextPull = \u4e0b\u4e00\u6b21\u62c9\u53d6 +gb.inclusions = \u5305\u542b\u5185\u5bb9 +gb.exclusions = \u4f8b\u5916 +gb.registration = \u6ce8\u518c +gb.registrations = federation \u6ce8\u518c +gb.sendProposal = propose +gb.status = \u72b6\u6001 +gb.origin = origin +gb.headRef = \u9ed8\u8ba4\u5206\u652f (HEAD) +gb.headRefDescription = \u4fee\u6539 HEAD \u6240\u6307\u5411\u7684 ref\u3002 \u4f8b\u5982: refs/heads/master +gb.federationStrategy = federation \u7b56\u7565 +gb.federationRegistration = federation \u6ce8\u518c +gb.federationResults = federation \u62c9\u53d6\u7ed3\u679c +gb.federationSets = federation \u96c6 +gb.message = \u6d88\u606f +gb.myUrlDescription = \u60a8\u7684 Gitblit \u5b9e\u4f8b\u7684\u516c\u5171\u8bbf\u95ee\u7f51\u5740 +gb.destinationUrl = \u53d1\u9001\u81f3 +gb.destinationUrlDescription = \u4f60\u6240\u8981\u53d1\u9001proposal\u7684 Gitblit \u5b9e\u4f8b\u7f51\u5740 +gb.users = \u7528\u6237 +gb.federation = federation +gb.error = \u9519\u8bef +gb.refresh = \u5237\u65b0 +gb.browse = \u6d4f\u89c8 +gb.clone = \u514b\u9686 +gb.filter = \u8fc7\u6ee4 +gb.create = \u521b\u5efa +gb.servers = \u670d\u52a1\u5668 +gb.recent = \u6700\u8fd1 +gb.available = \u53ef\u7528 +gb.selected = \u5df2\u9009\u4e2d +gb.size = \u5927\u5c0f +gb.downloading = \u4e0b\u8f7d\u4e2d +gb.loading = \u8f7d\u5165\u4e2d +gb.starting = \u542f\u52a8\u4e2d +gb.general = \u5e38\u89c4 +gb.settings = \u8bbe\u7f6e +gb.manage = \u7ba1\u7406 +gb.lastLogin = \u4e0a\u6b21\u767b\u5f55 +gb.skipSizeCalculation = \u5ffd\u7565\u5927\u5c0f\u4f30\u8ba1 +gb.skipSizeCalculationDescription = \u4e0d\u8ba1\u7b97\u7248\u672c\u5e93\u5927\u5c0f\uff08\u8282\u7701\u9875\u9762\u8f7d\u5165\u65f6\u95f4\uff09 +gb.skipSummaryMetrics = \u5ffd\u7565\u6982\u51b5\u5904 metrics +gb.skipSummaryMetricsDescription = \u6982\u51b5\u9875\u9762\u4e0d\u8ba1\u7b97metrics\uff08\u8282\u7701\u9875\u9762\u8f7d\u5165\u65f6\u95f4\uff09 +gb.accessLevel = \u8bbf\u95ee\u7ea7\u522b +gb.default = \u9ed8\u8ba4 +gb.setDefault = \u9ed8\u8ba4\u8bbe\u7f6e +gb.since = \u81ea\u4ece +gb.status = \u72b6\u6001 +gb.bootDate = \u542f\u52a8\u65e5\u671f +gb.servletContainer = servlet container +gb.heapMaximum = \u6700\u5927\u5806 +gb.heapAllocated = \u5df2\u5206\u914d\u5806 +gb.heapUsed = \u5df2\u4f7f\u7528\u5806 +gb.free = \u7a7a\u95f2 +gb.version = \u7248\u672c +gb.releaseDate = \u53d1\u884c\u65e5\u671f +gb.date = \u65e5\u671f +gb.activity = \u6d3b\u52a8 +gb.subscribe = \u8ba2\u9605 +gb.branch = \u5206\u652f +gb.maxHits = \u6700\u5927\u547d\u4e2d\u6570 +gb.recentActivity = \u6700\u8fd1\u6d3b\u52a8 +gb.recentActivityStats = \u6700\u8fd1{0}\u5929 / {2}\u4f4d\u7528\u6237\u505a\u4e86{1}\u6b21\u63d0\u4ea4 +gb.recentActivityNone = \u6700\u8fd1{0}\u5929 / \u6ca1\u6709\u6d3b\u52a8 +gb.dailyActivity = \u65e5\u5e38\u6d3b\u52a8 +gb.activeRepositories = \u6d3b\u8dc3\u7684\u7248\u672c\u5e93 +gb.activeAuthors = \u6d3b\u8dc3\u7528\u6237 +gb.commits = \u63d0\u4ea4\u6b21\u6570 +gb.teams = \u56e2\u961f +gb.teamName = \u56e2\u961f\u540d\u79f0 +gb.teamMembers = \u56e2\u961f\u6210\u5458 +gb.teamMemberships = \u56e2\u961f\u6210\u5458 +gb.newTeam = \u6dfb\u52a0\u56e2\u961f +gb.permittedTeams = \u5141\u8bb8\u56e2\u961f +gb.emptyRepository = \u7a7a\u7248\u672c\u5e93 +gb.repositoryUrl = \u7248\u672c\u5e93\u5730\u5740 +gb.mailingLists = \u90ae\u4ef6\u5217\u8868 +gb.preReceiveScripts = pre-receive \u811a\u672c +gb.postReceiveScripts = post-receive \u811a\u672c +gb.hookScripts = hook \u811a\u672c +gb.customFields = \u81ea\u5b9a\u4e49\u57df +gb.customFieldsDescription = Groovy\u811a\u672c\u652f\u6301\u7684\u81ea\u5b9a\u4e49\u57df +gb.accessPermissions = \u8bbf\u95ee\u6743\u9650 +gb.filters = \u8fc7\u6ee4 +gb.generalDescription = \u4e00\u822c\u8bbe\u7f6e +gb.accessPermissionsDescription = \u6309\u7167\u7528\u6237\u548c\u56e2\u961f\u9650\u5236\u8bbf\u95ee +gb.accessPermissionsForUserDescription = \u8bbe\u7f6e\u56e2\u961f\u6210\u5458\u6216\u8005\u6388\u4e88\u6307\u5b9a\u7248\u672c\u5e93\u6743\u9650 +gb.accessPermissionsForTeamDescription = \u8bbe\u7f6e\u56e2\u961f\u6210\u5458\u5e76\u6388\u4e88\u6307\u5b9a\u7248\u672c\u5e93\u6743\u9650 +gb.federationRepositoryDescription = \u4e0e\u5176\u4ed6Gitblit\u670d\u52a1\u5668\u5206\u4eab\u7248\u672c\u5e93 +gb.hookScriptsDescription = \u5728\u670d\u52a1\u5668\u4e0a\u8fd0\u884cGroovy\u811a\u672c +gb.reset = \u91cd\u7f6e +gb.pages = \u9875\u9762 +gb.workingCopy = \u5de5\u4f5c\u526f\u672c +gb.workingCopyWarning = \u6b64\u7248\u672c\u5e93\u5b58\u5728\u4e00\u4efd\u5de5\u4f5c\u526f\u672c\uff0c\u65e0\u6cd5\u8fdb\u884c\u63a8\u9001 +gb.query = \u67e5\u8be2 +gb.queryHelp = \u652f\u6301\u6807\u51c6\u67e5\u8be2\u683c\u5f0f.<p/><p/>\u8bf7\u67e5\u770b <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene \u67e5\u8be2\u5904\u7406\u5668\u683c\u5f0f</a> \u4ee5\u83b7\u53d6\u8be6\u7ec6\u5185\u5bb9\u3002 +gb.queryResults = \u7ed3\u679c {0} - {1} ({2} \u6b21\u547d\u4e2d) +gb.noHits = \u672a\u547d\u4e2d +gb.authored = authored +gb.committed = committed +gb.indexedBranches = \u5df2\u7d22\u5f15\u5206\u652f +gb.indexedBranchesDescription = \u9009\u62e9\u8981\u653e\u5165\u4f60\u7684 Lucene \u7d22\u5f15\u7684\u5206\u652f +gb.noIndexedRepositoriesWarning = \u60a8\u7684\u6240\u6709\u7248\u672c\u5e93\u90fd\u6ca1\u6709\u7ecf\u8fc7Lucene\u7d22\u5f15 +gb.undefinedQueryWarning = \u67e5\u8be2\u672a\u5b9a\u4e49! +gb.noSelectedRepositoriesWarning = \u8bf7\u81f3\u5c11\u9009\u62e9\u4e00\u4e2a\u7248\u672c\u5e93! +gb.luceneDisabled = Lucene\u7d22\u5f15\u5df2\u88ab\u7981\u6b62 +gb.failedtoRead = \u8bfb\u53d6\u5931\u8d25 +gb.isNotValidFile = \u4e0d\u662f\u5408\u6cd5\u6587\u4ef6 +gb.failedToReadMessage = \u5728 {0} \u4e2d\u8bfb\u53d6\u9ed8\u8ba4\u6d88\u606f\u5931\u8d25! +gb.passwordsDoNotMatch = \u5bc6\u7801\u4e0d\u5339\u914d! +gb.passwordTooShort = \u5bc6\u7801\u957f\u5ea6\u592a\u77ed\u3002\u6700\u77ed\u957f\u5ea6 {0} \u4e2a\u5b57\u7b26\u3002 +gb.passwordChanged = \u5bc6\u7801\u4fee\u6539\u6210\u529f\u3002 +gb.passwordChangeAborted = \u5bc6\u7801\u4fee\u6539\u7ec8\u6b62 +gb.pleaseSetRepositoryName = \u8bf7\u8bbe\u7f6e\u4e00\u4e2a\u7248\u672c\u5e93\u540d\u79f0! +gb.illegalLeadingSlash = \u7981\u6b62\u4f7f\u7528\u6839\u76ee\u5f55\u5f15\u7528 (/) \u3002 +gb.illegalRelativeSlash = \u76f8\u5bf9\u6587\u4ef6\u5939\u8def\u5f84(../)\u7981\u6b62\u4f7f\u7528 +gb.illegalCharacterRepositoryName = \u7248\u672c\u5e93\u4e2d\u542b\u6709\u4e0d\u5408\u6cd5\u5b57\u7b26 ''{0}'' ! +gb.selectAccessRestriction = \u8bf7\u9009\u62e9\u8bbf\u95ee\u6743\u9650\uff01 +gb.selectFederationStrategy = \u8bf7\u9009\u62e9federation\u7b56\u7565! +gb.pleaseSetTeamName = \u8bf7\u8f93\u5165\u4e00\u4e2a\u56e2\u961f\u540d\u79f0\uff01 +gb.teamNameUnavailable = \u56e2\u961f\u540d ''{0}'' \u4e0d\u5408\u6cd5. +gb.teamMustSpecifyRepository = \u56e2\u961f\u5fc5\u987b\u62e5\u6709\u81f3\u5c11\u4e00\u4e2a\u7248\u672c\u5e93\u3002 +gb.teamCreated = \u6210\u529f\u521b\u5efa\u65b0\u56e2\u961f ''{0}'' . +gb.pleaseSetUsername = \u8bf7\u8f93\u5165\u7528\u6237\u540d\uff01 +gb.usernameUnavailable = \u7528\u6237\u540d ''{0}'' \u4e0d\u53ef\u7528.. +gb.combinedMd5Rename = Gitblit\u91c7\u7528\u6df7\u5408md5\u5bc6\u7801\u54c8\u5e0c\u3002\u56e0\u6b64\u5fc5\u987b\u5728\u4fee\u6539\u7528\u6237\u540d\u540e\u4fee\u6539\u5bc6\u7801\u3002 +gb.userCreated = \u6210\u529f\u521b\u5efa\u65b0\u7528\u6237 \\"{0}\\"\u3002 +gb.couldNotFindFederationRegistration = \u65e0\u6cd5\u627e\u5230federation registration! +gb.failedToFindGravatarProfile = \u52a0\u8f7d {0} \u7684Gravatar\u4fe1\u606f\u5931\u8d25 +gb.branchStats = {0} \u4e2a\u63d0\u4ea4\u548c {1} \u4e2a\u6807\u7b7e\u5728 {2} \u5185 +gb.repositoryNotSpecified = \u672a\u6307\u5b9a\u7248\u672c\u5e93! +gb.repositoryNotSpecifiedFor = \u6ca1\u6709\u4e3a {0} \u8bbe\u7f6e\u7248\u672c\u5e93! +gb.canNotLoadRepository = \u65e0\u6cd5\u8f7d\u5165\u7248\u672c\u5e93 +gb.commitIsNull = \u63d0\u4ea4\u5185\u5bb9\u4e3a\u7a7a +gb.unauthorizedAccessForRepository = \u672a\u6388\u6743\u8bbf\u95ee\u7248\u672c\u5e93 +gb.failedToFindCommit = \u5728 {1} \u4e2d {2} \u4e2a\u9875\u9762\u5185\u67e5\u627e\u63d0\u4ea4 \\"{0}\\"\u5931\u8d25! +gb.couldNotFindFederationProposal = \u65e0\u6cd5\u627e\u5230federation proposal! +gb.invalidUsernameOrPassword = \u7528\u6237\u540d\u6216\u8005\u5bc6\u7801\u9519\u8bef\uff01 +gb.OneProposalToReview = 1\u4e2afederation proposals\u7b49\u5f85\u68c0\u67e5\u3002 +gb.nFederationProposalsToReview = {0} \u4e2afederation proposals\u7b49\u5f85\u68c0\u67e5 +gb.couldNotFindTag = \u65e0\u6cd5\u627e\u5230\u6807\u7b7e {0} +gb.couldNotCreateFederationProposal = \u65e0\u6cd5\u521b\u5efafederation proposal! +gb.pleaseSetGitblitUrl = \u8bf7\u8f93\u5165\u4f60\u7684Gitblit\u7f51\u5740! +gb.pleaseSetDestinationUrl = \u8bf7\u4e3a\u4f60\u7684proposal\u8f93\u5165\u4e00\u4e2a\u76ee\u6807\u5730\u5740! +gb.proposalReceived = \u6210\u529f\u4ece {0} \u63a5\u6536Proposal. +gb.noGitblitFound = \u62b1\u6b49, {0} \u65e0\u6cd5\u5728{1} \u4e2d\u627e\u5230Gitblit\u5b9e\u4f8b\u3002 +gb.noProposals = \u62b1\u6b49, {0} \u5f53\u524d\u4e0d\u63a5\u53d7proposals\u3002 +gb.noFederation = \u62b1\u6b49, {0} \u6ca1\u6709\u4e0e\u4efb\u4f55Gitblit\u5b9e\u4f8b\u8bbe\u7f6efederate\u3002. +gb.proposalFailed = \u62b1\u6b49, {0} \u65e0\u6cd5\u63a5\u53d7\u4efb\u4f55proposal\u6570\u636e! +gb.proposalError = \u62b1\u6b49\uff0c{0} \u62a5\u544a\u4e2d\u53d1\u73b0\u672a\u9884\u671f\u7684\u9519\u8bef\uff01 +gb.failedToSendProposal = \u53d1\u9001proposal\u5931\u8d25! +gb.userServiceDoesNotPermitAddUser = {0} \u4e0d\u5141\u8bb8\u6dfb\u52a0\u7528\u6237! +gb.userServiceDoesNotPermitPasswordChanges = {0} \u4e0d\u5141\u8bb8\u8fdb\u884c\u5bc6\u7801\u4fee\u6539! +gb.displayName = \u663e\u793a\u540d\u79f0 +gb.emailAddress = \u90ae\u7bb1 +gb.errorAdminLoginRequired = \u9700\u8981\u7ba1\u7406\u5458\u767b\u9646 +gb.errorOnlyAdminMayCreateRepository = \u53ea\u6709\u7ba1\u7406\u5458\u624d\u53ef\u4ee5\u521b\u5efa\u7248\u672c\u5e93 +gb.errorOnlyAdminOrOwnerMayEditRepository = \u53ea\u6709\u7ba1\u7406\u5458\u6216\u8005\u6240\u6709\u8005\u624d\u53ef\u4ee5\u7f16\u8f91\u4ee3\u7801\u5e93 +gb.errorAdministrationDisabled = \u7ba1\u7406\u6743\u9650\u88ab\u7981\u6b62\u3002 +gb.lastNDays = \u6700\u8fd1 {0} \u5929 +gb.completeGravatarProfile = \u5728Gravatar.com\u4e0a\u5b8c\u6210\u4e2a\u4eba\u8bbe\u5b9a +gb.none = \u65e0 +gb.line = \u884c +gb.content = \u5185\u5bb9 +gb.empty = \u7a7a\u767d\u7248\u672c\u5e93 +gb.inherited = \u7ee7\u627f +gb.deleteRepository = \u5220\u9664\u7248\u672c\u5e93 \\"{0}\\" \uff1f +gb.repositoryDeleted = \u7248\u672c\u5e93 ''{0}'' \u5df2\u5220\u9664\u3002 +gb.repositoryDeleteFailed = \u5220\u9664\u7248\u672c\u5e93 \\"{0}\\" \u5931\u8d25\uff01 +gb.deleteUser = \u5220\u9664\u7528\u6237 \\"{0}\\" \uff1f +gb.userDeleted = \u7528\u6237 ''{0}'' \u5df2\u5220\u9664\uff01 +gb.userDeleteFailed = \u5220\u9664\u7528\u6237''{0}''\u5931\u8d25\uff01 +gb.time.justNow = \u521a\u521a +gb.time.today = \u4eca\u5929 +gb.time.yesterday = \u6628\u5929 +gb.time.minsAgo = {0} \u5206\u949f\u4ee5\u524d +gb.time.hoursAgo = {0} \u5c0f\u65f6\u4ee5\u524d +gb.time.daysAgo = {0} \u5929\u4ee5\u524d +gb.time.weeksAgo = {0} \u5468\u4ee5\u524d +gb.time.monthsAgo = {0} \u4e2a\u6708\u4ee5\u524d +gb.time.oneYearAgo = 1 \u5e74\u4ee5\u524d +gb.time.yearsAgo = {0} \u5e74\u4ee5\u524d +gb.duration.oneDay = 1 \u5929 +gb.duration.days = {0} \u5929 +gb.duration.oneMonth = 1 \u6708 +gb.duration.months = {0} \u6708 +gb.duration.oneYear = 1 \u5e74 +gb.duration.years = {0} \u5e74 +gb.authorizationControl = \u6388\u6743\u63a7\u5236 +gb.allowAuthenticatedDescription = \u6388\u4e88\u6240\u6709\u8ba4\u8bc1\u7528\u6237\u53d7\u9650\u5236\u7684\u8bbf\u95ee\u6743\u9650 +gb.allowNamedDescription = \u6388\u4e88\u6307\u5b9a\u540d\u79f0\u7684\u7528\u6237\u6216\u56e2\u961f\u53d7\u9650\u5236\u7684\u8bbf\u95ee\u6743\u9650 +gb.markdownFailure = \u8bfb\u53d6 Markdown \u5185\u5bb9\u5931\u8d25\uff01 +gb.clearCache = \u6e05\u9664\u7f13\u5b58 +gb.projects = \u9879\u76ee +gb.project = \u9879\u76ee +gb.allProjects = \u6240\u6709\u9879\u76ee +gb.copyToClipboard = \u590d\u5236\u5230\u526a\u8d34\u677f +gb.fork = \u6d3e\u751f +gb.forks = \u6d3e\u751f +gb.forkRepository = \u6d3e\u751f {0} ? +gb.repositoryForked = {0} \u5df2\u88ab\u6d3e\u751f +gb.repositoryForkFailed = \u6d3e\u751f\u5931\u8d25 +gb.personalRepositories = \u79c1\u4eba\u7248\u672c\u5e93 +gb.allowForks = \u5141\u8bb8\u6d3e\u751f +gb.allowForksDescription = \u5141\u8bb8\u8ba4\u8bc1\u7528\u6237\u6d3e\u751f\u6b64\u7248\u672c\u5e93 +gb.forkedFrom = \u6d3e\u751f\u81ea +gb.canFork = \u5141\u8bb8\u6d3e\u751f +gb.canForkDescription = \u5141\u8bb8\u6d3e\u751f\u8ba4\u8bc1\u7248\u672c\u5e93\u5230\u79c1\u4eba\u7248\u672c\u5e93 +gb.myFork = \u67e5\u770b\u6211\u7684\u6d3e\u751f +gb.forksProhibited = \u7981\u6b62\u6d3e\u751f +gb.forksProhibitedWarning = \u5f53\u524d\u7248\u672c\u5e93\u7981\u6b62\u6d3e\u751f +gb.noForks = {0} \u6ca1\u6709\u6d3e\u751f +gb.forkNotAuthorized = \u62b1\u6b49\uff0c\u4f60\u65e0\u6743\u6d3e\u751f {0} +gb.forkInProgress = \u6b63\u5728\u6d3e\u751f +gb.preparingFork = \u6b63\u5728\u4e3a\u60a8\u51c6\u5907\u6d3e\u751f... +gb.isFork = \u5df2\u6d3e\u751f +gb.canCreate = \u5141\u8bb8\u521b\u5efa +gb.canCreateDescription = \u5141\u8bb8\u521b\u5efa\u79c1\u4eba\u7248\u672c\u5e93 +gb.illegalPersonalRepositoryLocation = \u60a8\u7684\u79c1\u4eba\u7248\u672c\u5e93\u5fc5\u987b\u4f4d\u4e8e \\"{0}\\" +gb.verifyCommitter = \u9a8c\u8bc1\u63d0\u4ea4\u8005 +gb.verifyCommitterDescription = \u9700\u8981\u63d0\u4ea4\u8005\u7684\u8eab\u4efd\u4e0e Gitblit \u7528\u6237\u8eab\u4efd\u76f8\u7b26 +gb.verifyCommitterNote = \u6240\u6709\u5408\u5e76\u9009\u9879\u9700\u8981\u4f7f\u7528 \\"--no-ff\\" \u6765\u6267\u884c\u63d0\u4ea4\u8005\u9a8c\u8bc1 +gb.repositoryPermissions = \u7248\u672c\u5e93\u6743\u9650 +gb.userPermissions = \u7528\u6237\u6743\u9650 +gb.teamPermissions = \u56e2\u961f\u6743\u9650 +gb.add = \u6dfb\u52a0 +gb.noPermission = \u5220\u9664\u6b64\u6743\u9650 +gb.excludePermission = {0} (exclude) +gb.viewPermission = {0} (view) +gb.clonePermission = {0} (clone) +gb.pushPermission = {0} (push) +gb.createPermission = {0} (push, ref creation) +gb.deletePermission = {0} (push, ref creation+deletion) +gb.rewindPermission = {0} (push, ref creation+deletion+rewind) +gb.permission = \u6743\u9650 +gb.regexPermission = \u6b64\u6743\u9650\u662f\u901a\u8fc7\u6b63\u5219\u8868\u8fbe\u5f0f \\"{0}\\" \u8bbe\u7f6e +gb.accessDenied = \u8bbf\u95ee\u88ab\u62d2\u7edd +gb.busyCollectingGarbage = \u62b1\u6b49\uff0cGitblit\u6b63\u5728 {0} \u5185\u6e05\u7406\u5783\u573e +gb.gcPeriod = GC \u65f6\u95f4 +gb.gcPeriodDescription = \u5783\u573e\u6e05\u7406\u7684\u6301\u7eed\u65f6\u95f4 +gb.gcThreshold = GC \u9600\u503c +gb.gcThresholdDescription = \u6fc0\u53d1\u5783\u573e\u6e05\u7406\u7684\u6700\u5c0f objects \u5927\u5c0f +gb.ownerPermission = \u7248\u672c\u5e93\u521b\u5efa\u8005 +gb.administrator = \u7ba1\u7406\u5458 +gb.administratorPermission = Gitblit \u7ba1\u7406\u5458 +gb.team = \u56e2\u961f +gb.teamPermission = \u901a\u8fc7 \\"{0}\\" \u56e2\u961f\u6210\u5458\u8bbe\u7f6e\u6743\u9650 +gb.missing = \u4e0d\u5b58\u5728! +gb.missingPermission = \u6b64\u6743\u9650\u7684\u7248\u672c\u5e93\u4e0d\u5b58\u5728! +gb.mutable = mutable +gb.specified = specified +gb.effective = effective +gb.organizationalUnit = \u7ec4\u7ec7\u90e8\u5206 +gb.organization = \u7ec4\u7ec7 +gb.locality = \u5730\u533a +gb.stateProvince = \u5dde\u6216\u7701 +gb.countryCode = \u56fd\u5bb6\u4ee3\u7801 +gb.properties = \u5c5e\u6027 +gb.issued = issued +gb.expires = \u5230\u671f +gb.expired = \u5df2\u5230\u671f +gb.expiring = \u5373\u5c06\u8fc7\u671f +gb.revoked = \u5df2\u64a4\u9500 +gb.serialNumber = \u5e8f\u5217\u53f7 +gb.certificates = \u8bc1\u4e66 +gb.newCertificate = \u521b\u5efa\u8bc1\u4e66 +gb.revokeCertificate = \u64a4\u9500\u8bc1\u4e66 +gb.sendEmail = \u53d1\u9001\u90ae\u4ef6 +gb.passwordHint = \u5bc6\u7801\u63d0\u793a +gb.ok = \u786e\u5b9a +gb.invalidExpirationDate = \u65e0\u6548\u7684\u8fc7\u671f\u65f6\u95f4! +gb.passwordHintRequired = \u9700\u8981\u586b\u5199\u5bc6\u7801\u63d0\u793a! +gb.viewCertificate = \u67e5\u770b\u8bc1\u4e66 +gb.subject = \u4e3b\u9898 +gb.issuer = \u63d0\u4ea4\u8005 +gb.validFrom = \u6709\u6548\u671f\u5f00\u59cb\u81ea +gb.validUntil = \u6709\u6548\u671f\u622a\u6b62\u4e8e +gb.publicKey = \u516c\u94a5 +gb.signatureAlgorithm = \u7b7e\u540d\u7b97\u6cd5 +gb.sha1FingerPrint = SHA-1 \u6307\u7eb9\u7b97\u6cd5 +gb.md5FingerPrint = MD5 \u6307\u7eb9\u7b97\u6cd5 +gb.reason = \u7406\u7531 +gb.revokeCertificateReason = \u8bf7\u9009\u62e9\u64a4\u9500\u8bc1\u4e66\u7684\u7406\u7531 +gb.unspecified = \u672a\u6307\u5b9a +gb.keyCompromise = key compromise +gb.caCompromise = CA compromise +gb.affiliationChanged = \u96b6\u5c5e\u5173\u7cfb\u5df2\u4fee\u6539 +gb.superseded = \u5df2\u53d6\u4ee3 +gb.cessationOfOperation = \u505c\u6b62\u64cd\u4f5c +gb.privilegeWithdrawn = \u7279\u6743\u5df2\u64a4\u56de +gb.time.inMinutes = {0} \u5206\u949f\u4e4b\u5185 +gb.time.inHours = {0} \u5c0f\u65f6\u4e4b\u5185 +gb.time.inDays = {0} \u5929\u4e4b\u5185 +gb.hostname = hostname +gb.hostnameRequired = \u8bf7\u8f93\u5165 hostname +gb.newSSLCertificate = \u521b\u5efa\u670d\u52a1\u5668 SSL \u8bc1\u4e66 +gb.newCertificateDefaults = \u521b\u5efa\u8bc1\u4e66\u9ed8\u8ba4\u8bbe\u7f6e +gb.duration = \u6301\u7eed\u65f6\u95f4 +gb.certificateRevoked = \u8bc1\u4e66 {0,number,0} \u5df2\u88ab\u64a4\u9500 +gb.clientCertificateGenerated = \u6210\u529f\u4e3a {0} \u751f\u6210\u65b0\u7684\u5ba2\u6237\u7aef\u8bc1\u4e66 +gb.sslCertificateGenerated = \u6210\u529f\u4e3a {0} \u751f\u6210\u65b0\u7684\u670d\u52a1\u5668 SSL \u8bc1\u4e66 +gb.newClientCertificateMessage = \u6ce8\u610f:\\n\u6b64\u5bc6\u7801\u5e76\u975e\u7528\u6237\u5bc6\u7801, \u8fd9\u662f\u4fdd\u5b58\u7528\u6237 keystore \u7684\u5bc6\u7801\u3002 \u7531\u4e8e\u672c\u5bc6\u7801\u672a\u5b58\u50a8\uff0c\u56e0\u6b64\u4f60\u5fc5\u987b\u4e00\u4e2a\u5bc6\u7801\u63d0\u793a\uff0c\u8fd9\u4e2a\u63d0\u793a\u4f1a\u8bb0\u5f55\u5728\u7528\u6237\u7684 README \u6587\u6863\u5185\u3002 +gb.certificate = \u8bc1\u4e66 +gb.emailCertificateBundle = \u53d1\u9001\u5ba2\u6237\u7aef\u8bc1\u4e66 +gb.pleaseGenerateClientCertificate = \u8bf7\u4e3a {0} \u751f\u6210\u4e00\u4e2a\u5ba2\u6237\u7aef\u8bc1\u4e66 +gb.clientCertificateBundleSent = {0} \u7684\u5ba2\u6237\u7aef\u8bc1\u4e66\u5df2\u53d1\u9001 +gb.enterKeystorePassword = \u8bf7\u8f93\u5165 Gitblit keystore \u5bc6\u7801 +gb.warning = \u8b66\u544a +gb.jceWarning = \u60a8\u7684 JAVA \u8fd0\u884c\u73af\u5883\u4e0d\u5305\u542b \\"JCE Unlimited Strength Jurisdiction Policy\\" \u6587\u4ef6\u3002\\n\u8fd9\u5c06\u5bfc\u81f4\u60a8\u6700\u591a\u53ea\u80fd\u75287\u4e2a\u5b57\u7b26\u7684\u5bc6\u7801\u4fdd\u62a4\u60a8\u7684 keystore\u3002 \\n\u8fd9\u4e9b\u662f\u4e00\u4e9b\u53ef\u9009\u4e0b\u8f7d\u7684\u653f\u7b56\u6587\u4ef6\u3002\\n\\n\u4f60\u662f\u5426\u8981\u7ee7\u7eed\u751f\u6210\u8bc1\u4e66\uff1f\\n\\n\u9009\u62e9\u5426\u7684\u8bdd\uff0c\u5c06\u4f1a\u6253\u5f00\u4e00\u4e2a\u6d4f\u89c8\u5668\u754c\u9762\u4f9b\u60a8\u4e0b\u8f7d\u76f8\u5173\u6587\u4ef6\u3002 +gb.maxActivityCommits = \u6700\u5927\u6d3b\u52a8\u63d0\u4ea4\u6570 +gb.maxActivityCommitsDescription = \u6d3b\u52a8\u9875\u9762\u663e\u793a\u7684\u6700\u5927\u63d0\u4ea4\u6570 +gb.noMaximum = \u65e0\u4e0a\u9650 +gb.attributes = \u5c5e\u6027 +gb.serveCertificate = \u4f7f\u7528\u6b64\u8bc1\u4e66\u63d0\u4f9b https \u652f\u6301 +gb.sslCertificateGeneratedRestart = \u6210\u529f\u4e3a {0} \u751f\u6210\u65b0\u7684 SSL \u8bc1\u4e66.\\n\u4f60\u5fc5\u987b\u91cd\u65b0\u542f\u52a8 Gitblit \u4ee5\u4f7f\u7528\u6b64\u8bc1\u4e66\u3002\\n\\n\u5982\u679c\u60a8\u4f7f\u7528 '--alias' \u53c2\u6570\u542f\u52a8\uff0c\u4f60\u5fc5\u987b\u4e5f\u8981\u8bbe\u7f6e ''--alias {0}''\u3002 +gb.validity = \u5408\u6cd5\u6027 +gb.siteName = \u7f51\u7ad9\u540d\u79f0 +gb.siteNameDescription = \u60a8\u7684\u670d\u52a1\u5668\u7684\u7b80\u8981\u63cf\u8ff0 +gb.excludeFromActivity = \u4ece\u6d3b\u52a8\u9875\u9762\u6392\u9664 +gb.isSparkleshared = repository is Sparkleshared +gb.sessionEnded = Session has been closed +gb.closeBrowser = Please close the browser to properly end the session.
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebSession.java b/src/main/java/com/gitblit/wicket/GitBlitWebSession.java new file mode 100644 index 00000000..5195a1fd --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitBlitWebSession.java @@ -0,0 +1,157 @@ +/*
+ * Copyright 2011 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;
+
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.wicket.Page;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.RedirectToUrlException;
+import org.apache.wicket.Request;
+import org.apache.wicket.Session;
+import org.apache.wicket.protocol.http.RequestUtils;
+import org.apache.wicket.protocol.http.WebRequestCycle;
+import org.apache.wicket.protocol.http.WebSession;
+import org.apache.wicket.protocol.http.request.WebClientInfo;
+
+import com.gitblit.Constants.AuthenticationType;
+import com.gitblit.models.UserModel;
+
+public final class GitBlitWebSession extends WebSession {
+
+ private static final long serialVersionUID = 1L;
+
+ protected TimeZone timezone;
+
+ private UserModel user;
+
+ private String errorMessage;
+
+ private String requestUrl;
+
+ private AtomicBoolean isForking;
+
+ public AuthenticationType authenticationType;
+
+ public GitBlitWebSession(Request request) {
+ super(request);
+ isForking = new AtomicBoolean();
+ authenticationType = AuthenticationType.CREDENTIALS;
+ }
+
+ public void invalidate() {
+ super.invalidate();
+ user = null;
+ }
+
+ /**
+ * Cache the requested protected resource pending successful authentication.
+ *
+ * @param pageClass
+ */
+ public void cacheRequest(Class<? extends Page> pageClass) {
+ // build absolute url with correctly encoded parameters?!
+ Request req = WebRequestCycle.get().getRequest();
+ Map<String, ?> params = req.getRequestParameters().getParameters();
+ PageParameters pageParams = new PageParameters(params);
+ String relativeUrl = WebRequestCycle.get().urlFor(pageClass, pageParams).toString();
+ requestUrl = RequestUtils.toAbsolutePath(relativeUrl);
+ if (isTemporary())
+ {
+ // we must bind the temporary session into the session store
+ // so that we can re-use this session for reporting an error message
+ // on the redirected page and continuing the request after
+ // authentication.
+ bind();
+ }
+ }
+
+ /**
+ * Continue any cached request. This is used when a request for a protected
+ * resource is aborted/redirected pending proper authentication. Gitblit
+ * no longer uses Wicket's built-in mechanism for this because of Wicket's
+ * failure to properly handle parameters with forward-slashes. This is a
+ * constant source of headaches with Wicket.
+ *
+ * @return false if there is no cached request to process
+ */
+ public boolean continueRequest() {
+ if (requestUrl != null) {
+ String url = requestUrl;
+ requestUrl = null;
+ throw new RedirectToUrlException(url);
+ }
+ return false;
+ }
+
+ public boolean isLoggedIn() {
+ return user != null;
+ }
+
+ public boolean canAdmin() {
+ if (user == null) {
+ return false;
+ }
+ return user.canAdmin();
+ }
+
+ public String getUsername() {
+ return user == null ? "anonymous" : user.username;
+ }
+
+ public UserModel getUser() {
+ return user;
+ }
+
+ public void setUser(UserModel user) {
+ this.user = user;
+ }
+
+ public TimeZone getTimezone() {
+ if (timezone == null) {
+ timezone = ((WebClientInfo) getClientInfo()).getProperties().getTimeZone();
+ }
+ // use server timezone if we can't determine the client timezone
+ if (timezone == null) {
+ timezone = TimeZone.getDefault();
+ }
+ return timezone;
+ }
+
+ public void cacheErrorMessage(String message) {
+ this.errorMessage = message;
+ }
+
+ public String clearErrorMessage() {
+ String msg = errorMessage;
+ errorMessage = null;
+ return msg;
+ }
+
+ public boolean isForking() {
+ return isForking.get();
+ }
+
+ public void isForking(boolean val) {
+ isForking.set(val);
+ }
+
+ public static GitBlitWebSession get() {
+ return (GitBlitWebSession) Session.get();
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/GitblitParamUrlCodingStrategy.java b/src/main/java/com/gitblit/wicket/GitblitParamUrlCodingStrategy.java new file mode 100644 index 00000000..fb86fb0e --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitblitParamUrlCodingStrategy.java @@ -0,0 +1,109 @@ +/*
+ * Copyright 2011 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;
+
+import java.text.MessageFormat;
+
+import org.apache.wicket.IRequestTarget;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.request.RequestParameters;
+import org.apache.wicket.request.target.coding.MixedParamUrlCodingStrategy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+
+/**
+ * Simple subclass of mixed parameter url coding strategy that works around the
+ * encoded forward-slash issue that is present in some servlet containers.
+ *
+ * https://issues.apache.org/jira/browse/WICKET-1303
+ * http://tomcat.apache.org/security-6.html
+ *
+ * @author James Moger
+ *
+ */
+public class GitblitParamUrlCodingStrategy extends MixedParamUrlCodingStrategy {
+
+ private Logger logger = LoggerFactory.getLogger(GitblitParamUrlCodingStrategy.class);
+
+ /**
+ * Construct.
+ *
+ * @param <C>
+ * @param mountPath
+ * mount path (not empty)
+ * @param bookmarkablePageClass
+ * class of mounted page (not null)
+ * @param parameterNames
+ * the parameter names (not null)
+ */
+ public <C extends Page> GitblitParamUrlCodingStrategy(String mountPath,
+ Class<C> bookmarkablePageClass, String[] parameterNames) {
+ super(mountPath, bookmarkablePageClass, parameterNames);
+ }
+
+ /**
+ * Url encodes a string that is mean for a URL path (e.g., between slashes)
+ *
+ * @param string
+ * string to be encoded
+ * @return encoded string
+ */
+ protected String urlEncodePathComponent(String string) {
+ char altChar = GitBlit.getChar(Keys.web.forwardSlashCharacter, '/');
+ if (altChar != '/') {
+ string = string.replace('/', altChar);
+ }
+ return super.urlEncodePathComponent(string);
+ }
+
+ /**
+ * Returns a decoded value of the given value (taken from a URL path
+ * section)
+ *
+ * @param value
+ * @return Decodes the value
+ */
+ protected String urlDecodePathComponent(String value) {
+ char altChar = GitBlit.getChar(Keys.web.forwardSlashCharacter, '/');
+ if (altChar != '/') {
+ value = value.replace(altChar, '/');
+ }
+ return super.urlDecodePathComponent(value);
+ }
+
+ /**
+ * Gets the decoded request target.
+ *
+ * @param requestParameters
+ * the request parameters
+ * @return the decoded request target
+ */
+ @Override
+ public IRequestTarget decode(RequestParameters requestParameters) {
+ final String parametersFragment = requestParameters.getPath().substring(
+ getMountPath().length());
+ logger.debug(MessageFormat
+ .format("REQ: {0} PARAMS {1}", getMountPath(), parametersFragment));
+
+ final PageParameters parameters = new PageParameters(decodeParameters(parametersFragment,
+ requestParameters.getParameters()));
+ return super.decode(requestParameters);
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/GitblitRedirectException.java b/src/main/java/com/gitblit/wicket/GitblitRedirectException.java new file mode 100644 index 00000000..c3df1ac1 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitblitRedirectException.java @@ -0,0 +1,49 @@ +/* + * Copyright 2012 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; + +import org.apache.wicket.AbstractRestartResponseException; +import org.apache.wicket.Page; +import org.apache.wicket.PageParameters; +import org.apache.wicket.RequestCycle; +import org.apache.wicket.protocol.http.RequestUtils; +import org.apache.wicket.request.target.basic.RedirectRequestTarget; + +/** + * This exception bypasses the servlet container rewriting relative redirect + * urls. The container can and does decode the carefully crafted %2F path + * separators on a redirect. :( Bad, bad servlet container. + * + * org.eclipse.jetty.server.Response#L447: String path=uri.getDecodedPath(); + * + * @author James Moger + */ +public class GitblitRedirectException extends AbstractRestartResponseException { + + private static final long serialVersionUID = 1L; + + public <C extends Page> GitblitRedirectException(Class<C> pageClass) { + this(pageClass, null); + } + + public <C extends Page> GitblitRedirectException(Class<C> pageClass, PageParameters params) { + RequestCycle cycle = RequestCycle.get(); + String relativeUrl = cycle.urlFor(pageClass, params).toString(); + String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl); + cycle.setRequestTarget(new RedirectRequestTarget(absoluteUrl)); + cycle.setRedirect(true); + } +} diff --git a/src/main/java/com/gitblit/wicket/PageRegistration.java b/src/main/java/com/gitblit/wicket/PageRegistration.java new file mode 100644 index 00000000..e8eeabae --- /dev/null +++ b/src/main/java/com/gitblit/wicket/PageRegistration.java @@ -0,0 +1,215 @@ +/*
+ * Copyright 2011 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;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.WebPage;
+
+import com.gitblit.utils.StringUtils;
+
+/**
+ * Represents a page link registration for the topbar.
+ *
+ * @author James Moger
+ *
+ */
+public class PageRegistration implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ public final String translationKey;
+ public final Class<? extends WebPage> pageClass;
+ public final PageParameters params;
+
+ public PageRegistration(String translationKey, Class<? extends WebPage> pageClass) {
+ this(translationKey, pageClass, null);
+ }
+
+ public PageRegistration(String translationKey, Class<? extends WebPage> pageClass,
+ PageParameters params) {
+ this.translationKey = translationKey;
+ this.pageClass = pageClass;
+ this.params = params;
+ }
+
+ /**
+ * Represents a page link to a non-Wicket page. Might be external.
+ *
+ * @author James Moger
+ *
+ */
+ public static class OtherPageLink extends PageRegistration {
+
+ private static final long serialVersionUID = 1L;
+
+ public final String url;
+
+ public OtherPageLink(String translationKey, String url) {
+ super(translationKey, null);
+ this.url = url;
+ }
+ }
+
+ /**
+ * Represents a DropDownMenu for the topbar
+ *
+ * @author James Moger
+ *
+ */
+ public static class DropDownMenuRegistration extends PageRegistration {
+
+ private static final long serialVersionUID = 1L;
+
+ public final List<DropDownMenuItem> menuItems;
+
+ public DropDownMenuRegistration(String translationKey, Class<? extends WebPage> pageClass) {
+ super(translationKey, pageClass);
+ menuItems = new ArrayList<DropDownMenuItem>();
+ }
+ }
+
+ /**
+ * A MenuItem for the DropDownMenu.
+ *
+ * @author James Moger
+ *
+ */
+ public static class DropDownMenuItem implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ final PageParameters parameters;
+ final String displayText;
+ final String parameter;
+ final String value;
+ final boolean isSelected;
+
+ /**
+ * Divider constructor.
+ */
+ public DropDownMenuItem() {
+ this(null, null, null, null);
+ }
+
+ /**
+ * Standard Menu Item constructor.
+ *
+ * @param displayText
+ * @param parameter
+ * @param value
+ */
+ public DropDownMenuItem(String displayText, String parameter, String value) {
+ this(displayText, parameter, value, null);
+ }
+
+ /**
+ * Standard Menu Item constructor that preserves aggregate parameters.
+ *
+ * @param displayText
+ * @param parameter
+ * @param value
+ */
+ public DropDownMenuItem(String displayText, String parameter, String value,
+ PageParameters params) {
+ this.displayText = displayText;
+ this.parameter = parameter;
+ this.value = value;
+
+ if (params == null) {
+ // no parameters specified
+ parameters = new PageParameters();
+ setParameter(parameter, value);
+ isSelected = false;
+ } else {
+ parameters = new PageParameters(params);
+ if (parameters.containsKey(parameter)) {
+ isSelected = params.getString(parameter).equals(value);
+ if (isSelected) {
+ // already selected, so remove this enables toggling
+ parameters.remove(parameter);
+ } else {
+ // set the new selection value
+ setParameter(parameter, value);
+ }
+ } else {
+ // not currently selected
+ isSelected = false;
+ setParameter(parameter, value);
+ }
+ }
+ }
+
+ private void setParameter(String parameter, String value) {
+ if (!StringUtils.isEmpty(parameter)) {
+ if (StringUtils.isEmpty(value)) {
+ this.parameters.remove(parameter);
+ } else {
+ this.parameters.put(parameter, value);
+ }
+ }
+ }
+
+ public String formatParameter() {
+ if (StringUtils.isEmpty(parameter) || StringUtils.isEmpty(value)) {
+ return "";
+ }
+ return parameter + "=" + value;
+ }
+
+ public PageParameters getPageParameters() {
+ return parameters;
+ }
+
+ public boolean isDivider() {
+ return displayText == null && value == null && parameter == null;
+ }
+
+ public boolean isSelected() {
+ return isSelected;
+ }
+
+ @Override
+ public int hashCode() {
+ if (isDivider()) {
+ // divider menu item
+ return super.hashCode();
+ }
+ if (StringUtils.isEmpty(displayText)) {
+ return value.hashCode() + parameter.hashCode();
+ }
+ return displayText.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof DropDownMenuItem) {
+ return hashCode() == o.hashCode();
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ if (StringUtils.isEmpty(displayText)) {
+ return formatParameter();
+ }
+ return displayText;
+ }
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/RequiresAdminRole.java b/src/main/java/com/gitblit/wicket/RequiresAdminRole.java new file mode 100644 index 00000000..ce2dcfcf --- /dev/null +++ b/src/main/java/com/gitblit/wicket/RequiresAdminRole.java @@ -0,0 +1,26 @@ +/*
+ * Copyright 2011 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface RequiresAdminRole {
+}
diff --git a/src/main/java/com/gitblit/wicket/SessionlessForm.java b/src/main/java/com/gitblit/wicket/SessionlessForm.java new file mode 100644 index 00000000..484e85e3 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/SessionlessForm.java @@ -0,0 +1,148 @@ +/* + * Copyright 2012 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; + +import java.text.MessageFormat; + +import org.apache.wicket.Component; +import org.apache.wicket.PageParameters; +import org.apache.wicket.markup.ComponentTag; +import org.apache.wicket.markup.MarkupStream; +import org.apache.wicket.markup.html.form.StatelessForm; +import org.apache.wicket.protocol.http.WicketURLDecoder; +import org.apache.wicket.protocol.http.request.WebRequestCodingStrategy; +import org.apache.wicket.util.string.AppendingStringBuffer; +import org.apache.wicket.util.string.Strings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.gitblit.wicket.pages.BasePage; + +/** + * This class is used to create a stateless form that can POST or GET to a + * bookmarkable page regardless of the pagemap and even after session expiration + * or a server restart. + * + * The trick is to embed "wicket:bookmarkablePage" as a hidden field of the form. + * Wicket already has logic to extract this parameter when it is trying + * to determine which page should receive the request. + * + * The parameters of the containing page can optionally be included as hidden + * fields in this form. Note that if a page parameter's name collides with any + * child's wicket:id in this form then the page parameter is excluded. + * + * @author James Moger + * + */ +public class SessionlessForm<T> extends StatelessForm<T> { + + private static final long serialVersionUID = 1L; + + private static final String HIDDEN_DIV_START = "<div style=\"width:0px;height:0px;position:absolute;left:-100px;top:-100px;overflow:hidden\">"; + + private final Class<? extends BasePage> pageClass; + + private final PageParameters pageParameters; + + private final Logger log = LoggerFactory.getLogger(SessionlessForm.class); + + /** + * Sessionless forms must have a bookmarkable page class. A bookmarkable + * page is defined as a page that has only a default and/or a PageParameter + * constructor. + * + * @param id + * @param bookmarkablePageClass + */ + public SessionlessForm(String id, Class<? extends BasePage> bookmarkablePageClass) { + this(id, bookmarkablePageClass, null); + } + + /** + * Sessionless forms must have a bookmarkable page class. A bookmarkable + * page is defined as a page that has only a default and/or a PageParameter + * constructor. + * + * @param id + * @param bookmarkablePageClass + * @param pageParameters + */ + public SessionlessForm(String id, Class<? extends BasePage> bookmarkablePageClass, + PageParameters pageParameters) { + super(id); + this.pageClass = bookmarkablePageClass; + this.pageParameters = pageParameters; + } + + + /** + * Append an additional hidden input tag that forces Wicket to correctly + * determine the destination page class even after a session expiration or + * a server restart. + * + * @param markupStream + * The markup stream + * @param openTag + * The open tag for the body + */ + @Override + protected void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag) + { + // render the hidden bookmarkable page field + AppendingStringBuffer buffer = new AppendingStringBuffer(HIDDEN_DIV_START); + buffer.append("<input type=\"hidden\" name=\"") + .append(WebRequestCodingStrategy.BOOKMARKABLE_PAGE_PARAMETER_NAME) + .append("\" value=\":") + .append(pageClass.getName()) + .append("\" />"); + + // insert the page parameters, if any, as hidden fields as long as they + // do not collide with any child wicket:id of the form. + if (pageParameters != null) { + for (String key : pageParameters.keySet()) { + Component c = get(key); + if (c != null) { + // this form has a field id which matches the + // parameter name, skip embedding a hidden value + log.warn(MessageFormat.format("Skipping page parameter \"{0}\" from sessionless form hidden fields because it collides with a form child wicket:id", key)); + continue; + } + String value = pageParameters.getString(key); + buffer.append("<input type=\"hidden\" name=\"") + .append(recode(key)) + .append("\" value=\"") + .append(recode(value)) + .append("\" />"); + } + } + + buffer.append("</div>"); + getResponse().write(buffer); + super.onComponentTagBody(markupStream, openTag); + } + + /** + * Take URL-encoded query string value, unencode it and return HTML-escaped version + * + * @param s + * value to reencode + * @return reencoded value + */ + private String recode(String s) { + String un = WicketURLDecoder.QUERY_INSTANCE.decode(s); + return Strings.escapeMarkup(un).toString(); + } +} diff --git a/src/main/java/com/gitblit/wicket/StringChoiceRenderer.java b/src/main/java/com/gitblit/wicket/StringChoiceRenderer.java new file mode 100644 index 00000000..58ed4798 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/StringChoiceRenderer.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012 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; + +import org.apache.wicket.markup.html.form.ChoiceRenderer; + +/** + * Choice renderer for a palette or list of string values. This renderer + * controls the id value of each option such that palettes are case insensitive. + * + * @author James Moger + * + */ +public class StringChoiceRenderer extends ChoiceRenderer<String> { + + private static final long serialVersionUID = 1L; + + public StringChoiceRenderer() { + super("", ""); + } + + /** + * @see org.apache.wicket.markup.html.form.IChoiceRenderer#getIdValue(java.lang.Object, int) + */ + @Override + public String getIdValue(String object, int index) + { + return object.toLowerCase(); + } +} diff --git a/src/main/java/com/gitblit/wicket/WicketUtils.java b/src/main/java/com/gitblit/wicket/WicketUtils.java new file mode 100644 index 00000000..e4eb29fb --- /dev/null +++ b/src/main/java/com/gitblit/wicket/WicketUtils.java @@ -0,0 +1,601 @@ +/*
+ * Copyright 2011 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;
+
+import java.text.DateFormat;
+import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.Request;
+import org.apache.wicket.behavior.HeaderContributor;
+import org.apache.wicket.behavior.SimpleAttributeModifier;
+import org.apache.wicket.markup.html.IHeaderContributor;
+import org.apache.wicket.markup.html.IHeaderResponse;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.image.ContextImage;
+import org.apache.wicket.protocol.http.WebRequest;
+import org.apache.wicket.resource.ContextRelativeResource;
+import org.eclipse.jgit.diff.DiffEntry.ChangeType;
+import org.wicketstuff.googlecharts.AbstractChartData;
+import org.wicketstuff.googlecharts.IChartData;
+
+import com.gitblit.Constants;
+import com.gitblit.Constants.FederationPullStatus;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.FederationModel;
+import com.gitblit.models.Metric;
+import com.gitblit.utils.HttpUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.TimeUtils;
+
+public class WicketUtils {
+
+ public static void setCssClass(Component container, String value) {
+ container.add(new SimpleAttributeModifier("class", value));
+ }
+
+ public static void setCssStyle(Component container, String value) {
+ container.add(new SimpleAttributeModifier("style", value));
+ }
+
+ public static void setCssBackground(Component container, String value) {
+ String background = MessageFormat.format("background-color:{0};",
+ StringUtils.getColor(value));
+ container.add(new SimpleAttributeModifier("style", background));
+ }
+
+ public static void setHtmlTooltip(Component container, String value) {
+ container.add(new SimpleAttributeModifier("title", value));
+ }
+
+ public static void setInputPlaceholder(Component container, String value) {
+ container.add(new SimpleAttributeModifier("placeholder", value));
+ }
+
+ public static void setChangeTypeCssClass(Component container, ChangeType type) {
+ switch (type) {
+ case ADD:
+ setCssClass(container, "addition");
+ break;
+ case COPY:
+ case RENAME:
+ setCssClass(container, "rename");
+ break;
+ case DELETE:
+ setCssClass(container, "deletion");
+ break;
+ case MODIFY:
+ setCssClass(container, "modification");
+ break;
+ }
+ }
+
+ public static void setTicketCssClass(Component container, String state) {
+ String css = null;
+ if (state.equals("open")) {
+ css = "label label-important";
+ } else if (state.equals("hold")) {
+ css = "label label-warning";
+ } else if (state.equals("resolved")) {
+ css = "label label-success";
+ } else if (state.equals("invalid")) {
+ css = "label";
+ }
+ if (css != null) {
+ setCssClass(container, css);
+ }
+ }
+
+ public static void setAlternatingBackground(Component c, int i) {
+ String clazz = i % 2 == 0 ? "light" : "dark";
+ setCssClass(c, clazz);
+ }
+
+ public static Label createAuthorLabel(String wicketId, String author) {
+ Label label = new Label(wicketId, author);
+ WicketUtils.setHtmlTooltip(label, author);
+ return label;
+ }
+
+ public static ContextImage getPullStatusImage(String wicketId, FederationPullStatus status) {
+ String filename = null;
+ switch (status) {
+ case MIRRORED:
+ case PULLED:
+ filename = "bullet_green.png";
+ break;
+ case SKIPPED:
+ filename = "bullet_yellow.png";
+ break;
+ case FAILED:
+ filename = "bullet_red.png";
+ break;
+ case EXCLUDED:
+ filename = "bullet_white.png";
+ break;
+ case PENDING:
+ case NOCHANGE:
+ default:
+ filename = "bullet_black.png";
+ }
+ return WicketUtils.newImage(wicketId, filename, status.name());
+ }
+
+ public static ContextImage getFileImage(String wicketId, String filename) {
+ filename = filename.toLowerCase();
+ if (filename.endsWith(".java")) {
+ return newImage(wicketId, "file_java_16x16.png");
+ } else if (filename.endsWith(".rb")) {
+ return newImage(wicketId, "file_ruby_16x16.png");
+ } else if (filename.endsWith(".php")) {
+ return newImage(wicketId, "file_php_16x16.png");
+ } else if (filename.endsWith(".cs")) {
+ return newImage(wicketId, "file_cs_16x16.png");
+ } else if (filename.endsWith(".cpp")) {
+ return newImage(wicketId, "file_cpp_16x16.png");
+ } else if (filename.endsWith(".c")) {
+ return newImage(wicketId, "file_c_16x16.png");
+ } else if (filename.endsWith(".h")) {
+ return newImage(wicketId, "file_h_16x16.png");
+ } else if (filename.endsWith(".sln")) {
+ return newImage(wicketId, "file_vs_16x16.png");
+ } else if (filename.endsWith(".csv") || filename.endsWith(".xls")
+ || filename.endsWith(".xlsx")) {
+ return newImage(wicketId, "file_excel_16x16.png");
+ } else if (filename.endsWith(".doc") || filename.endsWith(".docx")) {
+ return newImage(wicketId, "file_word_16x16.png");
+ } else if (filename.endsWith(".ppt")) {
+ return newImage(wicketId, "file_ppt_16x16.png");
+ } else if (filename.endsWith(".zip")) {
+ return newImage(wicketId, "file_zip_16x16.png");
+ } else if (filename.endsWith(".pdf")) {
+ return newImage(wicketId, "file_acrobat_16x16.png");
+ } else if (filename.endsWith(".htm") || filename.endsWith(".html")) {
+ return newImage(wicketId, "file_world_16x16.png");
+ } else if (filename.endsWith(".xml")) {
+ return newImage(wicketId, "file_code_16x16.png");
+ } else if (filename.endsWith(".properties")) {
+ return newImage(wicketId, "file_settings_16x16.png");
+ }
+
+ List<String> mdExtensions = GitBlit.getStrings(Keys.web.markdownExtensions);
+ for (String ext : mdExtensions) {
+ if (filename.endsWith('.' + ext.toLowerCase())) {
+ return newImage(wicketId, "file_world_16x16.png");
+ }
+ }
+ return newImage(wicketId, "file_16x16.png");
+ }
+
+ public static ContextImage getRegistrationImage(String wicketId, FederationModel registration,
+ Component c) {
+ if (registration.isResultData()) {
+ return WicketUtils.newImage(wicketId, "information_16x16.png",
+ c.getString("gb.federationResults"));
+ } else {
+ return WicketUtils.newImage(wicketId, "arrow_left.png",
+ c.getString("gb.federationRegistration"));
+ }
+ }
+
+ public static ContextImage newClearPixel(String wicketId) {
+ return newImage(wicketId, "pixel.png");
+ }
+
+ public static ContextImage newBlankImage(String wicketId) {
+ return newImage(wicketId, "blank.png");
+ }
+
+ public static ContextImage newImage(String wicketId, String file) {
+ return newImage(wicketId, file, null);
+ }
+
+ public static ContextImage newImage(String wicketId, String file, String tooltip) {
+ ContextImage img = new ContextImage(wicketId, file);
+ if (!StringUtils.isEmpty(tooltip)) {
+ setHtmlTooltip(img, tooltip);
+ }
+ return img;
+ }
+
+ public static Label newIcon(String wicketId, String css) {
+ Label lbl = new Label(wicketId);
+ setCssClass(lbl, css);
+ return lbl;
+ }
+
+ public static Label newBlankIcon(String wicketId) {
+ Label lbl = new Label(wicketId);
+ setCssClass(lbl, "");
+ lbl.setRenderBodyOnly(true);
+ return lbl;
+ }
+
+ public static ContextRelativeResource getResource(String file) {
+ return new ContextRelativeResource(file);
+ }
+
+ public static String getGitblitURL(Request request) {
+ HttpServletRequest req = ((WebRequest) request).getHttpServletRequest();
+ return HttpUtils.getGitblitURL(req);
+ }
+
+ public static HeaderContributor syndicationDiscoveryLink(final String feedTitle,
+ final String url) {
+ return new HeaderContributor(new IHeaderContributor() {
+ private static final long serialVersionUID = 1L;
+
+ public void renderHead(IHeaderResponse response) {
+ String contentType = "application/rss+xml";
+
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("<link rel=\"alternate\" ");
+ buffer.append("type=\"").append(contentType).append("\" ");
+ buffer.append("title=\"").append(feedTitle).append("\" ");
+ buffer.append("href=\"").append(url).append("\" />");
+ response.renderString(buffer.toString());
+ }
+ });
+ }
+
+ public static PageParameters newTokenParameter(String token) {
+ return new PageParameters("t=" + token);
+ }
+
+ public static PageParameters newRegistrationParameter(String url, String name) {
+ return new PageParameters("u=" + url + ",n=" + name);
+ }
+
+ public static PageParameters newUsernameParameter(String username) {
+ return new PageParameters("user=" + username);
+ }
+
+ public static PageParameters newTeamnameParameter(String teamname) {
+ return new PageParameters("team=" + teamname);
+ }
+
+ public static PageParameters newProjectParameter(String projectName) {
+ return new PageParameters("p=" + projectName);
+ }
+
+ public static PageParameters newRepositoryParameter(String repositoryName) {
+ return new PageParameters("r=" + repositoryName);
+ }
+
+ public static PageParameters newObjectParameter(String objectId) {
+ return new PageParameters("h=" + objectId);
+ }
+
+ public static PageParameters newObjectParameter(String repositoryName, String objectId) {
+ if (StringUtils.isEmpty(objectId)) {
+ return newRepositoryParameter(repositoryName);
+ }
+ return new PageParameters("r=" + repositoryName + ",h=" + objectId);
+ }
+
+ public static PageParameters newPathParameter(String repositoryName, String objectId,
+ String path) {
+ if (StringUtils.isEmpty(path)) {
+ return newObjectParameter(repositoryName, objectId);
+ }
+ if (StringUtils.isEmpty(objectId)) {
+ return new PageParameters("r=" + repositoryName + ",f=" + path);
+ }
+ return new PageParameters("r=" + repositoryName + ",h=" + objectId + ",f=" + path);
+ }
+
+ public static PageParameters newLogPageParameter(String repositoryName, String objectId,
+ int pageNumber) {
+ if (pageNumber <= 1) {
+ return newObjectParameter(repositoryName, objectId);
+ }
+ if (StringUtils.isEmpty(objectId)) {
+ return new PageParameters("r=" + repositoryName + ",pg=" + pageNumber);
+ }
+ return new PageParameters("r=" + repositoryName + ",h=" + objectId + ",pg=" + pageNumber);
+ }
+
+ public static PageParameters newHistoryPageParameter(String repositoryName, String objectId,
+ String path, int pageNumber) {
+ if (pageNumber <= 1) {
+ return newObjectParameter(repositoryName, objectId);
+ }
+ if (StringUtils.isEmpty(objectId)) {
+ return new PageParameters("r=" + repositoryName + ",f=" + path + ",pg=" + pageNumber);
+ }
+ return new PageParameters("r=" + repositoryName + ",h=" + objectId + ",f=" + path + ",pg="
+ + pageNumber);
+ }
+
+ public static PageParameters newBlobDiffParameter(String repositoryName, String baseCommitId,
+ String commitId, String path) {
+ if (StringUtils.isEmpty(commitId)) {
+ return new PageParameters("r=" + repositoryName + ",f=" + path + ",hb=" + baseCommitId);
+ }
+ return new PageParameters("r=" + repositoryName + ",h=" + commitId + ",f=" + path + ",hb="
+ + baseCommitId);
+ }
+
+ public static PageParameters newSearchParameter(String repositoryName, String commitId,
+ String search, Constants.SearchType type) {
+ if (StringUtils.isEmpty(commitId)) {
+ return new PageParameters("r=" + repositoryName + ",s=" + search + ",st=" + type.name());
+ }
+ return new PageParameters("r=" + repositoryName + ",h=" + commitId + ",s=" + search
+ + ",st=" + type.name());
+ }
+
+ public static PageParameters newSearchParameter(String repositoryName, String commitId,
+ String search, Constants.SearchType type, int pageNumber) {
+ if (StringUtils.isEmpty(commitId)) {
+ return new PageParameters("r=" + repositoryName + ",s=" + search + ",st=" + type.name()
+ + ",pg=" + pageNumber);
+ }
+ return new PageParameters("r=" + repositoryName + ",h=" + commitId + ",s=" + search
+ + ",st=" + type.name() + ",pg=" + pageNumber);
+ }
+
+ public static String getProjectName(PageParameters params) {
+ return params.getString("p", "");
+ }
+
+ public static String getRepositoryName(PageParameters params) {
+ return params.getString("r", "");
+ }
+
+ public static String getObject(PageParameters params) {
+ return params.getString("h", null);
+ }
+
+ public static String getPath(PageParameters params) {
+ return params.getString("f", null);
+ }
+
+ public static String getBaseObjectId(PageParameters params) {
+ return params.getString("hb", null);
+ }
+
+ public static String getSearchString(PageParameters params) {
+ return params.getString("s", null);
+ }
+
+ public static String getSearchType(PageParameters params) {
+ return params.getString("st", null);
+ }
+
+ public static int getPage(PageParameters params) {
+ // index from 1
+ return params.getInt("pg", 1);
+ }
+
+ public static String getRegEx(PageParameters params) {
+ return params.getString("x", "");
+ }
+
+ public static String getSet(PageParameters params) {
+ return params.getString("set", "");
+ }
+
+ public static String getTeam(PageParameters params) {
+ return params.getString("team", "");
+ }
+
+ public static int getDaysBack(PageParameters params) {
+ return params.getInt("db", 14);
+ }
+
+ public static String getUsername(PageParameters params) {
+ return params.getString("user", "");
+ }
+
+ public static String getTeamname(PageParameters params) {
+ return params.getString("team", "");
+ }
+
+ public static String getToken(PageParameters params) {
+ return params.getString("t", "");
+ }
+
+ public static String getUrlParameter(PageParameters params) {
+ return params.getString("u", "");
+ }
+
+ public static String getNameParameter(PageParameters params) {
+ return params.getString("n", "");
+ }
+
+ public static Label createDateLabel(String wicketId, Date date, TimeZone timeZone, TimeUtils timeUtils) {
+ String format = GitBlit.getString(Keys.web.datestampShortFormat, "MM/dd/yy");
+ DateFormat df = new SimpleDateFormat(format);
+ if (timeZone == null) {
+ timeZone = GitBlit.getTimezone();
+ }
+ df.setTimeZone(timeZone);
+ String dateString;
+ if (date.getTime() == 0) {
+ dateString = "--";
+ } else {
+ dateString = df.format(date);
+ }
+ String title = null;
+ if (date.getTime() <= System.currentTimeMillis()) {
+ // past
+ title = timeUtils.timeAgo(date);
+ }
+ if ((System.currentTimeMillis() - date.getTime()) < 10 * 24 * 60 * 60 * 1000L) {
+ String tmp = dateString;
+ dateString = title;
+ title = tmp;
+ }
+ Label label = new Label(wicketId, dateString);
+ WicketUtils.setCssClass(label, timeUtils.timeAgoCss(date));
+ if (!StringUtils.isEmpty(title)) {
+ WicketUtils.setHtmlTooltip(label, title);
+ }
+ return label;
+ }
+
+ public static Label createTimeLabel(String wicketId, Date date, TimeZone timeZone, TimeUtils timeUtils) {
+ String format = GitBlit.getString(Keys.web.timeFormat, "HH:mm");
+ DateFormat df = new SimpleDateFormat(format);
+ if (timeZone == null) {
+ timeZone = GitBlit.getTimezone();
+ }
+ df.setTimeZone(timeZone);
+ String timeString;
+ if (date.getTime() == 0) {
+ timeString = "--";
+ } else {
+ timeString = df.format(date);
+ }
+ String title = timeUtils.timeAgo(date);
+ Label label = new Label(wicketId, timeString);
+ if (!StringUtils.isEmpty(title)) {
+ WicketUtils.setHtmlTooltip(label, title);
+ }
+ return label;
+ }
+
+ public static Label createDatestampLabel(String wicketId, Date date, TimeZone timeZone, TimeUtils timeUtils) {
+ String format = GitBlit.getString(Keys.web.datestampLongFormat, "EEEE, MMMM d, yyyy");
+ DateFormat df = new SimpleDateFormat(format);
+ if (timeZone == null) {
+ timeZone = GitBlit.getTimezone();
+ }
+ df.setTimeZone(timeZone);
+ String dateString;
+ if (date.getTime() == 0) {
+ dateString = "--";
+ } else {
+ dateString = df.format(date);
+ }
+ String title = null;
+ if (TimeUtils.isToday(date)) {
+ title = timeUtils.today();
+ } else if (TimeUtils.isYesterday(date)) {
+ title = timeUtils.yesterday();
+ } else if (date.getTime() <= System.currentTimeMillis()) {
+ // past
+ title = timeUtils.timeAgo(date);
+ }
+ if ((System.currentTimeMillis() - date.getTime()) < 10 * 24 * 60 * 60 * 1000L) {
+ String tmp = dateString;
+ dateString = title;
+ title = tmp;
+ }
+ Label label = new Label(wicketId, dateString);
+ if (!StringUtils.isEmpty(title)) {
+ WicketUtils.setHtmlTooltip(label, title);
+ }
+ return label;
+ }
+
+ public static Label createTimestampLabel(String wicketId, Date date, TimeZone timeZone, TimeUtils timeUtils) {
+ String format = GitBlit.getString(Keys.web.datetimestampLongFormat,
+ "EEEE, MMMM d, yyyy HH:mm Z");
+ DateFormat df = new SimpleDateFormat(format);
+ if (timeZone == null) {
+ timeZone = GitBlit.getTimezone();
+ }
+ df.setTimeZone(timeZone);
+ String dateString;
+ if (date.getTime() == 0) {
+ dateString = "--";
+ } else {
+ dateString = df.format(date);
+ }
+ String title = null;
+ if (date.getTime() <= System.currentTimeMillis()) {
+ // past
+ title = timeUtils.timeAgo(date);
+ }
+ Label label = new Label(wicketId, dateString);
+ if (!StringUtils.isEmpty(title)) {
+ WicketUtils.setHtmlTooltip(label, title);
+ }
+ return label;
+ }
+
+ public static IChartData getChartData(Collection<Metric> metrics) {
+ final double[] commits = new double[metrics.size()];
+ final double[] tags = new double[metrics.size()];
+ int i = 0;
+ double max = 0;
+ for (Metric m : metrics) {
+ commits[i] = m.count;
+ if (m.tag > 0) {
+ tags[i] = m.count;
+ } else {
+ tags[i] = -1d;
+ }
+ max = Math.max(max, m.count);
+ i++;
+ }
+ IChartData data = new AbstractChartData(max) {
+ private static final long serialVersionUID = 1L;
+
+ public double[][] getData() {
+ return new double[][] { commits, tags };
+ }
+ };
+ return data;
+ }
+
+ public static double maxValue(Collection<Metric> metrics) {
+ double max = Double.MIN_VALUE;
+ for (Metric m : metrics) {
+ if (m.count > max) {
+ max = m.count;
+ }
+ }
+ return max;
+ }
+
+ public static IChartData getScatterData(Collection<Metric> metrics) {
+ final double[] y = new double[metrics.size()];
+ final double[] x = new double[metrics.size()];
+ int i = 0;
+ double max = 0;
+ for (Metric m : metrics) {
+ y[i] = m.count;
+ if (m.duration > 0) {
+ x[i] = m.duration;
+ } else {
+ x[i] = -1d;
+ }
+ max = Math.max(max, m.count);
+ i++;
+ }
+ IChartData data = new AbstractChartData(max) {
+ private static final long serialVersionUID = 1L;
+
+ public double[][] getData() {
+ return new double[][] { x, y };
+ }
+ };
+ return data;
+ }
+
+}
diff --git a/src/main/java/com/gitblit/wicket/charting/GoogleChart.java b/src/main/java/com/gitblit/wicket/charting/GoogleChart.java new file mode 100644 index 00000000..b6309ffe --- /dev/null +++ b/src/main/java/com/gitblit/wicket/charting/GoogleChart.java @@ -0,0 +1,101 @@ +/*
+ * Copyright 2011 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.charting;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.gitblit.utils.StringUtils;
+
+/**
+ * Abstract parent class for Google Charts built with the Visualization API.
+ *
+ * @author James Moger
+ *
+ */
+public abstract class GoogleChart implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ final String tagId;
+ final String dataName;
+ final String title;
+ final String keyName;
+ final String valueName;
+ final List<ChartValue> values;
+ int width;
+ int height;
+
+ public GoogleChart(String tagId, String title, String keyName, String valueName) {
+ this.tagId = tagId;
+ this.dataName = StringUtils.getSHA1(title).substring(0, 8);
+ this.title = title;
+ this.keyName = keyName;
+ this.valueName = valueName;
+ values = new ArrayList<ChartValue>();
+ }
+
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ public void addValue(String name, int value) {
+ values.add(new ChartValue(name, value));
+ }
+
+ public void addValue(String name, float value) {
+ values.add(new ChartValue(name, value));
+ }
+
+ public void addValue(String name, double value) {
+ values.add(new ChartValue(name, (float) value));
+ }
+
+ protected abstract void appendChart(StringBuilder sb);
+
+ protected void line(StringBuilder sb, String line) {
+ sb.append(line);
+ sb.append('\n');
+ }
+
+ protected class ChartValue implements Serializable, Comparable<ChartValue> {
+
+ private static final long serialVersionUID = 1L;
+
+ final String name;
+ final float value;
+
+ ChartValue(String name, float value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ @Override
+ public int compareTo(ChartValue o) {
+ // sorts the dataset by largest value first
+ if (value > o.value) {
+ return -1;
+ } else if (value < o.value) {
+ return 1;
+ }
+ return 0;
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/charting/GoogleCharts.java b/src/main/java/com/gitblit/wicket/charting/GoogleCharts.java new file mode 100644 index 00000000..77c522b5 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/charting/GoogleCharts.java @@ -0,0 +1,68 @@ +/*
+ Copyright 2011 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.charting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.markup.html.IHeaderContributor;
+import org.apache.wicket.markup.html.IHeaderResponse;
+
+/**
+ * The Google Visualization API provides interactive JavaScript based charts and
+ * graphs. This class implements the JavaScript header necessary to display
+ * complete graphs and charts.
+ *
+ * @author James Moger
+ *
+ */
+public class GoogleCharts implements IHeaderContributor {
+
+ private static final long serialVersionUID = 1L;
+
+ public final List<GoogleChart> charts = new ArrayList<GoogleChart>();
+
+ public void addChart(GoogleChart chart) {
+ charts.add(chart);
+ }
+
+ @Override
+ public void renderHead(IHeaderResponse response) {
+ // add Google Chart JS API reference
+ response.renderJavascriptReference("https://www.google.com/jsapi");
+
+ // prepare draw chart function
+ StringBuilder sb = new StringBuilder();
+ line(sb, "google.load(\"visualization\", \"1\", {packages:[\"corechart\"]});");
+ line(sb, "google.setOnLoadCallback(drawChart);");
+ line(sb, "function drawChart() {");
+
+ // add charts to header
+ for (GoogleChart chart : charts) {
+ chart.appendChart(sb);
+ }
+
+ // end draw chart function
+ line(sb, "}");
+ response.renderJavascript(sb.toString(), null);
+ }
+
+ private void line(StringBuilder sb, String line) {
+ sb.append(line);
+ sb.append('\n');
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/charting/GoogleLineChart.java b/src/main/java/com/gitblit/wicket/charting/GoogleLineChart.java new file mode 100644 index 00000000..fc0bf837 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/charting/GoogleLineChart.java @@ -0,0 +1,60 @@ +/*
+ * Copyright 2011 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.charting;
+
+import java.text.MessageFormat;
+
+/**
+ * Builds an interactive line chart using the Visualization API.
+ *
+ * @author James Moger
+ *
+ */
+public class GoogleLineChart extends GoogleChart {
+
+ private static final long serialVersionUID = 1L;
+
+ public GoogleLineChart(String tagId, String title, String keyName, String valueName) {
+ super(tagId, title, keyName, valueName);
+ }
+
+ @Override
+ protected void appendChart(StringBuilder sb) {
+ String dName = "data_" + dataName;
+ line(sb, MessageFormat.format("var {0} = new google.visualization.DataTable();", dName));
+ line(sb, MessageFormat.format("{0}.addColumn(''string'', ''{1}'');", dName, keyName));
+ line(sb, MessageFormat.format("{0}.addColumn(''number'', ''{1}'');", dName, valueName));
+ line(sb, MessageFormat.format("{0}.addRows({1,number,0});", dName, values.size()));
+
+ for (int i = 0; i < values.size(); i++) {
+ ChartValue value = values.get(i);
+ line(sb, MessageFormat.format("{0}.setValue({1,number,0}, 0, ''{2}'');", dName, i,
+ value.name));
+ line(sb, MessageFormat.format("{0}.setValue({1,number,0}, 1, {2,number,0.0});", dName,
+ i, value.value));
+ }
+
+ String cName = "chart_" + dataName;
+ line(sb, MessageFormat.format(
+ "var {0} = new google.visualization.LineChart(document.getElementById(''{1}''));",
+ cName, tagId));
+ line(sb,
+ MessageFormat
+ .format("{0}.draw({1}, '{'width: {2,number,0}, height: {3,number,0}, pointSize: 4, chartArea:'{'left:20,top:20'}', vAxis: '{' textPosition: ''none'' '}', legend: ''none'', title: ''{4}'' '}');",
+ cName, dName, width, height, title));
+ line(sb, "");
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java b/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java new file mode 100644 index 00000000..119a8248 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java @@ -0,0 +1,75 @@ +/*
+ * Copyright 2011 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.charting;
+
+import java.text.MessageFormat;
+import java.util.Collections;
+
+import com.gitblit.utils.StringUtils;
+
+/**
+ * Builds an interactive pie chart using the Visualization API.
+ *
+ * @author James Moger
+ *
+ */
+public class GooglePieChart extends GoogleChart {
+
+ private static final long serialVersionUID = 1L;
+
+ public GooglePieChart(String tagId, String title, String keyName, String valueName) {
+ super(tagId, title, keyName, valueName);
+ }
+
+ @Override
+ protected void appendChart(StringBuilder sb) {
+ // create dataset
+ String dName = "data_" + dataName;
+ line(sb, MessageFormat.format("var {0} = new google.visualization.DataTable();", dName));
+ line(sb, MessageFormat.format("{0}.addColumn(''string'', ''{1}'');", dName, keyName));
+ line(sb, MessageFormat.format("{0}.addColumn(''number'', ''{1}'');", dName, valueName));
+ line(sb, MessageFormat.format("{0}.addRows({1,number,0});", dName, values.size()));
+
+ Collections.sort(values);
+
+ StringBuilder colors = new StringBuilder("colors:[");
+ for (int i = 0; i < values.size(); i++) {
+ ChartValue value = values.get(i);
+ colors.append('\'');
+ colors.append(StringUtils.getColor(value.name));
+ colors.append('\'');
+ if (i < values.size() - 1) {
+ colors.append(',');
+ }
+ line(sb, MessageFormat.format("{0}.setValue({1,number,0}, 0, ''{2}'');", dName, i,
+ value.name));
+ line(sb, MessageFormat.format("{0}.setValue({1,number,0}, 1, {2,number,0.0});", dName,
+ i, value.value));
+ }
+ colors.append(']');
+
+ // instantiate chart
+ String cName = "chart_" + dataName;
+ line(sb, MessageFormat.format(
+ "var {0} = new google.visualization.PieChart(document.getElementById(''{1}''));",
+ cName, tagId));
+ line(sb,
+ MessageFormat
+ .format("{0}.draw({1}, '{'width: {2,number,0}, height: {3,number,0}, chartArea:'{'left:20,top:20'}', title: ''{4}'', {5} '}');",
+ cName, dName, width, height, title, colors.toString()));
+ line(sb, "");
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/ActivityPage.html b/src/main/java/com/gitblit/wicket/pages/ActivityPage.html new file mode 100644 index 00000000..4b10c2cf --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ActivityPage.html @@ -0,0 +1,23 @@ +<!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:extend>
+ <div class="pageTitle">
+ <h2><wicket:message key="gb.recentActivity"></wicket:message><small> <span class="hidden-phone">/ <span wicket:id="subheader">[days back]</span></span></small></h2>
+ </div>
+ <div class="hidden-phone" style="height: 155px;text-align: center;">
+ <table>
+ <tr>
+ <td><span class="hidden-tablet" id="chartDaily"></span></td>
+ <td><span id="chartRepositories"></span></td>
+ <td><span id="chartAuthors"></span></td>
+ </tr>
+ </table>
+ </div>
+ <div wicket:id="activityPanel" style="padding-top:5px;" >[activity panel]</div>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/ActivityPage.java b/src/main/java/com/gitblit/wicket/pages/ActivityPage.java new file mode 100644 index 00000000..bceac8f4 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ActivityPage.java @@ -0,0 +1,207 @@ +/*
+ * Copyright 2011 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.text.MessageFormat;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.behavior.HeaderContributor;
+import org.apache.wicket.markup.html.basic.Label;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.Activity;
+import com.gitblit.models.Metric;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.utils.ActivityUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.PageRegistration;
+import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
+import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.charting.GoogleChart;
+import com.gitblit.wicket.charting.GoogleCharts;
+import com.gitblit.wicket.charting.GoogleLineChart;
+import com.gitblit.wicket.charting.GooglePieChart;
+import com.gitblit.wicket.panels.ActivityPanel;
+
+/**
+ * Activity Page shows a list of recent commits across all visible Gitblit
+ * repositories.
+ *
+ * @author James Moger
+ *
+ */
+public class ActivityPage extends RootPage {
+
+ public ActivityPage(PageParameters params) {
+ super(params);
+ setupPage("", "");
+
+ // parameters
+ int daysBack = WicketUtils.getDaysBack(params);
+ if (daysBack < 1) {
+ daysBack = 14;
+ }
+ String objectId = WicketUtils.getObject(params);
+
+ // determine repositories to view and retrieve the activity
+ List<RepositoryModel> models = getRepositories(params);
+ List<Activity> recentActivity = ActivityUtils.getRecentActivity(models,
+ daysBack, objectId, getTimeZone());
+
+ if (recentActivity.size() == 0) {
+ // no activity, skip graphs and activity panel
+ add(new Label("subheader", MessageFormat.format(getString("gb.recentActivityNone"),
+ daysBack)));
+ add(new Label("activityPanel"));
+ } else {
+ // calculate total commits and total authors
+ int totalCommits = 0;
+ Set<String> uniqueAuthors = new HashSet<String>();
+ for (Activity activity : recentActivity) {
+ totalCommits += activity.getCommitCount();
+ uniqueAuthors.addAll(activity.getAuthorMetrics().keySet());
+ }
+ int totalAuthors = uniqueAuthors.size();
+
+ // add the subheader with stat numbers
+ add(new Label("subheader", MessageFormat.format(getString("gb.recentActivityStats"),
+ daysBack, totalCommits, totalAuthors)));
+
+ // create the activity charts
+ GoogleCharts charts = createCharts(recentActivity);
+ add(new HeaderContributor(charts));
+
+ // add activity panel
+ add(new ActivityPanel("activityPanel", recentActivity));
+ }
+ }
+
+ @Override
+ protected boolean reusePageParameters() {
+ return true;
+ }
+
+ @Override
+ protected void addDropDownMenus(List<PageRegistration> pages) {
+ DropDownMenuRegistration filters = new DropDownMenuRegistration("gb.filters",
+ ActivityPage.class);
+
+ PageParameters currentParameters = getPageParameters();
+ int daysBack = GitBlit.getInteger(Keys.web.activityDuration, 14);
+ if (currentParameters != null && !currentParameters.containsKey("db")) {
+ currentParameters.put("db", daysBack);
+ }
+
+ // preserve time filter options on repository choices
+ filters.menuItems.addAll(getRepositoryFilterItems(currentParameters));
+
+ // preserve repository filter options on time choices
+ filters.menuItems.addAll(getTimeFilterItems(currentParameters));
+
+ if (filters.menuItems.size() > 0) {
+ // Reset Filter
+ filters.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null));
+ }
+ pages.add(filters);
+ }
+
+ /**
+ * Creates the daily activity line chart, the active repositories pie chart,
+ * and the active authors pie chart
+ *
+ * @param recentActivity
+ * @return
+ */
+ private GoogleCharts createCharts(List<Activity> recentActivity) {
+ // activity metrics
+ Map<String, Metric> repositoryMetrics = new HashMap<String, Metric>();
+ Map<String, Metric> authorMetrics = new HashMap<String, Metric>();
+
+ // aggregate repository and author metrics
+ for (Activity activity : recentActivity) {
+
+ // aggregate author metrics
+ for (Map.Entry<String, Metric> entry : activity.getAuthorMetrics().entrySet()) {
+ String author = entry.getKey();
+ if (!authorMetrics.containsKey(author)) {
+ authorMetrics.put(author, new Metric(author));
+ }
+ authorMetrics.get(author).count += entry.getValue().count;
+ }
+
+ // aggregate repository metrics
+ for (Map.Entry<String, Metric> entry : activity.getRepositoryMetrics().entrySet()) {
+ String repository = StringUtils.stripDotGit(entry.getKey());
+ if (!repositoryMetrics.containsKey(repository)) {
+ repositoryMetrics.put(repository, new Metric(repository));
+ }
+ repositoryMetrics.get(repository).count += entry.getValue().count;
+ }
+ }
+
+ // build google charts
+ int w = 310;
+ int h = 150;
+ GoogleCharts charts = new GoogleCharts();
+
+ // sort in reverse-chronological order and then reverse that
+ Collections.sort(recentActivity);
+ Collections.reverse(recentActivity);
+
+ // daily line chart
+ GoogleChart chart = new GoogleLineChart("chartDaily", getString("gb.dailyActivity"), "day",
+ getString("gb.commits"));
+ SimpleDateFormat df = new SimpleDateFormat("MMM dd");
+ df.setTimeZone(getTimeZone());
+ for (Activity metric : recentActivity) {
+ chart.addValue(df.format(metric.startDate), metric.getCommitCount());
+ }
+ chart.setWidth(w);
+ chart.setHeight(h);
+ charts.addChart(chart);
+
+ // active repositories pie chart
+ chart = new GooglePieChart("chartRepositories", getString("gb.activeRepositories"),
+ getString("gb.repository"), getString("gb.commits"));
+ for (Metric metric : repositoryMetrics.values()) {
+ chart.addValue(metric.name, metric.count);
+ }
+ chart.setWidth(w);
+ chart.setHeight(h);
+ charts.addChart(chart);
+
+ // active authors pie chart
+ chart = new GooglePieChart("chartAuthors", getString("gb.activeAuthors"),
+ getString("gb.author"), getString("gb.commits"));
+ for (Metric metric : authorMetrics.values()) {
+ chart.addValue(metric.name, metric.count);
+ }
+ chart.setWidth(w);
+ chart.setHeight(h);
+ charts.addChart(chart);
+
+ return charts;
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/BasePage.html b/src/main/java/com/gitblit/wicket/pages/BasePage.html new file mode 100644 index 00000000..4a642e73 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/BasePage.html @@ -0,0 +1,62 @@ +<!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">
+
+ <!-- Head -->
+ <wicket:head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title wicket:id="title">[page title]</title>
+ <link rel="icon" href="gitblt-favicon.png" type="image/png" />
+
+ <link rel="stylesheet" href="bootstrap/css/bootstrap.css"/>
+ <link rel="stylesheet" type="text/css" href="gitblit.css"/>
+ </wicket:head>
+
+ <body>
+
+ <!-- page content -->
+ <wicket:child />
+
+ <!-- page footer -->
+ <div class="container">
+ <footer class="footer">
+ <p class="pull-right">
+ <a title="gitblit homepage" href="http://gitblit.com/">
+ <span wicket:id="gbVersion"></span>
+ </a>
+ </p>
+ <div wicket:id="userPanel">[user panel]</div>
+ </footer>
+ </div>
+
+ <!-- Override Bootstrap's responsive menu background highlighting -->
+ <style>
+ @media (max-width: 979px) {
+ .nav-collapse .nav > li > a:hover, .nav-collapse .dropdown-menu a:hover {
+ background-color: #000070;
+ }
+
+ .navbar div > ul .dropdown-menu li a {
+ color: #ccc;
+ }
+ }
+ </style>
+
+ <!-- Include scripts at end for faster page loading -->
+ <script type="text/javascript" src="bootstrap/js/jquery.js"></script>
+ <script type="text/javascript" src="bootstrap/js/bootstrap.js"></script>
+ </body>
+
+ <!-- user fragment -->
+ <wicket:fragment wicket:id="userFragment">
+ <span class="userPanel" wicket:id="username"></span>
+ <span class="userPanel" wicket:id="loginLink"></span>
+ <span class="hidden-phone">
+ <span class="userPanel" wicket:id="separator"></span>
+ <span class="userPanel"><a wicket:id="changePasswordLink"><wicket:message key="gb.changePassword"></wicket:message></a></span>
+ </span>
+ </wicket:fragment>
+
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/BasePage.java b/src/main/java/com/gitblit/wicket/pages/BasePage.java new file mode 100644 index 00000000..5c73df33 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/BasePage.java @@ -0,0 +1,460 @@ +/*
+ * Copyright 2011 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.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.regex.Pattern;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.RedirectToUrlException;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.RestartResponseException;
+import org.apache.wicket.markup.html.CSSPackageResource;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.link.ExternalLink;
+import org.apache.wicket.markup.html.panel.FeedbackPanel;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.protocol.http.RequestUtils;
+import org.apache.wicket.protocol.http.WebRequest;
+import org.apache.wicket.protocol.http.WebResponse;
+import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.Constants;
+import com.gitblit.Constants.AccessPermission;
+import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.Constants.AuthorizationControl;
+import com.gitblit.Constants.FederationStrategy;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.ProjectModel;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.TeamModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.TimeUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.LinkPanel;
+
+public abstract class BasePage extends WebPage {
+
+ private final Logger logger;
+
+ private transient TimeUtils timeUtils;
+
+ public BasePage() {
+ super();
+ logger = LoggerFactory.getLogger(getClass());
+ customizeHeader();
+ login();
+ }
+
+ public BasePage(PageParameters params) {
+ super(params);
+ logger = LoggerFactory.getLogger(getClass());
+ customizeHeader();
+ login();
+ }
+
+ private void customizeHeader() {
+ if (GitBlit.getBoolean(Keys.web.useResponsiveLayout, true)) {
+ add(CSSPackageResource.getHeaderContribution("bootstrap/css/bootstrap-responsive.css"));
+ }
+ }
+
+ protected String getLanguageCode() {
+ return GitBlitWebSession.get().getLocale().getLanguage();
+ }
+
+ protected String getCountryCode() {
+ return GitBlitWebSession.get().getLocale().getCountry().toLowerCase();
+ }
+
+ protected TimeUtils getTimeUtils() {
+ if (timeUtils == null) {
+ ResourceBundle bundle;
+ try {
+ bundle = ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp", GitBlitWebSession.get().getLocale());
+ } catch (Throwable t) {
+ bundle = ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp");
+ }
+ timeUtils = new TimeUtils(bundle);
+ }
+ return timeUtils;
+ }
+
+ @Override
+ protected void onBeforeRender() {
+ if (GitBlit.isDebugMode()) {
+ // strip Wicket tags in debug mode for jQuery DOM traversal
+ Application.get().getMarkupSettings().setStripWicketTags(true);
+ }
+ super.onBeforeRender();
+ }
+
+ @Override
+ protected void onAfterRender() {
+ if (GitBlit.isDebugMode()) {
+ // restore Wicket debug tags
+ Application.get().getMarkupSettings().setStripWicketTags(false);
+ }
+ super.onAfterRender();
+ }
+
+ private void login() {
+ GitBlitWebSession session = GitBlitWebSession.get();
+ if (session.isLoggedIn() && !session.isSessionInvalidated()) {
+ // already have a session, refresh usermodel to pick up
+ // any changes to permissions or roles (issue-186)
+ UserModel user = GitBlit.self().getUserModel(session.getUser().username);
+ session.setUser(user);
+ return;
+ }
+
+ // try to authenticate by servlet request
+ HttpServletRequest httpRequest = ((WebRequest) getRequestCycle().getRequest()).getHttpServletRequest();
+ UserModel user = GitBlit.self().authenticate(httpRequest);
+
+ // Login the user
+ if (user != null) {
+ // issue 62: fix session fixation vulnerability
+ session.replaceSession();
+ session.setUser(user);
+
+ // Set Cookie
+ WebResponse response = (WebResponse) getRequestCycle().getResponse();
+ GitBlit.self().setCookie(response, user);
+
+ session.continueRequest();
+ }
+ }
+
+ protected void setupPage(String repositoryName, String pageName) {
+ if (repositoryName != null && repositoryName.trim().length() > 0) {
+ add(new Label("title", getServerName() + " - " + repositoryName));
+ } else {
+ add(new Label("title", getServerName()));
+ }
+
+ ExternalLink rootLink = new ExternalLink("rootLink", urlFor(RepositoriesPage.class, null).toString());
+ WicketUtils.setHtmlTooltip(rootLink, GitBlit.getString(Keys.web.siteName, Constants.NAME));
+ add(rootLink);
+
+ // Feedback panel for info, warning, and non-fatal error messages
+ add(new FeedbackPanel("feedback"));
+
+ // footer
+ if (GitBlit.getBoolean(Keys.web.authenticateViewPages, true)
+ || GitBlit.getBoolean(Keys.web.authenticateAdminPages, true)) {
+ UserFragment userFragment = new UserFragment("userPanel", "userFragment", BasePage.this);
+ add(userFragment);
+ } else {
+ add(new Label("userPanel", ""));
+ }
+
+ add(new Label("gbVersion", "v" + Constants.getVersion()));
+ if (GitBlit.getBoolean(Keys.web.aggressiveHeapManagement, false)) {
+ System.gc();
+ }
+ }
+
+ protected Map<AccessRestrictionType, String> getAccessRestrictions() {
+ Map<AccessRestrictionType, String> map = new LinkedHashMap<AccessRestrictionType, String>();
+ for (AccessRestrictionType type : AccessRestrictionType.values()) {
+ switch (type) {
+ case NONE:
+ map.put(type, getString("gb.notRestricted"));
+ break;
+ case PUSH:
+ map.put(type, getString("gb.pushRestricted"));
+ break;
+ case CLONE:
+ map.put(type, getString("gb.cloneRestricted"));
+ break;
+ case VIEW:
+ map.put(type, getString("gb.viewRestricted"));
+ break;
+ }
+ }
+ return map;
+ }
+
+ protected Map<AccessPermission, String> getAccessPermissions() {
+ Map<AccessPermission, String> map = new LinkedHashMap<AccessPermission, String>();
+ for (AccessPermission type : AccessPermission.values()) {
+ switch (type) {
+ case NONE:
+ map.put(type, MessageFormat.format(getString("gb.noPermission"), type.code));
+ break;
+ case EXCLUDE:
+ map.put(type, MessageFormat.format(getString("gb.excludePermission"), type.code));
+ break;
+ case VIEW:
+ map.put(type, MessageFormat.format(getString("gb.viewPermission"), type.code));
+ break;
+ case CLONE:
+ map.put(type, MessageFormat.format(getString("gb.clonePermission"), type.code));
+ break;
+ case PUSH:
+ map.put(type, MessageFormat.format(getString("gb.pushPermission"), type.code));
+ break;
+ case CREATE:
+ map.put(type, MessageFormat.format(getString("gb.createPermission"), type.code));
+ break;
+ case DELETE:
+ map.put(type, MessageFormat.format(getString("gb.deletePermission"), type.code));
+ break;
+ case REWIND:
+ map.put(type, MessageFormat.format(getString("gb.rewindPermission"), type.code));
+ break;
+ }
+ }
+ return map;
+ }
+
+ protected Map<FederationStrategy, String> getFederationTypes() {
+ Map<FederationStrategy, String> map = new LinkedHashMap<FederationStrategy, String>();
+ for (FederationStrategy type : FederationStrategy.values()) {
+ switch (type) {
+ case EXCLUDE:
+ map.put(type, getString("gb.excludeFromFederation"));
+ break;
+ case FEDERATE_THIS:
+ map.put(type, getString("gb.federateThis"));
+ break;
+ case FEDERATE_ORIGIN:
+ map.put(type, getString("gb.federateOrigin"));
+ break;
+ }
+ }
+ return map;
+ }
+
+ protected Map<AuthorizationControl, String> getAuthorizationControls() {
+ Map<AuthorizationControl, String> map = new LinkedHashMap<AuthorizationControl, String>();
+ for (AuthorizationControl type : AuthorizationControl.values()) {
+ switch (type) {
+ case AUTHENTICATED:
+ map.put(type, getString("gb.allowAuthenticatedDescription"));
+ break;
+ case NAMED:
+ map.put(type, getString("gb.allowNamedDescription"));
+ break;
+ }
+ }
+ return map;
+ }
+
+ protected TimeZone getTimeZone() {
+ return GitBlit.getBoolean(Keys.web.useClientTimezone, false) ? GitBlitWebSession.get()
+ .getTimezone() : GitBlit.getTimezone();
+ }
+
+ protected String getServerName() {
+ ServletWebRequest servletWebRequest = (ServletWebRequest) getRequest();
+ HttpServletRequest req = servletWebRequest.getHttpServletRequest();
+ return req.getServerName();
+ }
+
+ public static String getRepositoryUrl(RepositoryModel repository) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(WicketUtils.getGitblitURL(RequestCycle.get().getRequest()));
+ sb.append(Constants.GIT_PATH);
+ sb.append(repository.name);
+
+ // inject username into repository url if authentication is required
+ if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE)
+ && GitBlitWebSession.get().isLoggedIn()) {
+ String username = GitBlitWebSession.get().getUsername();
+ sb.insert(sb.indexOf("://") + 3, username + "@");
+ }
+ return sb.toString();
+ }
+
+ protected List<ProjectModel> getProjectModels() {
+ final UserModel user = GitBlitWebSession.get().getUser();
+ List<ProjectModel> projects = GitBlit.self().getProjectModels(user, true);
+ return projects;
+ }
+
+ protected List<ProjectModel> getProjects(PageParameters params) {
+ if (params == null) {
+ return getProjectModels();
+ }
+
+ boolean hasParameter = false;
+ String regex = WicketUtils.getRegEx(params);
+ String team = WicketUtils.getTeam(params);
+ int daysBack = params.getInt("db", 0);
+
+ List<ProjectModel> availableModels = getProjectModels();
+ Set<ProjectModel> models = new HashSet<ProjectModel>();
+
+ if (!StringUtils.isEmpty(regex)) {
+ // filter the projects by the regex
+ hasParameter = true;
+ Pattern pattern = Pattern.compile(regex);
+ for (ProjectModel model : availableModels) {
+ if (pattern.matcher(model.name).find()) {
+ models.add(model);
+ }
+ }
+ }
+
+ if (!StringUtils.isEmpty(team)) {
+ // filter the projects by the specified teams
+ hasParameter = true;
+ List<String> teams = StringUtils.getStringsFromValue(team, ",");
+
+ // need TeamModels first
+ List<TeamModel> teamModels = new ArrayList<TeamModel>();
+ for (String name : teams) {
+ TeamModel teamModel = GitBlit.self().getTeamModel(name);
+ if (teamModel != null) {
+ teamModels.add(teamModel);
+ }
+ }
+
+ // brute-force our way through finding the matching models
+ for (ProjectModel projectModel : availableModels) {
+ for (String repositoryName : projectModel.repositories) {
+ for (TeamModel teamModel : teamModels) {
+ if (teamModel.hasRepositoryPermission(repositoryName)) {
+ models.add(projectModel);
+ }
+ }
+ }
+ }
+ }
+
+ if (!hasParameter) {
+ models.addAll(availableModels);
+ }
+
+ // time-filter the list
+ if (daysBack > 0) {
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.HOUR_OF_DAY, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ cal.add(Calendar.DATE, -1 * daysBack);
+ Date threshold = cal.getTime();
+ Set<ProjectModel> timeFiltered = new HashSet<ProjectModel>();
+ for (ProjectModel model : models) {
+ if (model.lastChange.after(threshold)) {
+ timeFiltered.add(model);
+ }
+ }
+ models = timeFiltered;
+ }
+
+ List<ProjectModel> list = new ArrayList<ProjectModel>(models);
+ Collections.sort(list);
+ return list;
+ }
+
+ public void warn(String message, Throwable t) {
+ logger.warn(message, t);
+ }
+
+ public void error(String message, boolean redirect) {
+ logger.error(message + " for " + GitBlitWebSession.get().getUsername());
+ if (redirect) {
+ GitBlitWebSession.get().cacheErrorMessage(message);
+ String relativeUrl = urlFor(RepositoriesPage.class, null).toString();
+ String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);
+ throw new RedirectToUrlException(absoluteUrl);
+ } else {
+ super.error(message);
+ }
+ }
+
+ public void error(String message, Throwable t, boolean redirect) {
+ logger.error(message, t);
+ if (redirect) {
+ GitBlitWebSession.get().cacheErrorMessage(message);
+ throw new RestartResponseException(getApplication().getHomePage());
+ } else {
+ super.error(message);
+ }
+ }
+
+ public void authenticationError(String message) {
+ logger.error(getRequest().getURL() + " for " + GitBlitWebSession.get().getUsername());
+ if (!GitBlitWebSession.get().isLoggedIn()) {
+ // cache the request if we have not authenticated.
+ // the request will continue after authentication.
+ GitBlitWebSession.get().cacheRequest(getClass());
+ }
+ error(message, true);
+ }
+
+ /**
+ * Panel fragment for displaying login or logout/change_password links.
+ *
+ */
+ static class UserFragment extends Fragment {
+
+ private static final long serialVersionUID = 1L;
+
+ public UserFragment(String id, String markupId, MarkupContainer markupProvider) {
+ super(id, markupId, markupProvider);
+
+ GitBlitWebSession session = GitBlitWebSession.get();
+ if (session.isLoggedIn()) {
+ UserModel user = session.getUser();
+ boolean editCredentials = GitBlit.self().supportsCredentialChanges(user);
+ boolean standardLogin = session.authenticationType.isStandard();
+
+ // username, logout, and change password
+ add(new Label("username", user.getDisplayName() + ":"));
+ add(new LinkPanel("loginLink", null, markupProvider.getString("gb.logout"),
+ LogoutPage.class).setVisible(standardLogin));
+
+ // quick and dirty hack for showing a separator
+ add(new Label("separator", "|").setVisible(standardLogin && editCredentials));
+ add(new BookmarkablePageLink<Void>("changePasswordLink",
+ ChangePasswordPage.class).setVisible(editCredentials));
+ } else {
+ // login
+ add(new Label("username").setVisible(false));
+ add(new Label("loginLink").setVisible(false));
+ add(new Label("separator").setVisible(false));
+ add(new Label("changePasswordLink").setVisible(false));
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/BlamePage.html b/src/main/java/com/gitblit/wicket/pages/BlamePage.html new file mode 100644 index 00000000..9391eaf0 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/BlamePage.html @@ -0,0 +1,39 @@ +<!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:extend>
+
+ <!-- blame nav links -->
+ <div class="page_nav2">
+ <a wicket:id="blobLink"><wicket:message key="gb.view"></wicket:message></a> | <a wicket:id="historyLink"><wicket:message key="gb.history"></wicket:message></a> | <a wicket:id="headLink"><wicket:message key="gb.head"></wicket:message></a> | <a wicket:id="commitLink"><wicket:message key="gb.commit"></wicket:message></a> | <a wicket:id="commitDiffLink"><wicket:message key="gb.commitdiff"></wicket:message></a>
+ </div>
+
+ <!-- commit header -->
+ <div wicket:id="commitHeader">[commit header]</div>
+
+ <!-- breadcrumbs -->
+ <div wicket:id="breadcrumbs">[breadcrumbs]</div>
+
+ <!-- blame content -->
+ <table class="annotated" style="margin-bottom:5px;">
+ <tbody>
+ <tr>
+ <th><wicket:message key="gb.commit">[commit]</wicket:message></th>
+ <th><wicket:message key="gb.line">[line]</wicket:message></th>
+ <th><wicket:message key="gb.content">[content]</wicket:message></th>
+ </tr>
+ <tr wicket:id="annotation">
+ <td><span class="sha1" wicket:id="commit"></span></td>
+ <td><span class="sha1" wicket:id="line"></span></td>
+ <td><span class="sha1" wicket:id="data"></span></td>
+ </tr>
+ </tbody>
+ </table>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/BlamePage.java b/src/main/java/com/gitblit/wicket/pages/BlamePage.java new file mode 100644 index 00000000..d76181d2 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/BlamePage.java @@ -0,0 +1,129 @@ +/*
+ * Copyright 2011 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.text.DateFormat;
+import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.AnnotatedLine;
+import com.gitblit.utils.DiffUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.CommitHeaderPanel;
+import com.gitblit.wicket.panels.LinkPanel;
+import com.gitblit.wicket.panels.PathBreadcrumbsPanel;
+
+public class BlamePage extends RepositoryPage {
+
+ public BlamePage(PageParameters params) {
+ super(params);
+
+ final String blobPath = WicketUtils.getPath(params);
+
+ RevCommit commit = getCommit();
+
+ add(new BookmarkablePageLink<Void>("blobLink", BlobPage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
+ add(new BookmarkablePageLink<Void>("commitLink", CommitPage.class,
+ WicketUtils.newObjectParameter(repositoryName, objectId)));
+ add(new BookmarkablePageLink<Void>("commitDiffLink", CommitDiffPage.class,
+ WicketUtils.newObjectParameter(repositoryName, objectId)));
+
+ // blame page links
+ add(new BookmarkablePageLink<Void>("headLink", BlamePage.class,
+ WicketUtils.newPathParameter(repositoryName, Constants.HEAD, blobPath)));
+ add(new BookmarkablePageLink<Void>("historyLink", HistoryPage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
+
+ add(new CommitHeaderPanel("commitHeader", repositoryName, commit));
+
+ add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, blobPath, objectId));
+
+ String format = GitBlit.getString(Keys.web.datetimestampLongFormat,
+ "EEEE, MMMM d, yyyy HH:mm Z");
+ final DateFormat df = new SimpleDateFormat(format);
+ df.setTimeZone(getTimeZone());
+ List<AnnotatedLine> lines = DiffUtils.blame(getRepository(), blobPath, objectId);
+ ListDataProvider<AnnotatedLine> blameDp = new ListDataProvider<AnnotatedLine>(lines);
+ DataView<AnnotatedLine> blameView = new DataView<AnnotatedLine>("annotation", blameDp) {
+ private static final long serialVersionUID = 1L;
+ private int count;
+ private String lastCommitId = "";
+ private boolean showInitials = true;
+
+ public void populateItem(final Item<AnnotatedLine> item) {
+ AnnotatedLine entry = item.getModelObject();
+ item.add(new Label("line", "" + entry.lineNumber));
+ item.add(new Label("data", StringUtils.escapeForHtml(entry.data, true))
+ .setEscapeModelStrings(false));
+ if (!lastCommitId.equals(entry.commitId)) {
+ lastCommitId = entry.commitId;
+ count++;
+ // show the link for first line
+ LinkPanel commitLink = new LinkPanel("commit", null,
+ getShortObjectId(entry.commitId), CommitPage.class,
+ newCommitParameter(entry.commitId));
+ WicketUtils.setHtmlTooltip(commitLink,
+ MessageFormat.format("{0}, {1}", entry.author, df.format(entry.when)));
+ item.add(commitLink);
+ showInitials = true;
+ } else {
+ if (showInitials) {
+ showInitials = false;
+ // show author initials
+ item.add(new Label("commit", getInitials(entry.author)));
+ } else {
+ // hide the commit link until the next block
+ item.add(new Label("commit").setVisible(false));
+ }
+ }
+ if (count % 2 == 0) {
+ WicketUtils.setCssClass(item, "even");
+ } else {
+ WicketUtils.setCssClass(item, "odd");
+ }
+ }
+ };
+ add(blameView);
+ }
+
+ private String getInitials(String author) {
+ StringBuilder sb = new StringBuilder();
+ String[] chunks = author.split(" ");
+ for (String chunk : chunks) {
+ sb.append(chunk.charAt(0));
+ }
+ return sb.toString().toUpperCase();
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.blame");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.html b/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.html new file mode 100644 index 00000000..c6336429 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.html @@ -0,0 +1,26 @@ +<!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:extend>
+
+ <!-- blob nav links -->
+ <div class="page_nav2">
+ <a wicket:id="blameLink"><wicket:message key="gb.blame"></wicket:message></a> | <a wicket:id="historyLink"><wicket:message key="gb.history"></wicket:message></a> | <a wicket:id="patchLink"><wicket:message key="gb.patch"></wicket:message></a> | <a wicket:id="commitLink"><wicket:message key="gb.commit"></wicket:message></a> | <a wicket:id="commitDiffLink"><wicket:message key="gb.commitdiff"></wicket:message></a>
+ </div>
+
+ <!-- commit header -->
+ <div wicket:id="commitHeader">[commit header]</div>
+
+ <!-- breadcrumbs -->
+ <div wicket:id="breadcrumbs">[breadcrumbs]</div>
+
+ <!-- diff content -->
+ <pre wicket:id="diffText">[diff text]</pre>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java b/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java new file mode 100644 index 00000000..d86d2e63 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java @@ -0,0 +1,85 @@ +/*
+ * Copyright 2011 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 org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.utils.DiffUtils;
+import com.gitblit.utils.DiffUtils.DiffOutputType;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.CommitHeaderPanel;
+import com.gitblit.wicket.panels.PathBreadcrumbsPanel;
+
+public class BlobDiffPage extends RepositoryPage {
+
+ public BlobDiffPage(PageParameters params) {
+ super(params);
+
+ final String blobPath = WicketUtils.getPath(params);
+ final String baseObjectId = WicketUtils.getBaseObjectId(params);
+
+ Repository r = getRepository();
+ RevCommit commit = getCommit();
+
+ DiffOutputType diffType = DiffOutputType.forName(GitBlit.getString(Keys.web.diffStyle,
+ DiffOutputType.GITBLIT.name()));
+
+ String diff;
+ if (StringUtils.isEmpty(baseObjectId)) {
+ // use first parent
+ diff = DiffUtils.getDiff(r, commit, blobPath, diffType);
+ add(new BookmarkablePageLink<Void>("patchLink", PatchPage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
+ } else {
+ // base commit specified
+ RevCommit baseCommit = JGitUtils.getCommit(r, baseObjectId);
+ diff = DiffUtils.getDiff(r, baseCommit, commit, blobPath, diffType);
+ add(new BookmarkablePageLink<Void>("patchLink", PatchPage.class,
+ WicketUtils.newBlobDiffParameter(repositoryName, baseObjectId, objectId,
+ blobPath)));
+ }
+
+ add(new BookmarkablePageLink<Void>("commitLink", CommitPage.class,
+ WicketUtils.newObjectParameter(repositoryName, objectId)));
+ add(new BookmarkablePageLink<Void>("commitDiffLink", CommitDiffPage.class,
+ WicketUtils.newObjectParameter(repositoryName, objectId)));
+
+ // diff page links
+ add(new BookmarkablePageLink<Void>("blameLink", BlamePage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
+ add(new BookmarkablePageLink<Void>("historyLink", HistoryPage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
+
+ add(new CommitHeaderPanel("commitHeader", repositoryName, commit));
+
+ add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, blobPath, objectId));
+
+ add(new Label("diffText", diff).setEscapeModelStrings(false));
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.diff");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/BlobPage.html b/src/main/java/com/gitblit/wicket/pages/BlobPage.html new file mode 100644 index 00000000..80f061fd --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/BlobPage.html @@ -0,0 +1,38 @@ +<!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">
+
+<!-- contribute google-code-prettify resources to the page header -->
+<wicket:head>
+ <wicket:link>
+ <link href="prettify/prettify.css" type="text/css" rel="stylesheet" />
+ <script type="text/javascript" src="prettify/prettify.js"></script>
+ </wicket:link>
+</wicket:head>
+
+<wicket:extend>
+<!-- need to specify body.onload -->
+<body onload="prettyPrint()">
+
+ <!-- blob nav links -->
+ <div class="page_nav2">
+ <a wicket:id="blameLink"><wicket:message key="gb.blame"></wicket:message></a> | <a wicket:id="historyLink"><wicket:message key="gb.history"></wicket:message></a> | <a wicket:id="rawLink"><wicket:message key="gb.raw"></wicket:message></a> | <a wicket:id="headLink"><wicket:message key="gb.head"></wicket:message></a>
+ </div>
+
+ <!-- commit header -->
+ <div wicket:id="commitHeader">[commit header]</div>
+
+ <!-- breadcrumbs -->
+ <div wicket:id="breadcrumbs">[breadcrumbs]</div>
+
+ <!-- blob content -->
+ <pre style="border:0px;" wicket:id="blobText">[blob content]</pre>
+
+ <!-- blob image -->
+ <img wicket:id="blobImage" style="padding-top:5px;"></img>
+
+</body>
+</wicket:extend>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/BlobPage.java b/src/main/java/com/gitblit/wicket/pages/BlobPage.java new file mode 100644 index 00000000..e2b8546b --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/BlobPage.java @@ -0,0 +1,194 @@ +/*
+ * Copyright 2011 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.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.image.Image;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.ExternalImage;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.CommitHeaderPanel;
+import com.gitblit.wicket.panels.PathBreadcrumbsPanel;
+
+public class BlobPage extends RepositoryPage {
+
+ public BlobPage(PageParameters params) {
+ super(params);
+
+ Repository r = getRepository();
+ final String blobPath = WicketUtils.getPath(params);
+ String [] encodings = GitBlit.getEncodings();
+
+ if (StringUtils.isEmpty(blobPath)) {
+ // blob by objectid
+
+ add(new BookmarkablePageLink<Void>("blameLink", BlamePage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, blobPath))
+ .setEnabled(false));
+ add(new BookmarkablePageLink<Void>("historyLink", HistoryPage.class).setEnabled(false));
+ add(new BookmarkablePageLink<Void>("rawLink", RawPage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
+ add(new BookmarkablePageLink<Void>("headLink", BlobPage.class).setEnabled(false));
+ add(new CommitHeaderPanel("commitHeader", objectId));
+ add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, blobPath, objectId));
+ Component c = new Label("blobText", JGitUtils.getStringContent(r, objectId, encodings));
+ WicketUtils.setCssClass(c, "plainprint");
+ add(c);
+ } else {
+ // standard blob view
+ String extension = null;
+ if (blobPath.lastIndexOf('.') > -1) {
+ extension = blobPath.substring(blobPath.lastIndexOf('.') + 1).toLowerCase();
+ }
+
+ // see if we should redirect to the markdown page
+ for (String ext : GitBlit.getStrings(Keys.web.markdownExtensions)) {
+ if (ext.equals(extension)) {
+ setResponsePage(MarkdownPage.class, params);
+ return;
+ }
+ }
+
+ // manually get commit because it can be null
+ RevCommit commit = JGitUtils.getCommit(r, objectId);
+
+ // blob page links
+ add(new BookmarkablePageLink<Void>("blameLink", BlamePage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
+ add(new BookmarkablePageLink<Void>("historyLink", HistoryPage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
+ add(new BookmarkablePageLink<Void>("rawLink", RawPage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
+ add(new BookmarkablePageLink<Void>("headLink", BlobPage.class,
+ WicketUtils.newPathParameter(repositoryName, Constants.HEAD, blobPath)));
+
+ add(new CommitHeaderPanel("commitHeader", repositoryName, commit));
+
+ add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, blobPath, objectId));
+
+ // Map the extensions to types
+ Map<String, Integer> map = new HashMap<String, Integer>();
+ for (String ext : GitBlit.getStrings(Keys.web.prettyPrintExtensions)) {
+ map.put(ext.toLowerCase(), 1);
+ }
+ for (String ext : GitBlit.getStrings(Keys.web.imageExtensions)) {
+ map.put(ext.toLowerCase(), 2);
+ }
+ for (String ext : GitBlit.getStrings(Keys.web.binaryExtensions)) {
+ map.put(ext.toLowerCase(), 3);
+ }
+
+ if (extension != null) {
+ int type = 0;
+ if (map.containsKey(extension)) {
+ type = map.get(extension);
+ }
+ switch (type) {
+ case 2:
+ // image blobs
+ add(new Label("blobText").setVisible(false));
+ add(new ExternalImage("blobImage", urlFor(RawPage.class, WicketUtils.newPathParameter(repositoryName, objectId, blobPath)).toString()));
+ break;
+ case 3:
+ // binary blobs
+ add(new Label("blobText", "Binary File"));
+ add(new Image("blobImage").setVisible(false));
+ break;
+ default:
+ // plain text
+ String source = JGitUtils.getStringContent(r, commit.getTree(), blobPath, encodings);
+ String table = generateSourceView(source, type == 1);
+ add(new Label("blobText", table).setEscapeModelStrings(false));
+ add(new Image("blobImage").setVisible(false));
+ }
+ } else {
+ // plain text
+ String source = JGitUtils.getStringContent(r, commit.getTree(), blobPath, encodings);
+ String table = generateSourceView(source, false);
+ add(new Label("blobText", table).setEscapeModelStrings(false));
+ add(new Image("blobImage").setVisible(false));
+ }
+ }
+ }
+
+ protected String generateSourceView(String source, boolean prettyPrint) {
+ String [] lines = source.split("\n");
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("<!-- start blob table -->");
+ sb.append("<table width=\"100%\"><tbody><tr>");
+
+ // nums column
+ sb.append("<!-- start nums column -->");
+ sb.append("<td id=\"nums\">");
+ sb.append("<pre>");
+ String numPattern = "<span id=\"L{0}\" class=\"num\">{0}</span>\n";
+ for (int i = 0; i < lines.length; i++) {
+ sb.append(MessageFormat.format(numPattern, "" + (i + 1)));
+ }
+ sb.append("</pre>");
+ sb.append("<!-- end nums column -->");
+ sb.append("</td>");
+
+ sb.append("<!-- start lines column -->");
+ sb.append("<td id=\"lines\">");
+ sb.append("<div class=\"sourceview\">");
+ if (prettyPrint) {
+ sb.append("<pre class=\"prettyprint\">");
+ } else {
+ sb.append("<pre class=\"plainprint\">");
+ }
+ lines = StringUtils.escapeForHtml(source, true).split("\n");
+
+ sb.append("<table width=\"100%\"><tbody>");
+
+ String linePattern = "<tr class=\"{0}\"><td><a href=\"#L{2}\">{1}</a>\r</tr>";
+ for (int i = 0; i < lines.length; i++) {
+ String line = lines[i].replace('\r', ' ');
+ String cssClass = (i % 2 == 0) ? "even" : "odd";
+ sb.append(MessageFormat.format(linePattern, cssClass, line, "" + (i + 1)));
+ }
+ sb.append("</tbody></table></pre>");
+ sb.append("</pre>");
+ sb.append("</div>");
+ sb.append("</td>");
+ sb.append("<!-- end lines column -->");
+
+ sb.append("</tr></tbody></table>");
+ sb.append("<!-- end blob table -->");
+
+ return sb.toString();
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.view");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/BranchesPage.html b/src/main/java/com/gitblit/wicket/pages/BranchesPage.html new file mode 100644 index 00000000..65fd9b9d --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/BranchesPage.html @@ -0,0 +1,15 @@ +<!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:extend>
+
+ <!-- branches -->
+ <div style="margin-top:5px;" wicket:id="branchesPanel">[branches panel]</div>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/BranchesPage.java b/src/main/java/com/gitblit/wicket/pages/BranchesPage.java new file mode 100644 index 00000000..8684fb3d --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/BranchesPage.java @@ -0,0 +1,34 @@ +/*
+ * Copyright 2011 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 org.apache.wicket.PageParameters;
+
+import com.gitblit.wicket.panels.BranchesPanel;
+
+public class BranchesPage extends RepositoryPage {
+
+ public BranchesPage(PageParameters params) {
+ super(params);
+
+ add(new BranchesPanel("branchesPanel", getRepositoryModel(), getRepository(), -1, isShowAdmin() || isOwner()));
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.branches");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/ChangePasswordPage.html b/src/main/java/com/gitblit/wicket/pages/ChangePasswordPage.html new file mode 100644 index 00000000..36439a91 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ChangePasswordPage.html @@ -0,0 +1,31 @@ +<!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('password').focus();">
+ <div>
+ <form style="text-align:center;" wicket:id="passwordForm">
+ <center>
+ <table class="plain">
+ <tr>
+ <th><wicket:message key="gb.password"></wicket:message> </th>
+ <td class="edit"><input type="password" wicket:id="password" id="password" size="30" tabindex="1" /></td>
+ </tr>
+ <tr>
+ <th><wicket:message key="gb.confirmPassword"></wicket:message> </th>
+ <td class="edit"><input type="password" wicket:id="confirmPassword" size="30" tabindex="2" /></td>
+ </tr>
+ </table>
+ <div class="form-actions">
+ <input class="btn btn-primary" type="submit" wicket:message="value:gb.save" wicket:id="save" tabindex="3" />
+ <input class="btn" type="submit" wicket:message="value:gb.cancel" wicket:id="cancel" tabindex="4" />
+ </div>
+ </center>
+ </form>
+ </div>
+ </body>
+ </wicket:extend>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/ChangePasswordPage.java b/src/main/java/com/gitblit/wicket/pages/ChangePasswordPage.java new file mode 100644 index 00000000..c4014208 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ChangePasswordPage.java @@ -0,0 +1,139 @@ +/*
+ * Copyright 2011 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.text.MessageFormat;
+
+import org.apache.wicket.RestartResponseException;
+import org.apache.wicket.markup.html.form.Button;
+import org.apache.wicket.markup.html.form.PasswordTextField;
+import org.apache.wicket.markup.html.form.StatelessForm;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.protocol.http.WebResponse;
+
+import com.gitblit.GitBlit;
+import com.gitblit.GitBlitException;
+import com.gitblit.Keys;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+
+public class ChangePasswordPage extends RootSubPage {
+
+ IModel<String> password = new Model<String>("");
+ IModel<String> confirmPassword = new Model<String>("");
+
+ public ChangePasswordPage() {
+ super();
+
+ if (!GitBlitWebSession.get().isLoggedIn()) {
+ // Change password requires a login
+ throw new RestartResponseException(getApplication().getHomePage());
+ }
+
+ if (!GitBlit.getBoolean(Keys.web.authenticateAdminPages, true)
+ && !GitBlit.getBoolean(Keys.web.authenticateViewPages, false)) {
+ // no authentication enabled
+ throw new RestartResponseException(getApplication().getHomePage());
+ }
+
+ UserModel user = GitBlitWebSession.get().getUser();
+ if (!GitBlit.self().supportsCredentialChanges(user)) {
+ error(MessageFormat.format(getString("gb.userServiceDoesNotPermitPasswordChanges"),
+ GitBlit.getString(Keys.realm.userService, "${baseFolder}/users.conf")), true);
+ }
+
+ setupPage(getString("gb.changePassword"), user.username);
+
+ StatelessForm<Void> form = new StatelessForm<Void>("passwordForm") {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onSubmit() {
+ String password = ChangePasswordPage.this.password.getObject();
+ String confirmPassword = ChangePasswordPage.this.confirmPassword.getObject();
+ // ensure passwords match
+ if (!password.equals(confirmPassword)) {
+ error(getString("gb.passwordsDoNotMatch"));
+ return;
+ }
+
+ // ensure password satisfies minimum length requirement
+ int minLength = GitBlit.getInteger(Keys.realm.minPasswordLength, 5);
+ if (minLength < 4) {
+ minLength = 4;
+ }
+ if (password.length() < minLength) {
+ error(MessageFormat.format(getString("gb.passwordTooShort"), minLength));
+ return;
+ }
+
+ UserModel user = GitBlitWebSession.get().getUser();
+
+ // convert to MD5 digest, if appropriate
+ String type = GitBlit.getString(Keys.realm.passwordStorage, "md5");
+ if (type.equalsIgnoreCase("md5")) {
+ // store MD5 digest of password
+ password = StringUtils.MD5_TYPE + StringUtils.getMD5(password);
+ } else if (type.equalsIgnoreCase("combined-md5")) {
+ // store MD5 digest of username+password
+ password = StringUtils.COMBINED_MD5_TYPE
+ + StringUtils.getMD5(user.username.toLowerCase() + password);
+ }
+
+ user.password = password;
+ try {
+ GitBlit.self().updateUserModel(user.username, user, false);
+ if (GitBlit.getBoolean(Keys.web.allowCookieAuthentication, false)) {
+ WebResponse response = (WebResponse) getRequestCycle().getResponse();
+ GitBlit.self().setCookie(response, user);
+ }
+ } catch (GitBlitException e) {
+ error(e.getMessage());
+ return;
+ }
+ setRedirect(false);
+ info(getString("gb.passwordChanged"));
+ setResponsePage(RepositoriesPage.class);
+ }
+ };
+ PasswordTextField passwordField = new PasswordTextField("password", password);
+ passwordField.setResetPassword(false);
+ form.add(passwordField);
+ PasswordTextField confirmPasswordField = new PasswordTextField("confirmPassword",
+ confirmPassword);
+ confirmPasswordField.setResetPassword(false);
+ form.add(confirmPasswordField);
+
+ form.add(new Button("save"));
+ Button cancel = new Button("cancel") {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onSubmit() {
+ setRedirect(false);
+ error(getString("gb.passwordChangeAborted"));
+ setResponsePage(RepositoriesPage.class);
+ }
+ };
+ cancel.setDefaultFormProcessing(false);
+ form.add(cancel);
+
+ add(form);
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.html b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.html new file mode 100644 index 00000000..de39f4ca --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.html @@ -0,0 +1,43 @@ +<!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:extend>
+
+ <!-- commitdiff nav links -->
+ <div class="page_nav2">
+ <wicket:message key="gb.parent"></wicket:message>: <span wicket:id="parentLink">[parent link]</span> | <a wicket:id="patchLink"><wicket:message key="gb.patch"></wicket:message></a> | <a wicket:id="commitLink"><wicket:message key="gb.commit"></wicket:message></a>
+ </div>
+
+ <!-- commit header -->
+ <div wicket:id="commitHeader">[commit header]</div>
+
+ <!-- changed paths -->
+ <div style="padding-top:15px;">
+ <!-- commit legend -->
+ <div class="hidden-phone" style="text-align:right;" wicket:id="commitLegend"></div>
+
+ <div class="header"><i class="icon-file"></i> <wicket:message key="gb.changedFiles">[changed files]</wicket:message></div>
+ </div>
+
+ <table class="pretty">
+ <tr wicket:id="changedPath">
+ <td class="changeType"><span wicket:id="changeType">[change type]</span></td>
+ <td class="path"><span wicket:id="pathName">[commit path]</span></td>
+ <td class="hidden-phone rightAlign">
+ <span class="link">
+ <a wicket:id="patch"><wicket:message key="gb.patch"></wicket:message></a> | <a wicket:id="view"><wicket:message key="gb.view"></wicket:message></a> | <a wicket:id="blame"><wicket:message key="gb.blame"></wicket:message></a> | <a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a>
+ </span>
+ </td>
+ </tr>
+ </table>
+
+ <!-- diff content -->
+ <pre style="padding-top:10px;" wicket:id="diffText">[diff text]</pre>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java new file mode 100644 index 00000000..3ad70742 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java @@ -0,0 +1,192 @@ +/* + * Copyright 2011 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.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.link.BookmarkablePageLink; +import org.apache.wicket.markup.html.link.ExternalLink; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.markup.repeater.data.DataView; +import org.apache.wicket.markup.repeater.data.ListDataProvider; +import org.eclipse.jgit.diff.DiffEntry.ChangeType; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; + +import com.gitblit.GitBlit; +import com.gitblit.Keys; +import com.gitblit.models.PathModel.PathChangeModel; +import com.gitblit.models.SubmoduleModel; +import com.gitblit.utils.DiffUtils; +import com.gitblit.utils.DiffUtils.DiffOutputType; +import com.gitblit.utils.JGitUtils; +import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.panels.CommitHeaderPanel; +import com.gitblit.wicket.panels.CommitLegendPanel; +import com.gitblit.wicket.panels.LinkPanel; + +public class CommitDiffPage extends RepositoryPage { + + public CommitDiffPage(PageParameters params) { + super(params); + + Repository r = getRepository(); + + DiffOutputType diffType = DiffOutputType.forName(GitBlit.getString(Keys.web.diffStyle, + DiffOutputType.GITBLIT.name())); + + RevCommit commit = null, otherCommit = null; + + if( objectId.contains("..") ) + { + String[] parts = objectId.split("\\.\\."); + commit = getCommit(r, parts[0]); + otherCommit = getCommit(r, parts[1]); + } + else + { + commit = getCommit(); + } + + String diff; + + if(otherCommit == null) + { + diff = DiffUtils.getCommitDiff(r, commit, diffType); + } + else + { + diff = DiffUtils.getDiff(r, commit, otherCommit, diffType); + } + + List<String> parents = new ArrayList<String>(); + if (commit.getParentCount() > 0) { + for (RevCommit parent : commit.getParents()) { + parents.add(parent.name()); + } + } + + // commit page links + if (parents.size() == 0) { + add(new Label("parentLink", getString("gb.none"))); + } else { + add(new LinkPanel("parentLink", null, parents.get(0).substring(0, 8), + CommitDiffPage.class, newCommitParameter(parents.get(0)))); + } + add(new BookmarkablePageLink<Void>("patchLink", PatchPage.class, + WicketUtils.newObjectParameter(repositoryName, objectId))); + add(new BookmarkablePageLink<Void>("commitLink", CommitPage.class, + WicketUtils.newObjectParameter(repositoryName, objectId))); + + add(new CommitHeaderPanel("commitHeader", repositoryName, commit)); + + // changed paths list + List<PathChangeModel> paths; + + if( otherCommit == null ) + { + paths = JGitUtils.getFilesInCommit(r, commit); + } + else + { + paths = JGitUtils.getFilesInCommit(r, otherCommit); + } + + add(new CommitLegendPanel("commitLegend", paths)); + ListDataProvider<PathChangeModel> pathsDp = new ListDataProvider<PathChangeModel>(paths); + DataView<PathChangeModel> pathsView = new DataView<PathChangeModel>("changedPath", pathsDp) { + private static final long serialVersionUID = 1L; + int counter; + + public void populateItem(final Item<PathChangeModel> item) { + final PathChangeModel entry = item.getModelObject(); + Label changeType = new Label("changeType", ""); + WicketUtils.setChangeTypeCssClass(changeType, entry.changeType); + setChangeTypeTooltip(changeType, entry.changeType); + item.add(changeType); + + boolean hasSubmodule = false; + String submodulePath = null; + if (entry.isTree()) { + // tree + item.add(new LinkPanel("pathName", null, entry.path, TreePage.class, + WicketUtils + .newPathParameter(repositoryName, entry.commitId, entry.path))); + } else if (entry.isSubmodule()) { + // submodule + String submoduleId = entry.objectId; + SubmoduleModel submodule = getSubmodule(entry.path); + submodulePath = submodule.gitblitPath; + hasSubmodule = submodule.hasSubmodule; + + item.add(new LinkPanel("pathName", "list", entry.path + " @ " + + getShortObjectId(submoduleId), TreePage.class, + WicketUtils + .newPathParameter(submodulePath, submoduleId, "")).setEnabled(hasSubmodule)); + } else { + // blob + item.add(new LinkPanel("pathName", "list", entry.path, BlobPage.class, + WicketUtils + .newPathParameter(repositoryName, entry.commitId, entry.path))); + } + + // quick links + if (entry.isSubmodule()) { + // submodule + item.add(new ExternalLink("patch", "").setEnabled(false)); + item.add(new BookmarkablePageLink<Void>("view", CommitPage.class, WicketUtils + .newObjectParameter(submodulePath, entry.objectId)).setEnabled(hasSubmodule)); + item.add(new ExternalLink("blame", "").setEnabled(false)); + item.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils + .newPathParameter(repositoryName, entry.commitId, entry.path))); + } else { + // tree or blob + item.add(new BookmarkablePageLink<Void>("patch", PatchPage.class, WicketUtils + .newPathParameter(repositoryName, entry.commitId, entry.path))); + item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, WicketUtils + .newPathParameter(repositoryName, entry.commitId, entry.path))); + item.add(new BookmarkablePageLink<Void>("blame", BlamePage.class, WicketUtils + .newPathParameter(repositoryName, entry.commitId, entry.path))); + item.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils + .newPathParameter(repositoryName, entry.commitId, entry.path)) + .setEnabled(!entry.changeType.equals(ChangeType.ADD))); + } + WicketUtils.setAlternatingBackground(item, counter); + counter++; + } + }; + add(pathsView); + add(new Label("diffText", diff).setEscapeModelStrings(false)); + } + + @Override + protected String getPageName() { + return getString("gb.commitdiff"); + } + + private RevCommit getCommit(Repository r, String rev) + { + RevCommit otherCommit = JGitUtils.getCommit(r, rev); + if (otherCommit == null) { + error(MessageFormat.format(getString("gb.failedToFindCommit"), rev, repositoryName, getPageName()), true); + } + return otherCommit; + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/CommitPage.html b/src/main/java/com/gitblit/wicket/pages/CommitPage.html new file mode 100644 index 00000000..79a038c9 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/CommitPage.html @@ -0,0 +1,99 @@ +<!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:extend>
+
+ <!-- commit nav links -->
+ <div class="page_nav2">
+ <wicket:message key="gb.parent"></wicket:message>: <span wicket:id="parentLink">[parent link]</span> | <a wicket:id="patchLink"><wicket:message key="gb.patch"></wicket:message></a> | <span wicket:id="commitdiffLink">[commitdiff link]</span>
+ </div>
+
+ <!-- commit header -->
+ <div wicket:id="commitHeader">[commit header]</div>
+
+ <div class="row">
+
+
+ <div class="span10">
+ <!-- commit info -->
+ <table class="plain">
+ <tr><th><wicket:message key="gb.refs">refs</wicket:message></th><td><div wicket:id="refsPanel">[references]</div></td></tr>
+ <tr><th><wicket:message key="gb.author">author</wicket:message></th><td><span class="sha1" wicket:id="commitAuthor">[author</span></td></tr>
+ <tr><th></th><td><span class="sha1" wicket:id="commitAuthorDate">[author date]</span></td></tr>
+ <tr><th><wicket:message key="gb.committer">committer</wicket:message></th><td><span class="sha1" wicket:id="commitCommitter">[committer]</span></td></tr>
+ <tr><th></th><td><span class="sha1" wicket:id="commitCommitterDate">[commit date]</span></td></tr>
+ <tr class="hidden-phone"><th><wicket:message key="gb.commit">commit</wicket:message></th><td><span class="sha1" wicket:id="commitId">[commit id]</span></td></tr>
+ <tr class="hidden-phone"><th><wicket:message key="gb.tree">tree</wicket:message></th>
+ <td><span class="sha1" wicket:id="commitTree">[commit tree]</span>
+ <span class="link">
+ <a wicket:id="treeLink"><wicket:message key="gb.tree"></wicket:message></a> | <span wicket:id="compressedLinks"></span>
+ </span>
+ </td></tr>
+ <tr class="hidden-phone"><th valign="top"><wicket:message key="gb.parent">parent</wicket:message></th>
+ <td>
+ <span wicket:id="commitParents">
+ <span class="sha1" wicket:id="commitParent">[commit parents]</span>
+ <span class="link">
+ <a wicket:id="view"><wicket:message key="gb.view"></wicket:message></a> | <a wicket:id="diff"><wicket:message key="gb.diff"></wicket:message></a>
+ </span><br/>
+ </span>
+ </td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+
+ <!-- full message -->
+ <div class="commit_message" wicket:id="fullMessage">[commit message]</div>
+
+ <!-- git notes -->
+ <table class="gitnotes">
+ <tr wicket:id="notes">
+ <td class="info">
+ <table>
+ <tr><td><span wicket:id="refName"></span></td></tr>
+ <tr><td><span class="sha1" wicket:id="authorName"></span></td></tr>
+ <tr><td><span class="sha1" wicket:id="authorDate"></span></td></tr>
+ </table>
+ <!-- Note Author Gravatar -->
+ <span style="vertical-align: top;" wicket:id="noteAuthorAvatar" />
+ </td>
+ <td class="message"><span class="sha1" wicket:id="noteContent"></span></td>
+ </tr>
+ </table>
+
+ <!-- commit legend -->
+ <div class="hidden-phone" style="text-align:right;" wicket:id="commitLegend"></div>
+
+ <!-- header -->
+ <div class="header"><i class="icon-file"></i> <wicket:message key="gb.changedFiles">[changed files]</wicket:message></div>
+
+ <!-- changed paths -->
+ <table class="pretty">
+ <tr wicket:id="changedPath">
+ <td class="changeType"><span wicket:id="changeType">[change type]</span></td>
+ <td class="path"><span wicket:id="pathName">[commit path]</span></td>
+ <td class="hidden-phone rightAlign">
+ <span class="link">
+ <a wicket:id="diff"><wicket:message key="gb.diff"></wicket:message></a> | <a wicket:id="view"><wicket:message key="gb.view"></wicket:message></a> | <a wicket:id="blame"><wicket:message key="gb.blame"></wicket:message></a> | <a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a>
+ </span>
+ </td>
+ </tr>
+ </table>
+
+ <wicket:fragment wicket:id="fullPersonIdent">
+ <span wicket:id="personName"></span><span wicket:id="personAddress"></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="partialPersonIdent">
+ <span wicket:id="personName"></span>
+ </wicket:fragment>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/CommitPage.java b/src/main/java/com/gitblit/wicket/pages/CommitPage.java new file mode 100644 index 00000000..c5a24c8d --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/CommitPage.java @@ -0,0 +1,223 @@ +/*
+ * Copyright 2011 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.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.link.ExternalLink;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.apache.wicket.model.StringResourceModel;
+import org.eclipse.jgit.diff.DiffEntry.ChangeType;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import com.gitblit.Constants;
+import com.gitblit.GitBlit;
+import com.gitblit.models.GitNote;
+import com.gitblit.models.PathModel.PathChangeModel;
+import com.gitblit.models.SubmoduleModel;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.CommitHeaderPanel;
+import com.gitblit.wicket.panels.CommitLegendPanel;
+import com.gitblit.wicket.panels.CompressedDownloadsPanel;
+import com.gitblit.wicket.panels.GravatarImage;
+import com.gitblit.wicket.panels.LinkPanel;
+import com.gitblit.wicket.panels.RefsPanel;
+
+public class CommitPage extends RepositoryPage {
+
+ public CommitPage(PageParameters params) {
+ super(params);
+
+ Repository r = getRepository();
+ RevCommit c = getCommit();
+
+ List<String> parents = new ArrayList<String>();
+ if (c.getParentCount() > 0) {
+ for (RevCommit parent : c.getParents()) {
+ parents.add(parent.name());
+ }
+ }
+
+ // commit page links
+ if (parents.size() == 0) {
+ add(new Label("parentLink", "none"));
+ add(new Label("commitdiffLink", getString("gb.commitdiff")));
+ } else {
+ add(new LinkPanel("parentLink", null, getShortObjectId(parents.get(0)),
+ CommitPage.class, newCommitParameter(parents.get(0))));
+ add(new LinkPanel("commitdiffLink", null, new StringResourceModel("gb.commitdiff",
+ this, null), CommitDiffPage.class, WicketUtils.newObjectParameter(
+ repositoryName, objectId)));
+ }
+ add(new BookmarkablePageLink<Void>("patchLink", PatchPage.class,
+ WicketUtils.newObjectParameter(repositoryName, objectId)));
+
+ add(new CommitHeaderPanel("commitHeader", repositoryName, c));
+
+ addRefs(r, c);
+
+ // author
+ add(createPersonPanel("commitAuthor", c.getAuthorIdent(), Constants.SearchType.AUTHOR));
+ add(WicketUtils.createTimestampLabel("commitAuthorDate", c.getAuthorIdent().getWhen(),
+ getTimeZone(), getTimeUtils()));
+
+ // committer
+ add(createPersonPanel("commitCommitter", c.getCommitterIdent(), Constants.SearchType.COMMITTER));
+ add(WicketUtils.createTimestampLabel("commitCommitterDate",
+ c.getCommitterIdent().getWhen(), getTimeZone(), getTimeUtils()));
+
+ add(new Label("commitId", c.getName()));
+
+ add(new LinkPanel("commitTree", "list", c.getTree().getName(), TreePage.class,
+ newCommitParameter()));
+ add(new BookmarkablePageLink<Void>("treeLink", TreePage.class, newCommitParameter()));
+ final String baseUrl = WicketUtils.getGitblitURL(getRequest());
+
+ add(new CompressedDownloadsPanel("compressedLinks", baseUrl, repositoryName, objectId, null));
+
+ // Parent Commits
+ ListDataProvider<String> parentsDp = new ListDataProvider<String>(parents);
+ DataView<String> parentsView = new DataView<String>("commitParents", parentsDp) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<String> item) {
+ String entry = item.getModelObject();
+ item.add(new LinkPanel("commitParent", "list", entry, CommitPage.class,
+ newCommitParameter(entry)));
+ item.add(new BookmarkablePageLink<Void>("view", CommitPage.class,
+ newCommitParameter(entry)));
+ item.add(new BookmarkablePageLink<Void>("diff", CommitDiffPage.class,
+ newCommitParameter(entry)));
+ }
+ };
+ add(parentsView);
+
+ addFullText("fullMessage", c.getFullMessage(), true);
+
+ // git notes
+ List<GitNote> notes = JGitUtils.getNotesOnCommit(r, c);
+ ListDataProvider<GitNote> notesDp = new ListDataProvider<GitNote>(notes);
+ DataView<GitNote> notesView = new DataView<GitNote>("notes", notesDp) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<GitNote> item) {
+ GitNote entry = item.getModelObject();
+ item.add(new RefsPanel("refName", repositoryName, Arrays.asList(entry.notesRef)));
+ item.add(createPersonPanel("authorName", entry.notesRef.getAuthorIdent(),
+ Constants.SearchType.AUTHOR));
+ item.add(new GravatarImage("noteAuthorAvatar", entry.notesRef.getAuthorIdent()));
+ item.add(WicketUtils.createTimestampLabel("authorDate", entry.notesRef
+ .getAuthorIdent().getWhen(), getTimeZone(), getTimeUtils()));
+ item.add(new Label("noteContent", GitBlit.self().processCommitMessage(
+ repositoryName, entry.content)).setEscapeModelStrings(false));
+ }
+ };
+ add(notesView.setVisible(notes.size() > 0));
+
+ // changed paths list
+ List<PathChangeModel> paths = JGitUtils.getFilesInCommit(r, c);
+ add(new CommitLegendPanel("commitLegend", paths));
+ ListDataProvider<PathChangeModel> pathsDp = new ListDataProvider<PathChangeModel>(paths);
+ DataView<PathChangeModel> pathsView = new DataView<PathChangeModel>("changedPath", pathsDp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+
+ public void populateItem(final Item<PathChangeModel> item) {
+ final PathChangeModel entry = item.getModelObject();
+ Label changeType = new Label("changeType", "");
+ WicketUtils.setChangeTypeCssClass(changeType, entry.changeType);
+ setChangeTypeTooltip(changeType, entry.changeType);
+ item.add(changeType);
+
+ boolean hasSubmodule = false;
+ String submodulePath = null;
+ if (entry.isTree()) {
+ // tree
+ item.add(new LinkPanel("pathName", null, entry.path, TreePage.class,
+ WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path)));
+ } else if (entry.isSubmodule()) {
+ // submodule
+ String submoduleId = entry.objectId;
+ SubmoduleModel submodule = getSubmodule(entry.path);
+ submodulePath = submodule.gitblitPath;
+ hasSubmodule = submodule.hasSubmodule;
+
+ item.add(new LinkPanel("pathName", "list", entry.path + " @ " +
+ getShortObjectId(submoduleId), TreePage.class,
+ WicketUtils.newPathParameter(submodulePath, submoduleId, "")).setEnabled(hasSubmodule));
+ } else {
+ // blob
+ String displayPath = entry.path;
+ String path = entry.path;
+ if (entry.isSymlink()) {
+ path = JGitUtils.getStringContent(getRepository(), getCommit().getTree(), path);
+ displayPath = entry.path + " -> " + path;
+ }
+ item.add(new LinkPanel("pathName", "list", displayPath, BlobPage.class,
+ WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, path)));
+ }
+
+ // quick links
+ if (entry.isSubmodule()) {
+ // submodule
+ item.add(new BookmarkablePageLink<Void>("diff", BlobDiffPage.class, WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path))
+ .setEnabled(!entry.changeType.equals(ChangeType.ADD)));
+ item.add(new BookmarkablePageLink<Void>("view", CommitPage.class, WicketUtils
+ .newObjectParameter(submodulePath, entry.objectId)).setEnabled(hasSubmodule));
+ item.add(new ExternalLink("blame", "").setEnabled(false));
+ item.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path))
+ .setEnabled(!entry.changeType.equals(ChangeType.ADD)));
+ } else {
+ // tree or blob
+ item.add(new BookmarkablePageLink<Void>("diff", BlobDiffPage.class, WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path))
+ .setEnabled(!entry.changeType.equals(ChangeType.ADD)
+ && !entry.changeType.equals(ChangeType.DELETE)));
+ item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path)));
+ item.add(new BookmarkablePageLink<Void>("blame", BlamePage.class, WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path))
+ .setEnabled(!entry.changeType.equals(ChangeType.ADD)));
+ item.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path))
+ .setEnabled(!entry.changeType.equals(ChangeType.ADD)));
+ }
+
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(pathsView);
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.commit");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/DocsPage.html b/src/main/java/com/gitblit/wicket/pages/DocsPage.html new file mode 100644 index 00000000..ad93000c --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/DocsPage.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:extend>
+
+ <!-- header -->
+ <div style="margin-top:5px;" class="header"><i class="icon-book" style="vertical-align: middle;"></i> <b><span wicket:id="header">[header]</span></b></div>
+
+ <!-- documents -->
+ <table style="width:100%" class="pretty">
+ <tr wicket:id="document">
+ <td class="icon"><img wicket:id="docIcon" /></td>
+ <td><span wicket:id="docName"></span></td>
+ <td class="size"><span wicket:id="docSize">[doc size]</span></td>
+ <td class="treeLinks">
+ <span class="hidden-phone link">
+ <a wicket:id="view"><wicket:message key="gb.view"></wicket:message></a> | <a wicket:id="raw"><wicket:message key="gb.raw"></wicket:message></a> | <a wicket:id="blame"><wicket:message key="gb.blame"></wicket:message></a> | <a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a>
+ </span>
+ </td>
+ </tr>
+ </table>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/DocsPage.java b/src/main/java/com/gitblit/wicket/pages/DocsPage.java new file mode 100644 index 00000000..9ddc98d3 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/DocsPage.java @@ -0,0 +1,82 @@ +/*
+ * Copyright 2011 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.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.eclipse.jgit.lib.Repository;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.PathModel;
+import com.gitblit.utils.ByteFormat;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.LinkPanel;
+
+public class DocsPage extends RepositoryPage {
+
+ public DocsPage(PageParameters params) {
+ super(params);
+
+ Repository r = getRepository();
+ List<String> extensions = GitBlit.getStrings(Keys.web.markdownExtensions);
+ List<PathModel> paths = JGitUtils.getDocuments(r, extensions);
+
+ final ByteFormat byteFormat = new ByteFormat();
+
+ add(new Label("header", getString("gb.docs")));
+
+ // documents list
+ ListDataProvider<PathModel> pathsDp = new ListDataProvider<PathModel>(paths);
+ DataView<PathModel> pathsView = new DataView<PathModel>("document", pathsDp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+
+ public void populateItem(final Item<PathModel> item) {
+ PathModel entry = item.getModelObject();
+ item.add(WicketUtils.newImage("docIcon", "file_world_16x16.png"));
+ item.add(new Label("docSize", byteFormat.format(entry.size)));
+ item.add(new LinkPanel("docName", "list", entry.name, BlobPage.class, WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path)));
+
+ // links
+ item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path)));
+ item.add(new BookmarkablePageLink<Void>("raw", RawPage.class, WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path)));
+ item.add(new BookmarkablePageLink<Void>("blame", BlamePage.class, WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path)));
+ item.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path)));
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(pathsView);
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.docs");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html new file mode 100644 index 00000000..7fc0de23 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html @@ -0,0 +1,111 @@ +<!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="tabbable">
+ <!-- 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="#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>
+ </ul>
+
+ <!-- tab content -->
+ <div class="tab-content">
+
+ <!-- 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" /> <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" /> <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" /> <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" /> <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.enableTickets"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="useTickets" tabindex="7" /> <span class="help-inline"><wicket:message key="gb.useTicketsDescription"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.enableDocs"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="useDocs" tabindex="8" /> <span class="help-inline"><wicket:message key="gb.useDocsDescription"></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="9" /> <span class="help-inline"><wicket:message key="gb.showRemoteBranchesDescription"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.showReadme"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="showReadme" tabindex="10" /> <span class="help-inline"><wicket:message key="gb.showReadmeDescription"></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="11" /> <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="12" /> <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="13" /> <span class="help-inline"><wicket:message key="gb.maxActivityCommitsDescription"></wicket:message></span></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="14" /></td></tr>
+ </tbody>
+ </table>
+ </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="15" /> </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="16" /></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="17" /> <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="18" /> <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="19" /> <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>
+ </div>
+
+ <!-- federation -->
+ <div class="tab-pane" id="federation">
+ <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="20" /></td></tr>
+ <tr><th><wicket:message key="gb.federationSets"></wicket:message></th><td style="padding:2px;"><span wicket:id="federationSets"></span></td></tr>
+ </tbody>
+ </table>
+ </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>
+ </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> <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>
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="form-actions"><input class="btn btn-primary" type="submit" value="Save" wicket:message="value:gb.save" wicket:id="save" /> <input class="btn" type="submit" value="Cancel" wicket:message="value:gb.cancel" wicket:id="cancel" /></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 new file mode 100644 index 00000000..d68d6550 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -0,0 +1,696 @@ +/*
+ * Copyright 2011 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.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+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;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Button;
+import org.apache.wicket.markup.html.form.CheckBox;
+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.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.util.CollectionModel;
+import org.apache.wicket.model.util.ListModel;
+
+import com.gitblit.Constants;
+import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.Constants.AuthorizationControl;
+import com.gitblit.Constants.FederationStrategy;
+import com.gitblit.Constants.RegistrantType;
+import com.gitblit.GitBlit;
+import com.gitblit.GitBlitException;
+import com.gitblit.Keys;
+import com.gitblit.models.RegistrantAccessPermission;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.StringChoiceRenderer;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.BulletListPanel;
+import com.gitblit.wicket.panels.RegistrantPermissionsPanel;
+
+public class EditRepositoryPage extends RootSubPage {
+
+ private final boolean isCreate;
+
+ private boolean isAdmin;
+
+ RepositoryModel repositoryModel;
+
+ private IModel<String> mailingLists;
+
+ public EditRepositoryPage() {
+ // create constructor
+ super();
+ isCreate = true;
+ RepositoryModel model = new RepositoryModel();
+ String restriction = GitBlit.getString(Keys.git.defaultAccessRestriction, null);
+ model.accessRestriction = AccessRestrictionType.fromName(restriction);
+ String authorization = GitBlit.getString(Keys.git.defaultAuthorizationControl, null);
+ model.authorizationControl = AuthorizationControl.fromName(authorization);
+
+ GitBlitWebSession session = GitBlitWebSession.get();
+ UserModel user = session.getUser();
+ if (user != null && user.canCreate() && !user.canAdmin()) {
+ // personal create permissions, inject personal repository path
+ model.name = user.getPersonalPath() + "/";
+ model.projectPath = user.getPersonalPath();
+ model.addOwner(user.username);
+ // personal repositories are private by default
+ model.accessRestriction = AccessRestrictionType.VIEW;
+ model.authorizationControl = AuthorizationControl.NAMED;
+ }
+
+ setupPage(model);
+ setStatelessHint(false);
+ setOutputMarkupId(true);
+ }
+
+ public EditRepositoryPage(PageParameters params) {
+ // edit constructor
+ super(params);
+ isCreate = false;
+ String name = WicketUtils.getRepositoryName(params);
+ RepositoryModel model = GitBlit.self().getRepositoryModel(name);
+ setupPage(model);
+ setStatelessHint(false);
+ setOutputMarkupId(true);
+ }
+
+ @Override
+ protected boolean requiresPageMap() {
+ return true;
+ }
+
+ protected void setupPage(RepositoryModel model) {
+ this.repositoryModel = model;
+
+ // ensure this user can create or edit this repository
+ checkPermissions(repositoryModel);
+
+ List<String> indexedBranches = new ArrayList<String>();
+ List<String> federationSets = new ArrayList<String>();
+ final List<RegistrantAccessPermission> repositoryUsers = new ArrayList<RegistrantAccessPermission>();
+ final List<RegistrantAccessPermission> repositoryTeams = new ArrayList<RegistrantAccessPermission>();
+ List<String> preReceiveScripts = new ArrayList<String>();
+ List<String> postReceiveScripts = new ArrayList<String>();
+
+ GitBlitWebSession session = GitBlitWebSession.get();
+ final UserModel user = session.getUser() == null ? UserModel.ANONYMOUS : session.getUser();
+ final boolean allowEditName = isCreate || isAdmin || repositoryModel.isUsersPersonalRepository(user.username);
+
+ if (isCreate) {
+ if (user.canAdmin()) {
+ super.setupPage(getString("gb.newRepository"), "");
+ } else {
+ super.setupPage(getString("gb.newRepository"), user.getDisplayName());
+ }
+ } else {
+ super.setupPage(getString("gb.edit"), repositoryModel.name);
+ repositoryUsers.addAll(GitBlit.self().getUserAccessPermissions(repositoryModel));
+ repositoryTeams.addAll(GitBlit.self().getTeamAccessPermissions(repositoryModel));
+ Collections.sort(repositoryUsers);
+ Collections.sort(repositoryTeams);
+
+ federationSets.addAll(repositoryModel.federationSets);
+ if (!ArrayUtils.isEmpty(repositoryModel.indexedBranches)) {
+ indexedBranches.addAll(repositoryModel.indexedBranches);
+ }
+ }
+
+ final String oldName = repositoryModel.name;
+
+ final RegistrantPermissionsPanel usersPalette = new RegistrantPermissionsPanel("users",
+ RegistrantType.USER, GitBlit.self().getAllUsernames(), repositoryUsers, getAccessPermissions());
+ final RegistrantPermissionsPanel teamsPalette = new RegistrantPermissionsPanel("teams",
+ RegistrantType.TEAM, GitBlit.self().getAllTeamnames(), repositoryTeams, getAccessPermissions());
+
+ // owners palette
+ List<String> owners = new ArrayList<String>(repositoryModel.owners);
+ List<String> persons = GitBlit.self().getAllUsernames();
+ final Palette<String> ownersPalette = new Palette<String>("owners", new ListModel<String>(owners), new CollectionModel<String>(
+ persons), new StringChoiceRenderer(), 12, true);
+
+ // indexed local branches palette
+ List<String> allLocalBranches = new ArrayList<String>();
+ allLocalBranches.add(Constants.DEFAULT_BRANCH);
+ allLocalBranches.addAll(repositoryModel.getLocalBranches());
+ boolean luceneEnabled = GitBlit.getBoolean(Keys.web.allowLuceneIndexing, true);
+ final Palette<String> indexedBranchesPalette = new Palette<String>("indexedBranches", new ListModel<String>(
+ indexedBranches), new CollectionModel<String>(allLocalBranches),
+ new StringChoiceRenderer(), 8, false);
+ indexedBranchesPalette.setEnabled(luceneEnabled);
+
+ // federation sets palette
+ List<String> sets = GitBlit.getStrings(Keys.federation.sets);
+ final Palette<String> federationSetsPalette = new Palette<String>("federationSets",
+ new ListModel<String>(federationSets), new CollectionModel<String>(sets),
+ new StringChoiceRenderer(), 8, false);
+
+ // pre-receive palette
+ if (!ArrayUtils.isEmpty(repositoryModel.preReceiveScripts)) {
+ preReceiveScripts.addAll(repositoryModel.preReceiveScripts);
+ }
+ final Palette<String> preReceivePalette = new Palette<String>("preReceiveScripts",
+ new ListModel<String>(preReceiveScripts), new CollectionModel<String>(GitBlit
+ .self().getPreReceiveScriptsUnused(repositoryModel)),
+ new StringChoiceRenderer(), 12, true);
+
+ // post-receive palette
+ if (!ArrayUtils.isEmpty(repositoryModel.postReceiveScripts)) {
+ postReceiveScripts.addAll(repositoryModel.postReceiveScripts);
+ }
+ final Palette<String> postReceivePalette = new Palette<String>("postReceiveScripts",
+ new ListModel<String>(postReceiveScripts), new CollectionModel<String>(GitBlit
+ .self().getPostReceiveScriptsUnused(repositoryModel)),
+ new StringChoiceRenderer(), 12, true);
+
+ // custom fields
+ final Map<String, String> customFieldsMap = GitBlit.getMap(Keys.groovy.customFields);
+ List<String> customKeys = new ArrayList<String>(customFieldsMap.keySet());
+ final ListView<String> customFieldsListView = new ListView<String>("customFieldsListView", customKeys) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void populateItem(ListItem<String> item) {
+ String key = item.getModelObject();
+ item.add(new Label("customFieldLabel", customFieldsMap.get(key)));
+
+ String value = "";
+ if (repositoryModel.customFields != null && repositoryModel.customFields.containsKey(key)) {
+ value = repositoryModel.customFields.get(key);
+ }
+ TextField<String> field = new TextField<String>("customFieldValue", new Model<String>(value));
+ item.add(field);
+ }
+ };
+ customFieldsListView.setReuseItems(true);
+
+ CompoundPropertyModel<RepositoryModel> rModel = new CompoundPropertyModel<RepositoryModel>(
+ repositoryModel);
+ Form<RepositoryModel> form = new Form<RepositoryModel>("editForm", rModel) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void onSubmit() {
+ try {
+ // confirm a repository name was entered
+ if (repositoryModel.name == null && StringUtils.isEmpty(repositoryModel.name)) {
+ error(getString("gb.pleaseSetRepositoryName"));
+ 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
+ if (repositoryModel.accessRestriction == null) {
+ error(getString("gb.selectAccessRestriction"));
+ return;
+ }
+
+ // confirm federation strategy selection
+ if (repositoryModel.federationStrategy == null) {
+ error(getString("gb.selectFederationStrategy"));
+ return;
+ }
+
+ // save federation set preferences
+ if (repositoryModel.federationStrategy.exceeds(FederationStrategy.EXCLUDE)) {
+ repositoryModel.federationSets.clear();
+ Iterator<String> sets = federationSetsPalette.getSelectedChoices();
+ while (sets.hasNext()) {
+ repositoryModel.federationSets.add(sets.next());
+ }
+ }
+
+ // set mailing lists
+ String ml = mailingLists.getObject();
+ if (!StringUtils.isEmpty(ml)) {
+ Set<String> list = new HashSet<String>();
+ for (String address : ml.split("(,|\\s)")) {
+ if (StringUtils.isEmpty(address)) {
+ continue;
+ }
+ list.add(address.toLowerCase());
+ }
+ repositoryModel.mailingLists = new ArrayList<String>(list);
+ }
+
+ // indexed branches
+ List<String> indexedBranches = new ArrayList<String>();
+ Iterator<String> branches = indexedBranchesPalette.getSelectedChoices();
+ while (branches.hasNext()) {
+ indexedBranches.add(branches.next());
+ }
+ repositoryModel.indexedBranches = indexedBranches;
+
+ // owners
+ repositoryModel.owners.clear();
+ Iterator<String> owners = ownersPalette.getSelectedChoices();
+ while (owners.hasNext()) {
+ repositoryModel.addOwner(owners.next());
+ }
+
+ // pre-receive scripts
+ List<String> preReceiveScripts = new ArrayList<String>();
+ Iterator<String> pres = preReceivePalette.getSelectedChoices();
+ while (pres.hasNext()) {
+ preReceiveScripts.add(pres.next());
+ }
+ repositoryModel.preReceiveScripts = preReceiveScripts;
+
+ // post-receive scripts
+ List<String> postReceiveScripts = new ArrayList<String>();
+ Iterator<String> post = postReceivePalette.getSelectedChoices();
+ while (post.hasNext()) {
+ postReceiveScripts.add(post.next());
+ }
+ repositoryModel.postReceiveScripts = postReceiveScripts;
+
+ // custom fields
+ repositoryModel.customFields = new LinkedHashMap<String, String>();
+ for (int i = 0; i < customFieldsListView.size(); i++) {
+ ListItem<String> child = (ListItem<String>) customFieldsListView.get(i);
+ String key = child.getModelObject();
+
+ TextField<String> field = (TextField<String>) child.get("customFieldValue");
+ String value = field.getValue();
+
+ repositoryModel.customFields.put(key, value);
+ }
+
+ // save the repository
+ GitBlit.self().updateRepositoryModel(oldName, repositoryModel, isCreate);
+
+ // repository access permissions
+ if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {
+ GitBlit.self().setUserAccessPermissions(repositoryModel, repositoryUsers);
+ GitBlit.self().setTeamAccessPermissions(repositoryModel, repositoryTeams);
+ }
+ } catch (GitBlitException e) {
+ error(e.getMessage());
+ return;
+ }
+ setRedirect(false);
+ setResponsePage(RepositoriesPage.class);
+ }
+ };
+
+ // 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(GitBlit.getBoolean(Keys.web.allowForking, true)));
+ DropDownChoice<AccessRestrictionType> accessRestriction = new DropDownChoice<AccessRestrictionType>("accessRestriction", Arrays
+ .asList(AccessRestrictionType.values()), 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
+ List<String> availableRefs = new ArrayList<String>();
+ if (!ArrayUtils.isEmpty(repositoryModel.availableRefs)) {
+ availableRefs.addAll(repositoryModel.availableRefs);
+ }
+ form.add(new DropDownChoice<String>("HEAD", availableRefs).setEnabled(availableRefs.size() > 0));
+
+ boolean gcEnabled = GitBlit.getBoolean(Keys.git.enableGarbageCollection, false);
+ 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));
+
+ // 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("useTickets"));
+ form.add(new CheckBox("useDocs"));
+ form.add(new CheckBox("showRemoteBranches"));
+ form.add(new CheckBox("showReadme"));
+ 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()));
+
+ mailingLists = new Model<String>(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? ""
+ : StringUtils.flattenStrings(repositoryModel.mailingLists, " "));
+ form.add(new TextField<String>("mailingLists", mailingLists));
+ form.add(indexedBranchesPalette);
+
+ List<AuthorizationControl> acList = Arrays.asList(AuthorizationControl.values());
+ final RadioChoice<AuthorizationControl> authorizationControl = new RadioChoice<Constants.AuthorizationControl>(
+ "authorizationControl", acList, new AuthorizationControlRenderer());
+ form.add(authorizationControl);
+
+ final CheckBox verifyCommitter = new CheckBox("verifyCommitter");
+ verifyCommitter.setOutputMarkupId(true);
+ form.add(verifyCommitter);
+
+ form.add(usersPalette);
+ form.add(teamsPalette);
+ form.add(federationSetsPalette);
+ form.add(preReceivePalette);
+ form.add(new BulletListPanel("inheritedPreReceive", getString("gb.inherited"), GitBlit.self()
+ .getPreReceiveScriptsInherited(repositoryModel)));
+ form.add(postReceivePalette);
+ form.add(new BulletListPanel("inheritedPostReceive", getString("gb.inherited"), GitBlit.self()
+ .getPostReceiveScriptsInherited(repositoryModel)));
+
+ WebMarkupContainer customFieldsSection = new WebMarkupContainer("customFieldsSection");
+ customFieldsSection.add(customFieldsListView);
+ form.add(customFieldsSection.setVisible(!GitBlit.getString(Keys.groovy.customFields, "").isEmpty()));
+
+ // 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);
+ usersPalette.setEnabled(allowFineGrainedControls);
+ teamsPalette.setEnabled(allowFineGrainedControls);
+ }
+
+ accessRestriction.add(new AjaxFormComponentUpdatingBehavior("onchange") {
+
+ private static final long serialVersionUID = 1L;
+
+ protected void onUpdate(AjaxRequestTarget target) {
+ // enable/disable permissions panel based on access restriction
+ boolean allowAuthorizationControl = repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE);
+ authorizationControl.setEnabled(allowAuthorizationControl);
+ verifyCommitter.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(verifyCommitter);
+ target.addComponent(usersPalette);
+ target.addComponent(teamsPalette);
+ }
+ });
+
+ authorizationControl.add(new AjaxFormChoiceComponentUpdatingBehavior() {
+
+ private static final long serialVersionUID = 1L;
+
+ 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);
+ }
+ });
+
+ form.add(new Button("save"));
+ Button cancel = new Button("cancel") {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onSubmit() {
+ setResponsePage(RepositoriesPage.class);
+ }
+ };
+ cancel.setDefaultFormProcessing(false);
+ form.add(cancel);
+
+ add(form);
+ }
+
+ /**
+ * Unfortunately must repeat part of AuthorizaitonStrategy here because that
+ * mechanism does not take PageParameters into consideration, only page
+ * instantiation.
+ *
+ * Repository Owners should be able to edit their repository.
+ */
+ private void checkPermissions(RepositoryModel model) {
+ boolean authenticateAdmin = GitBlit.getBoolean(Keys.web.authenticateAdminPages, true);
+ boolean allowAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, true);
+
+ GitBlitWebSession session = GitBlitWebSession.get();
+ UserModel user = session.getUser();
+
+ if (allowAdmin) {
+ if (authenticateAdmin) {
+ if (user == null) {
+ // No Login Available
+ error(getString("gb.errorAdminLoginRequired"), true);
+ }
+ if (isCreate) {
+ // Create Repository
+ if (!user.canCreate() && !user.canAdmin()) {
+ // Only administrators or permitted users may create
+ error(getString("gb.errorOnlyAdminMayCreateRepository"), true);
+ }
+ } else {
+ // Edit Repository
+ if (user.canAdmin()) {
+ // Admins can edit everything
+ isAdmin = true;
+ return;
+ } else {
+ if (!model.isOwner(user.username)) {
+ // User is not an Admin nor Owner
+ error(getString("gb.errorOnlyAdminOrOwnerMayEditRepository"), true);
+ }
+ }
+ }
+ }
+ } else {
+ // No Administration Permitted
+ error(getString("gb.errorAdministrationDisabled"), true);
+ }
+ }
+
+ 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> {
+
+ private static final long serialVersionUID = 1L;
+
+ private final Map<FederationStrategy, String> map;
+
+ public FederationTypeRenderer() {
+ map = getFederationTypes();
+ }
+
+ @Override
+ public String getDisplayValue(FederationStrategy type) {
+ return map.get(type);
+ }
+
+ @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);
+ }
+ }
+
+ private class GCPeriodRenderer implements IChoiceRenderer<Integer> {
+
+ private static final long serialVersionUID = 1L;
+
+ public GCPeriodRenderer() {
+ }
+
+ @Override
+ public String getDisplayValue(Integer value) {
+ if (value == 1) {
+ return getString("gb.duration.oneDay");
+ } else {
+ return MessageFormat.format(getString("gb.duration.days"), value);
+ }
+ }
+
+ @Override
+ public String getIdValue(Integer value, int index) {
+ return Integer.toString(index);
+ }
+ }
+
+ private class MaxActivityCommitsRenderer implements IChoiceRenderer<Integer> {
+
+ private static final long serialVersionUID = 1L;
+
+ public MaxActivityCommitsRenderer() {
+ }
+
+ @Override
+ public String getDisplayValue(Integer value) {
+ if (value == -1) {
+ return getString("gb.excludeFromActivity");
+ } else if (value == 0) {
+ return getString("gb.noMaximum");
+ } else {
+ return value + " " + getString("gb.commits");
+ }
+ }
+
+ @Override
+ public String getIdValue(Integer value, int index) {
+ return Integer.toString(index);
+ }
+ }
+
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/EditTeamPage.html b/src/main/java/com/gitblit/wicket/pages/EditTeamPage.html new file mode 100644 index 00000000..a60d1715 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EditTeamPage.html @@ -0,0 +1,66 @@ +<!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();">
+<!-- Team Table -->
+<form style="padding-top:5px;" wicket:id="editForm">
+
+<div class="tabbable">
+ <!-- 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>
+ </ul>
+
+ <!-- tab content -->
+ <div class="tab-content">
+
+ <!-- general tab -->
+ <div class="tab-pane active" id="general">
+ <table class="plain">
+ <tbody class="settings">
+ <tr><th><wicket:message key="gb.teamName"></wicket:message></th><td class="edit"><input type="text" wicket:id="name" id="name" size="30" tabindex="1" /></td></tr>
+ <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canAdmin" tabindex="2" /> <span class="help-inline"><wicket:message key="gb.canAdminDescription"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.canCreate"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canCreate" tabindex="3" /> <span class="help-inline"><wicket:message key="gb.canCreateDescription"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.canFork"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canFork" tabindex="4" /> <span class="help-inline"><wicket:message key="gb.canForkDescription"></wicket:message></span></label></td></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="5" /></td></tr>
+ </tbody>
+ </table>
+ </div>
+
+ <!-- access permissions tab -->
+ <div class="tab-pane" id="permissions">
+ <table class="plain">
+ <tbody class="settings">
+ <tr><th><wicket:message key="gb.teamMembers"></wicket:message></th><td style="padding:2px;"><span wicket:id="users"></span></td></tr>
+ <tr><td colspan="2"><hr></hr></td></tr>
+ <tr><th><wicket:message key="gb.repositoryPermissions"></wicket:message></th><td style="padding:2px;"><span wicket:id="repositories"></span></td></tr>
+ </tbody>
+ </table>
+ </div>
+
+ <!-- hooks -->
+ <div class="tab-pane" id="hooks">
+ <table class="plain">
+ <tbody class="settings">
+ <tr><td colspan="2" style="padding-top:10px;"><h3><wicket:message key="gb.hookScripts"></wicket:message> <small><wicket:message key="gb.hookScriptsDescription"></wicket:message></small></h3></td></tr>
+ <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>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
+
+<div class="row">
+ <div class="form-actions"><input class="btn btn-primary" type="submit" value="Save" wicket:message="value:gb.save" wicket:id="save" tabindex="6" /> <input class="btn" type="submit" value="Cancel" wicket:message="value:gb.cancel" wicket:id="cancel" tabindex="7" /></div>
+</div>
+
+</form>
+</body>
+</wicket:extend>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java b/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java new file mode 100644 index 00000000..8344d387 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java @@ -0,0 +1,250 @@ +/*
+ * Copyright 2011 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.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.behavior.SimpleAttributeModifier;
+import org.apache.wicket.extensions.markup.html.form.palette.Palette;
+import org.apache.wicket.markup.html.form.Button;
+import org.apache.wicket.markup.html.form.CheckBox;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.TextField;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.util.CollectionModel;
+import org.apache.wicket.model.util.ListModel;
+
+import com.gitblit.GitBlit;
+import com.gitblit.GitBlitException;
+import com.gitblit.Keys;
+import com.gitblit.Constants.RegistrantType;
+import com.gitblit.models.RegistrantAccessPermission;
+import com.gitblit.models.TeamModel;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.RequiresAdminRole;
+import com.gitblit.wicket.StringChoiceRenderer;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.BulletListPanel;
+import com.gitblit.wicket.panels.RegistrantPermissionsPanel;
+
+@RequiresAdminRole
+public class EditTeamPage extends RootSubPage {
+
+ private final boolean isCreate;
+
+ private IModel<String> mailingLists;
+
+ public EditTeamPage() {
+ // create constructor
+ super();
+ isCreate = true;
+ setupPage(new TeamModel(""));
+ setStatelessHint(false);
+ setOutputMarkupId(true);
+ }
+
+ public EditTeamPage(PageParameters params) {
+ // edit constructor
+ super(params);
+ isCreate = false;
+ String name = WicketUtils.getTeamname(params);
+ TeamModel model = GitBlit.self().getTeamModel(name);
+ setupPage(model);
+ setStatelessHint(false);
+ setOutputMarkupId(true);
+ }
+
+ @Override
+ protected boolean requiresPageMap() {
+ return true;
+ }
+
+ protected void setupPage(final TeamModel teamModel) {
+ if (isCreate) {
+ super.setupPage(getString("gb.newTeam"), "");
+ } else {
+ super.setupPage(getString("gb.edit"), teamModel.name);
+ }
+
+ CompoundPropertyModel<TeamModel> model = new CompoundPropertyModel<TeamModel>(teamModel);
+
+ List<String> repos = getAccessRestrictedRepositoryList(true, null);
+
+ List<String> teamUsers = new ArrayList<String>(teamModel.users);
+ Collections.sort(teamUsers);
+ List<String> preReceiveScripts = new ArrayList<String>();
+ List<String> postReceiveScripts = new ArrayList<String>();
+
+ final String oldName = teamModel.name;
+ final List<RegistrantAccessPermission> permissions = teamModel.getRepositoryPermissions();
+
+ // users palette
+ final Palette<String> users = new Palette<String>("users", new ListModel<String>(
+ new ArrayList<String>(teamUsers)), new CollectionModel<String>(GitBlit.self()
+ .getAllUsernames()), new StringChoiceRenderer(), 10, false);
+
+ // pre-receive palette
+ if (teamModel.preReceiveScripts != null) {
+ preReceiveScripts.addAll(teamModel.preReceiveScripts);
+ }
+ final Palette<String> preReceivePalette = new Palette<String>("preReceiveScripts",
+ new ListModel<String>(preReceiveScripts), new CollectionModel<String>(GitBlit
+ .self().getPreReceiveScriptsUnused(null)), new StringChoiceRenderer(),
+ 12, true);
+
+ // post-receive palette
+ if (teamModel.postReceiveScripts != null) {
+ postReceiveScripts.addAll(teamModel.postReceiveScripts);
+ }
+ final Palette<String> postReceivePalette = new Palette<String>("postReceiveScripts",
+ new ListModel<String>(postReceiveScripts), new CollectionModel<String>(GitBlit
+ .self().getPostReceiveScriptsUnused(null)), new StringChoiceRenderer(),
+ 12, true);
+
+ Form<TeamModel> form = new Form<TeamModel>("editForm", model) {
+
+ private static final long serialVersionUID = 1L;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.wicket.markup.html.form.Form#onSubmit()
+ */
+ @Override
+ protected void onSubmit() {
+ String teamname = teamModel.name;
+ if (StringUtils.isEmpty(teamname)) {
+ error(getString("gb.pleaseSetTeamName"));
+ return;
+ }
+ if (isCreate) {
+ TeamModel model = GitBlit.self().getTeamModel(teamname);
+ if (model != null) {
+ error(MessageFormat.format(getString("gb.teamNameUnavailable"), teamname));
+ return;
+ }
+ }
+ // update team permissions
+ for (RegistrantAccessPermission repositoryPermission : permissions) {
+ teamModel.setRepositoryPermission(repositoryPermission.registrant, repositoryPermission.permission);
+ }
+
+ Iterator<String> selectedUsers = users.getSelectedChoices();
+ List<String> members = new ArrayList<String>();
+ while (selectedUsers.hasNext()) {
+ members.add(selectedUsers.next().toLowerCase());
+ }
+ teamModel.users.clear();
+ teamModel.users.addAll(members);
+
+ // set mailing lists
+ String ml = mailingLists.getObject();
+ if (!StringUtils.isEmpty(ml)) {
+ Set<String> list = new HashSet<String>();
+ for (String address : ml.split("(,|\\s)")) {
+ if (StringUtils.isEmpty(address)) {
+ continue;
+ }
+ list.add(address.toLowerCase());
+ }
+ teamModel.mailingLists.clear();
+ teamModel.mailingLists.addAll(list);
+ }
+
+ // pre-receive scripts
+ List<String> preReceiveScripts = new ArrayList<String>();
+ Iterator<String> pres = preReceivePalette.getSelectedChoices();
+ while (pres.hasNext()) {
+ preReceiveScripts.add(pres.next());
+ }
+ teamModel.preReceiveScripts.clear();
+ teamModel.preReceiveScripts.addAll(preReceiveScripts);
+
+ // post-receive scripts
+ List<String> postReceiveScripts = new ArrayList<String>();
+ Iterator<String> post = postReceivePalette.getSelectedChoices();
+ while (post.hasNext()) {
+ postReceiveScripts.add(post.next());
+ }
+ teamModel.postReceiveScripts.clear();
+ teamModel.postReceiveScripts.addAll(postReceiveScripts);
+
+ try {
+ GitBlit.self().updateTeamModel(oldName, teamModel, isCreate);
+ } catch (GitBlitException e) {
+ error(e.getMessage());
+ return;
+ }
+ setRedirect(false);
+ if (isCreate) {
+ // create another team
+ info(MessageFormat.format(getString("gb.teamCreated"),
+ teamModel.name));
+ }
+ // back to users page
+ setResponsePage(UsersPage.class);
+ }
+ };
+
+ // do not let the browser pre-populate these fields
+ form.add(new SimpleAttributeModifier("autocomplete", "off"));
+
+ // not all user services support manipulating team memberships
+ boolean editMemberships = GitBlit.self().supportsTeamMembershipChanges(null);
+
+ // field names reflective match TeamModel fields
+ form.add(new TextField<String>("name"));
+ form.add(new CheckBox("canAdmin"));
+ form.add(new CheckBox("canFork").setEnabled(GitBlit.getBoolean(Keys.web.allowForking, true)));
+ form.add(new CheckBox("canCreate"));
+ form.add(users.setEnabled(editMemberships));
+ mailingLists = new Model<String>(teamModel.mailingLists == null ? ""
+ : StringUtils.flattenStrings(teamModel.mailingLists, " "));
+ form.add(new TextField<String>("mailingLists", mailingLists));
+
+ form.add(new RegistrantPermissionsPanel("repositories", RegistrantType.REPOSITORY,
+ repos, permissions, getAccessPermissions()));
+ form.add(preReceivePalette);
+ form.add(new BulletListPanel("inheritedPreReceive", "inherited", GitBlit.self()
+ .getPreReceiveScriptsInherited(null)));
+ form.add(postReceivePalette);
+ form.add(new BulletListPanel("inheritedPostReceive", "inherited", GitBlit.self()
+ .getPostReceiveScriptsInherited(null)));
+
+ form.add(new Button("save"));
+ Button cancel = new Button("cancel") {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onSubmit() {
+ setResponsePage(UsersPage.class);
+ }
+ };
+ cancel.setDefaultFormProcessing(false);
+ form.add(cancel);
+
+ add(form);
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/EditUserPage.html b/src/main/java/com/gitblit/wicket/pages/EditUserPage.html new file mode 100644 index 00000000..e79011c8 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EditUserPage.html @@ -0,0 +1,78 @@ +<!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('username').focus();">
+<!-- User Table -->
+<form style="padding-top:5px;" wicket:id="editForm">
+
+<div class="tabbable">
+ <!-- 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="#attributes" data-toggle="tab"><wicket:message key="gb.attributes"></wicket:message></a></li>
+ <li><a href="#permissions" data-toggle="tab"><wicket:message key="gb.accessPermissions"></wicket:message></a></li>
+ </ul>
+
+ <!-- tab content -->
+ <div class="tab-content">
+
+ <!-- general tab -->
+ <div class="tab-pane active" id="general">
+ <table class="plain">
+ <tbody class="settings">
+ <tr><th><wicket:message key="gb.username"></wicket:message></th><td class="edit"><input type="text" wicket:id="username" id="username" size="30" tabindex="1" /></td></tr>
+ <tr><th><wicket:message key="gb.password"></wicket:message></th><td class="edit"><input type="password" wicket:id="password" size="30" tabindex="2" /></td></tr>
+ <tr><th><wicket:message key="gb.confirmPassword"></wicket:message></th><td class="edit"><input type="password" wicket:id="confirmPassword" size="30" tabindex="3" /></td></tr>
+ <tr><th><wicket:message key="gb.displayName"></wicket:message></th><td class="edit"><input type="text" wicket:id="displayName" size="30" tabindex="4" /></td></tr>
+ <tr><th><wicket:message key="gb.emailAddress"></wicket:message></th><td class="edit"><input type="text" wicket:id="emailAddress" size="30" tabindex="5" /></td></tr>
+ <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canAdmin" tabindex="6" /> <span class="help-inline"><wicket:message key="gb.canAdminDescription"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.canCreate"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canCreate" tabindex="7" /> <span class="help-inline"><wicket:message key="gb.canCreateDescription"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.canFork"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canFork" tabindex="8" /> <span class="help-inline"><wicket:message key="gb.canForkDescription"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.excludeFromFederation"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="excludeFromFederation" tabindex="9" /> <span class="help-inline"><wicket:message key="gb.excludeFromFederationDescription"></wicket:message></span></label></td></tr>
+ </tbody>
+ </table>
+ </div>
+
+ <!-- attributes tab -->
+ <div class="tab-pane" id="attributes">
+ <table class="plain">
+ <tbody class="settings">
+ <tr><th><wicket:message key="gb.organizationalUnit"></wicket:message> (OU)</th><td class="edit"><input type="text" wicket:id="organizationalUnit" size="30" tabindex="1" /></td></tr>
+ <tr><th><wicket:message key="gb.organization"></wicket:message> (O)</th><td class="edit"><input type="text" wicket:id="organization" size="30" tabindex="2" /></td></tr>
+ <tr><th><wicket:message key="gb.locality"></wicket:message> (L)</th><td class="edit"><input type="text" wicket:id="locality" size="30" tabindex="3" /></td></tr>
+ <tr><th><wicket:message key="gb.stateProvince"></wicket:message> (ST)</th><td class="edit"><input type="text" wicket:id="stateProvince" size="30" tabindex="4" /></td></tr>
+ <tr><th><wicket:message key="gb.countryCode"></wicket:message> (C)</th><td class="edit"><input type="text" wicket:id="countryCode" size="15 " tabindex="5" /></td></tr>
+ </tbody>
+ </table>
+ </div>
+
+ <!-- access permissions tab -->
+ <div class="tab-pane" id="permissions">
+ <table class="plain">
+ <tbody class="settings">
+ <tr><th><wicket:message key="gb.teamMemberships"></wicket:message></th><td style="padding:2px;"><span wicket:id="teams"></span></td></tr>
+ <tr><td colspan="2"><hr></hr></td></tr>
+ <tr><th><wicket:message key="gb.repositoryPermissions"></wicket:message></th>
+ <td style="padding:2px;">
+ <div wicket:id="repositories"></div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
+
+<div class="row">
+ <div class="form-actions"><input class="btn btn-primary" type="submit" value="Save" wicket:message="value:gb.save" wicket:id="save" tabindex="9" /> <input class="btn" type="submit" value="Cancel" wicket:message="value:gb.cancel" wicket:id="cancel" tabindex="10" /></div>
+</div>
+
+</form>
+</body>
+
+</wicket:extend>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EditUserPage.java b/src/main/java/com/gitblit/wicket/pages/EditUserPage.java new file mode 100644 index 00000000..c060f237 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EditUserPage.java @@ -0,0 +1,261 @@ +/*
+ * Copyright 2011 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.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.behavior.SimpleAttributeModifier;
+import org.apache.wicket.extensions.markup.html.form.palette.Palette;
+import org.apache.wicket.markup.html.form.Button;
+import org.apache.wicket.markup.html.form.CheckBox;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.PasswordTextField;
+import org.apache.wicket.markup.html.form.TextField;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.util.CollectionModel;
+import org.apache.wicket.model.util.ListModel;
+
+import com.gitblit.Constants.RegistrantType;
+import com.gitblit.GitBlit;
+import com.gitblit.GitBlitException;
+import com.gitblit.Keys;
+import com.gitblit.models.RegistrantAccessPermission;
+import com.gitblit.models.TeamModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.RequiresAdminRole;
+import com.gitblit.wicket.StringChoiceRenderer;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.RegistrantPermissionsPanel;
+
+@RequiresAdminRole
+public class EditUserPage extends RootSubPage {
+
+ private final boolean isCreate;
+
+ public EditUserPage() {
+ // create constructor
+ super();
+ if (!GitBlit.self().supportsAddUser()) {
+ error(MessageFormat.format(getString("gb.userServiceDoesNotPermitAddUser"),
+ GitBlit.getString(Keys.realm.userService, "${baseFolder}/users.conf")), true);
+ }
+ isCreate = true;
+ setupPage(new UserModel(""));
+ setStatelessHint(false);
+ setOutputMarkupId(true);
+ }
+
+ public EditUserPage(PageParameters params) {
+ // edit constructor
+ super(params);
+ isCreate = false;
+ String name = WicketUtils.getUsername(params);
+ UserModel model = GitBlit.self().getUserModel(name);
+ setupPage(model);
+ setStatelessHint(false);
+ setOutputMarkupId(true);
+ }
+
+ @Override
+ protected boolean requiresPageMap() {
+ return true;
+ }
+
+ protected void setupPage(final UserModel userModel) {
+ if (isCreate) {
+ super.setupPage(getString("gb.newUser"), "");
+ } else {
+ super.setupPage(getString("gb.edit"), userModel.username);
+ }
+
+ final Model<String> confirmPassword = new Model<String>(
+ StringUtils.isEmpty(userModel.password) ? "" : userModel.password);
+ CompoundPropertyModel<UserModel> model = new CompoundPropertyModel<UserModel>(userModel);
+
+ // build list of projects including all repositories wildcards
+ List<String> repos = getAccessRestrictedRepositoryList(true, userModel);
+
+ List<String> userTeams = new ArrayList<String>();
+ for (TeamModel team : userModel.teams) {
+ userTeams.add(team.name);
+ }
+ Collections.sort(userTeams);
+
+ final String oldName = userModel.username;
+ final List<RegistrantAccessPermission> permissions = GitBlit.self().getUserAccessPermissions(userModel);
+
+ final Palette<String> teams = new Palette<String>("teams", new ListModel<String>(
+ new ArrayList<String>(userTeams)), new CollectionModel<String>(GitBlit.self()
+ .getAllTeamnames()), new StringChoiceRenderer(), 10, false);
+ Form<UserModel> form = new Form<UserModel>("editForm", model) {
+
+ private static final long serialVersionUID = 1L;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.wicket.markup.html.form.Form#onSubmit()
+ */
+ @Override
+ protected void onSubmit() {
+ if (StringUtils.isEmpty(userModel.username)) {
+ error(getString("gb.pleaseSetUsername"));
+ return;
+ }
+ // force username to lower-case
+ userModel.username = userModel.username.toLowerCase();
+ String username = userModel.username;
+ if (isCreate) {
+ UserModel model = GitBlit.self().getUserModel(username);
+ if (model != null) {
+ error(MessageFormat.format(getString("gb.usernameUnavailable"), username));
+ return;
+ }
+ }
+ boolean rename = !StringUtils.isEmpty(oldName)
+ && !oldName.equalsIgnoreCase(username);
+ if (GitBlit.self().supportsCredentialChanges(userModel)) {
+ if (!userModel.password.equals(confirmPassword.getObject())) {
+ error(getString("gb.passwordsDoNotMatch"));
+ return;
+ }
+ String password = userModel.password;
+ if (!password.toUpperCase().startsWith(StringUtils.MD5_TYPE)
+ && !password.toUpperCase().startsWith(StringUtils.COMBINED_MD5_TYPE)) {
+ // This is a plain text password.
+ // Check length.
+ int minLength = GitBlit.getInteger(Keys.realm.minPasswordLength, 5);
+ if (minLength < 4) {
+ minLength = 4;
+ }
+ if (password.trim().length() < minLength) {
+ error(MessageFormat.format(getString("gb.passwordTooShort"),
+ minLength));
+ return;
+ }
+
+ // Optionally store the password MD5 digest.
+ String type = GitBlit.getString(Keys.realm.passwordStorage, "md5");
+ if (type.equalsIgnoreCase("md5")) {
+ // store MD5 digest of password
+ userModel.password = StringUtils.MD5_TYPE
+ + StringUtils.getMD5(userModel.password);
+ } else if (type.equalsIgnoreCase("combined-md5")) {
+ // store MD5 digest of username+password
+ userModel.password = StringUtils.COMBINED_MD5_TYPE
+ + StringUtils.getMD5(username + userModel.password);
+ }
+ } else if (rename
+ && password.toUpperCase().startsWith(StringUtils.COMBINED_MD5_TYPE)) {
+ error(getString("gb.combinedMd5Rename"));
+ return;
+ }
+ }
+
+ // update user permissions
+ for (RegistrantAccessPermission repositoryPermission : permissions) {
+ userModel.setRepositoryPermission(repositoryPermission.registrant, repositoryPermission.permission);
+ }
+
+ Iterator<String> selectedTeams = teams.getSelectedChoices();
+ userModel.teams.clear();
+ while (selectedTeams.hasNext()) {
+ TeamModel team = GitBlit.self().getTeamModel(selectedTeams.next());
+ if (team == null) {
+ continue;
+ }
+ userModel.teams.add(team);
+ }
+
+ try {
+ GitBlit.self().updateUserModel(oldName, userModel, isCreate);
+ } catch (GitBlitException e) {
+ error(e.getMessage());
+ return;
+ }
+ setRedirect(false);
+ if (isCreate) {
+ // create another user
+ info(MessageFormat.format(getString("gb.userCreated"),
+ userModel.username));
+ setResponsePage(EditUserPage.class);
+ } else {
+ // back to users page
+ setResponsePage(UsersPage.class);
+ }
+ }
+ };
+
+ // do not let the browser pre-populate these fields
+ form.add(new SimpleAttributeModifier("autocomplete", "off"));
+
+ // not all user services support manipulating username and password
+ boolean editCredentials = GitBlit.self().supportsCredentialChanges(userModel);
+
+ // not all user services support manipulating display name
+ boolean editDisplayName = GitBlit.self().supportsDisplayNameChanges(userModel);
+
+ // not all user services support manipulating email address
+ boolean editEmailAddress = GitBlit.self().supportsEmailAddressChanges(userModel);
+
+ // not all user services support manipulating team memberships
+ boolean editTeams = GitBlit.self().supportsTeamMembershipChanges(userModel);
+
+ // field names reflective match UserModel fields
+ form.add(new TextField<String>("username").setEnabled(editCredentials));
+ PasswordTextField passwordField = new PasswordTextField("password");
+ passwordField.setResetPassword(false);
+ form.add(passwordField.setEnabled(editCredentials));
+ PasswordTextField confirmPasswordField = new PasswordTextField("confirmPassword",
+ confirmPassword);
+ confirmPasswordField.setResetPassword(false);
+ form.add(confirmPasswordField.setEnabled(editCredentials));
+ form.add(new TextField<String>("displayName").setEnabled(editDisplayName));
+ form.add(new TextField<String>("emailAddress").setEnabled(editEmailAddress));
+ form.add(new CheckBox("canAdmin"));
+ form.add(new CheckBox("canFork").setEnabled(GitBlit.getBoolean(Keys.web.allowForking, true)));
+ form.add(new CheckBox("canCreate"));
+ form.add(new CheckBox("excludeFromFederation"));
+ form.add(new RegistrantPermissionsPanel("repositories", RegistrantType.REPOSITORY, repos, permissions, getAccessPermissions()));
+ form.add(teams.setEnabled(editTeams));
+
+ form.add(new TextField<String>("organizationalUnit").setEnabled(editDisplayName));
+ form.add(new TextField<String>("organization").setEnabled(editDisplayName));
+ form.add(new TextField<String>("locality").setEnabled(editDisplayName));
+ form.add(new TextField<String>("stateProvince").setEnabled(editDisplayName));
+ form.add(new TextField<String>("countryCode").setEnabled(editDisplayName));
+ form.add(new Button("save"));
+ Button cancel = new Button("cancel") {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onSubmit() {
+ setResponsePage(UsersPage.class);
+ }
+ };
+ cancel.setDefaultFormProcessing(false);
+ form.add(cancel);
+
+ add(form);
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.html new file mode 100644 index 00000000..d46a5ded --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.html @@ -0,0 +1,53 @@ +<!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:extend>
+
+ <h2>Empty Repository</h2>
+ <p></p>
+ <div class="row">
+ <div class="span10">
+ <div class="alert alert-success">
+ <span wicket:id="repository" style="font-weight: bold;">[repository]</span> is an empty repository and can not be viewed by Gitblit.
+ <p></p>
+ Please push some commits to <span wicket:id="pushurl"></span>
+ <p></p>
+ <hr/>
+ After you have pushed commits you may <b>refresh</b> this page to view your repository.
+ </div>
+ </div>
+ </div>
+
+ <h3>Git Command-Line Syntax</h3>
+ <span style="padding-bottom:5px;">If you do not have a local Git repository, then you should clone this repository, commit some files, and then push your commits back to Gitblit.</span>
+ <p></p>
+ <pre style="padding: 5px 30px;" wicket:id="cloneSyntax"></pre>
+ <p></p>
+ <span style="padding-bottom:5px;">If you already have a local Git repository with commits, then you may add this repository as a remote and push to it.</span>
+ <p></p>
+ <pre wicket:id="remoteSyntax" style="padding: 5px 30px;"></pre>
+ <p></p>
+ <h3>Learn Git</h3>
+ If you are unsure how to use this information, consider reviewing the <a href="http://book.git-scm.com">Git Community Book</a> or <a href="http://progit.org/book" target="_blank">Pro Git</a> for a better understanding on how to use Git.
+ <p></p>
+ <h4>Open Source Git Clients</h4>
+ <ul>
+ <li><a href="http://git-scm.com">Git</a> - the official, command-line Git</li>
+ <li><a href="http://tortoisegit.googlecode.com">TortoiseGit</a> - Windows file explorer integration (requires official, command-line Git)</li>
+ <li><a href="http://eclipse.org/egit">Eclipse/EGit</a> - Git for the Eclipse IDE (based on JGit, like Gitblit)</li>
+ <li><a href="https://code.google.com/p/gitextensions/">Git Extensions</a> - C# frontend for Git that features Windows Explorer and Visual Studio integration</li>
+ <li><a href="http://gitx.laullon.com/">GitX (L)</a> - a Mac OS X Git client</li>
+ </ul>
+ <p></p>
+ <h4>Commercial/Closed-Source Git Clients</h4>
+ <ul>
+ <li><a href="http://www.syntevo.com/smartgit">SmartGit</a> - A Java Git, Mercurial, and SVN client application (requires official, command-line Git)</li>
+ <li><a href="http://www.sourcetreeapp.com/">SourceTree</a> - A free Mac Client for Git, Mercurial, and SVN</li>
+ </ul>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java new file mode 100644 index 00000000..be0dad9e --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage.java @@ -0,0 +1,67 @@ +/*
+ * Copyright 2011 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.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.wicket.GitblitRedirectException;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.RepositoryUrlPanel;
+
+public class EmptyRepositoryPage extends RootPage {
+
+ public EmptyRepositoryPage(PageParameters params) {
+ super(params);
+
+ setVersioned(false);
+
+ String repositoryName = WicketUtils.getRepositoryName(params);
+ RepositoryModel repository = GitBlit.self().getRepositoryModel(repositoryName);
+ if (repository == null) {
+ error(getString("gb.canNotLoadRepository") + " " + repositoryName, true);
+ }
+
+ if (repository.hasCommits) {
+ // redirect to the summary page if this repository is not empty
+ throw new GitblitRedirectException(SummaryPage.class, params);
+ }
+
+ setupPage(repositoryName, getString("gb.emptyRepository"));
+
+ List<String> repositoryUrls = new ArrayList<String>();
+
+ if (GitBlit.getBoolean(Keys.git.enableGitServlet, true)) {
+ // add the Gitblit repository url
+ repositoryUrls.add(getRepositoryUrl(repository));
+ }
+ repositoryUrls.addAll(GitBlit.self().getOtherCloneUrls(repositoryName));
+
+ String primaryUrl = ArrayUtils.isEmpty(repositoryUrls) ? "" : repositoryUrls.get(0);
+ add(new Label("repository", repositoryName));
+ add(new RepositoryUrlPanel("pushurl", primaryUrl));
+ add(new Label("cloneSyntax", MessageFormat.format("git clone {0}", repositoryUrls.get(0))));
+ add(new Label("remoteSyntax", MessageFormat.format("git remote add gitblit {0}\ngit push gitblit master", primaryUrl)));
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_es.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_es.html new file mode 100644 index 00000000..2849fc70 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_es.html @@ -0,0 +1,56 @@ +
+
+<!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="es">
+
+<body>
+<wicket:extend>
+
+ <h2>Repositorio Vacío</h2>
+ <p></p>
+ <div class="row">
+ <div class="span7">
+ <div class="alert alert-success">
+ <span wicket:id="repository" style="font-weight: bold;">[repository]</span> es un repositorio vacío y no puede ser visto en Gitblit.
+ <p></p>
+ Por favor, empuja algunas consignas a <span wicket:id="pushurl"></span>
+ <p></p>
+ <hr/>
+ Después de empujar tus consignas puedes <b>refrescar</b> ésta página para ver tu Repositorio.
+ </div>
+ </div>
+ </div>
+
+ <h3>Sintaxis de la Línea de Comandos de Git</h3>
+ <span style="padding-bottom:5px;">Si no tienes un Repositiorio local Git, puedes clonar éste, consignar algunos archivos, y después empujar las consignas de vuelta a Gitblit.</span>
+ <p></p>
+ <pre style="padding: 5px 30px;" wicket:id="cloneSyntax"></pre>
+ <p></p>
+ <span style="padding-bottom:5px;">Si ya tienes un repositorio local Git con algunas consignas, puedes añadir éste como remoto y empujar desde allí.</span>
+ <p></p>
+ <pre style="padding: 5px 30px;" wicket:id="remoteSyntax"></pre>
+ <p></p>
+ <h3>Aprender Git</h3>
+ Si no estás seguro de como usar esta información, échale un vistazo al <a href="http://book.git-scm.com">Libro de la cominidad Git</a> o <a href="http://progit.org/book" target="_blank">Pro Git</a> para una mejor compresión de como usar Git.
+ <p></p>
+ <h4>Clientes Git de Código abierto.</h4>
+ <ul>
+ <li><a href="http://git-scm.com">Git</a> - El Git oficial en línea de comandos</li>
+ <li><a href="http://tortoisegit.googlecode.com">TortoiseGit</a> - Explorador de archivos integrado en Windows (necesita Git oficial en línea de comandos)</li>
+ <li><a href="http://eclipse.org/egit">Eclipse/EGit</a> - Git para el IDE de Eclipse (basado en JGit, como Gitblit)</li>
+ <li><a href="https://code.google.com/p/gitextensions/">Git Extensions</a> - Interfaz de usuario gráfico Git en C# con integración en IE y en Visual Studio</li>
+ <li><a href="http://gitx.laullon.com/">GitX (L)</a> - Cliente Git para Mac OS X</li>
+ </ul>
+ <p></p>
+ <h4>Clientes Git comerciales</h4>
+ <ul>
+ <li><a href="http://www.syntevo.com/smartgit">SmartGit</a> - aplicación Java (necesita Git oficial en línea de comandos)</li>
+ <li><a href="http://www.sourcetreeapp.com/">SourceTree</a> - Un cliente Git gratuito para Mac, Mercurial, y SVN</li>
+ </ul>
+</wicket:extend>
+</body>
+</html>
+
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html new file mode 100644 index 00000000..591335e4 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html @@ -0,0 +1,57 @@ +<!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:extend> + + <h2>비어있는 ì €ìž¥ì†Œ</h2> + <p></p> + <div class="row"> + <div class="span10"> + <div class="alert alert-success"> + <span wicket:id="repository" style="font-weight: bold;">[repository]</span> ì €ìž¥ì†ŒëŠ” 비어 있어서 Gitblit ì—ì„œ ë³¼ 수 없습니다. + <p></p> + ì´ Git url ì— ì»¤ë°‹í•´ 주세요. <span wicket:id="pushurl"></span> + <p></p> + <hr/> + After you have pushed commits you may <b>refresh</b> this page to view your repository. + </div> + </div> + </div> + + <p></p> + <h3>Git ëª…ë ¹ì–´</h3> + <span style="padding-bottom:5px;">로컬 Git ì €ìž¥ì†Œê°€ 없다면, ì´ ì €ìž¥ì†Œë¥¼ í´ë¡ (clone) í•œ 후, 몇 파ì¼ì„ ì»¤ë°‹í•˜ê³ , ê·¸ ì»¤ë°‹ì„ Gitblit ì— í‘¸ì‹œ(push) 하세요.</span> + <p></p> + <pre style="padding: 5px 30px;" wicket:id="cloneSyntax"></pre> + <p></p> + <span style="padding-bottom:5px;">만약 ì»¤ë°‹ëœ ë¡œì»¬ Git ì €ìž¥ì†Œê°€ 있다면, 다ìŒê³¼ ê°™ì´ ì €ìž¥ì†Œì— ë¦¬ëª¨íŠ¸ë¥¼ ì¶”ê°€í•˜ê³ í‘¸ì‹œ(push)í• ìˆ˜ 있습니다.</span> + <p></p> + <pre style="padding: 5px 30px;" wicket:id="remoteSyntax"></pre> + <p></p> + <h3>Git 배우기</h3> + 만약 ì‚¬ìš©ë²•ì— ìžì‹ ì´ ì—†ë‹¤ë©´, Git ì‚¬ìš©ë²•ì„ ë” ìž˜ ì´í•´í•˜ê¸° 위해 + <a href="http://book.git-scm.com">Git Community Book</a> ë˜ëŠ” + <a href="http://progit.org/book" target="_blank">Pro Git</a>, + <a href="http://dogfeet.github.com/articles/2012/progit.html" target="_blank">Pro Git 한글</a> ì„ ë³¼ ê²ƒì„ ê³ ë ¤í•´ 보세요. + <p></p> + <h4>오픈소스 Git í´ë¼ì´ì–¸íŠ¸</h4> + <ul> + <li><a href="http://git-scm.com">Git</a> - ëª…ë ¹ì–´ 기반 ê³µì‹ Git</li> + <li><a href="http://tortoisegit.googlecode.com">TortoiseGit</a> - 윈ë„ì˜ íŒŒì¼ íƒìƒ‰ê¸°ì— í†µí•©ëœ UI í´ë¼ì´ì–¸íŠ¸ (ëª…ë ¹ì–´ 기반 ê³µì‹ Git í•„ìš”)</li> + <li><a href="http://eclipse.org/egit">Eclipse/EGit</a> - ì´í´ë¦½ìŠ¤ IDE í”ŒëŸ¬ê·¸ì¸ (Gitblit ê³¼ ê°™ì€ JGit 기반)</li> + <li><a href="https://code.google.com/p/gitextensions/">Git Extensions</a> - C# frontend for Git that features Windows Explorer and Visual Studio integration</li> + <li><a href="http://gitx.laullon.com/">GitX (L)</a> - a Mac OS X Git client</li> + </ul> + <p></p> + <h4>ìœ ë£Œ Git í´ë¼ì´ì–¸íŠ¸</h4> + <ul> + <li><a href="http://www.syntevo.com/smartgit">SmartGit</a> - ìžë°” 어플리케ì´ì…˜ (ëª…ë ¹ì–´ 기반 ê³µì‹ Git í•„ìš”)</li> + <li><a href="http://www.sourcetreeapp.com/">SourceTree</a> - A free Mac Client for Git, Mercurial, and SVN</li> + </ul> +</wicket:extend> +</body> +</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_nl.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_nl.html new file mode 100644 index 00000000..a8ee2e25 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_nl.html @@ -0,0 +1,53 @@ +<!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="nl"
+ lang="nl">
+
+<body>
+<wicket:extend>
+
+ <h2>Empty Repository</h2>
+ <p></p>
+ <div class="row">
+ <div class="span10">
+ <div class="alert alert-success">
+ <span wicket:id="repository" style="font-weight: bold;">[repository]</span> is een lege repositorie en kan niet bekeken worden door Gitblit.
+ <p></p>
+ Push aub een paar commitsome commits naar <span wicket:id="pushurl"></span>
+ <p></p>
+ <hr/>
+ Nadat u een paar commits gepushed hebt kunt u deze pagina <b>verversen</b> om de repository te bekijken.
+ </div>
+ </div>
+ </div>
+
+ <h3>Git Command-Line Syntax</h3>
+ <span style="padding-bottom:5px;">Als u geen lokale Git repositorie heeft, kunt u deze repository clonen, er een paar bestanden naar committen en deze commits teug pushen naar Gitblit.</span>
+ <p></p>
+ <pre style="padding: 5px 30px;" wicket:id="cloneSyntax"></pre>
+ <p></p>
+ <span style="padding-bottom:5px;">Als u al een lokale Git repositorie heeft met commits kunt u deze repository als een remote toevoegen en er naar toe pushen.</span>
+ <p></p>
+ <pre wicket:id="remoteSyntax" style="padding: 5px 30px;"></pre>
+ <p></p>
+ <h3>Learn Git</h3>
+ Als u niet goed weet wat u met deze informatie aan moet raden we aan om het <a href="http://book.git-scm.com">Git Community Book</a> of <a href="http://progit.org/book" target="_blank">Pro Git</a> te bestuderen voor een betere begrip van hoe u Git kunt gebruiken.
+ <p></p>
+ <h4>Open Source Git Clients</h4>
+ <ul>
+ <li><a href="http://git-scm.com">Git</a> - de officiele, command-line Git</li>
+ <li><a href="http://tortoisegit.googlecode.com">TortoiseGit</a> - Windows bestandsverkenner ingetratie (officiele command-line Git is wel nodig)</li>
+ <li><a href="http://eclipse.org/egit">Eclipse/EGit</a> - Git voor de Eclipse IDE (gebaseerd op JGit, zoals Gitblit)</li>
+ <li><a href="https://code.google.com/p/gitextensions/">Git Extensions</a> - C# frontend voor Git met Windows Explorer en Visual Studio integratie</li>
+ <li><a href="http://gitx.laullon.com/">GitX (L)</a> - een Mac OS X Git client</li>
+ </ul>
+ <p></p>
+ <h4>Commercial/Closed-Source Git Clients</h4>
+ <ul>
+ <li><a href="http://www.syntevo.com/smartgit">SmartGit</a> - Een Java Git, Mercurial, en SVN client applicatie (officiele command-line Git is wel nodig)</li>
+ <li><a href="http://www.sourcetreeapp.com/">SourceTree</a> - Een gratis Mac Client voor Git, Mercurial, en SVN</li>
+ </ul>
+</wicket:extend>
+</body>
+</html>
diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pl.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pl.html new file mode 100644 index 00000000..109899aa --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pl.html @@ -0,0 +1,56 @@ + + +<!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="es"> + +<body> +<wicket:extend> + + <h2>Puste repozytorium</h2> + <p></p> + <div class="row"> + <div class="span10"> + <div class="alert alert-success"> + <span wicket:id="repository" style="font-weight: bold;">[repository]</span> jest pustym repozytorium i nie może być zaprezentowane przez Gitblit. + <p></p> + Wgraj, poprzez push, dowolne zmiany do lokalizacji <span wicket:id="pushurl"></span> + <p></p> + <hr/> + Po wgraniu zmian <b>odśwież</b> stronę, aby podejrzeć repozytorium. + </div> + </div> + </div> + + <h3>Składnia linii poleceń GITa</h3> + <span style="padding-bottom:5px;">Jeśli nie posiadasz lokalnego repozytorium GITa to sklonuj to repozytorium, wgraj dowolne pliki, a następnie wyślij poprzez push zmiany na Gitblit.</span> + <p></p> + <pre style="padding: 5px 30px;" wicket:id="cloneSyntax"></pre> + <p></p> + <span style="padding-bottom:5px;">Gdy posiadasz lokalne repozytorium GITa z dowolnymi zmianami, to możesz dodać to repozytorium jako remote i wysłać do niego zmiany poprzez push.</span> + <p></p> + <pre style="padding: 5px 30px;" wicket:id="remoteSyntax"></pre> + <p></p> + <h3>Nauka GITa</h3> + Jeżeli powyższe informacje są dla Ciebie niezrozumiałe, zapoznaj się z książką <a href="http://git-scm.com/book/pl" target="_blank">Pro Git - Wersja PL</a> dla lepszego zrozumienia, jak poprawnie używać GITa. + <p></p> + <h4>Darmowi klienci GITa</h4> + <ul> + <li><a href="http://git-scm.com">Git</a> - Oficjalny klient, dostępny przez linię poleceń</li> + <li><a href="http://tortoisegit.googlecode.com">TortoiseGit</a> - Rozszerzenie eksploratora Windows (wymaga oficjalnego, dostępnego przez linię poleceń klienta)</li> + <li><a href="http://eclipse.org/egit">Eclipse/EGit</a> - GIT dla edytora Eclipse (oparty o JGit, podobnie jak Gitblit)</li> + <li><a href="https://code.google.com/p/gitextensions/">Git Extensions</a> - napisana w C# fasada na GIT, udostępniająca integrację dla Windows Explorer oraz Visual Studio</li> + <li><a href="http://gitx.laullon.com/">GitX (L)</a> - klient GIT na Mac OS X</li> + </ul> + <p></p> + <h4>Komercyjni klienci GITa</h4> + <ul> + <li><a href="http://www.syntevo.com/smartgit">SmartGit</a> - aplikacja napisana w Javie (wymaga oficjalnego, dostępnego przez linię poleceń klienta)</li> + <li><a href="http://www.sourcetreeapp.com/">SourceTree</a> - darmowy klient GIT, Mercurial i SVN na Mac OS X</li> + </ul> +</wicket:extend> +</body> +</html> + 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 new file mode 100644 index 00000000..351ef879 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_pt_BR.html @@ -0,0 +1,53 @@ +<!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="pt-br"
+ lang="pt-br">
+
+<body>
+<wicket:extend>
+
+ <h2>Repositório Vazio</h2>
+ <p></p>
+ <div class="row">
+ <div class="span10">
+ <div class="alert alert-success">
+ <span wicket:id="repository" style="font-weight: bold;">[repository]</span> é um repositório vazio e não pode ser visualizado pelo Gitblit.
+ <p></p>
+ Por favor faça o push de alguns commits para <span wicket:id="pushurl"></span>
+ <p></p>
+ <hr/>
+ Depois de ter feito push você poderá <b>atualizar</b> esta página para visualizar seu repositório.
+ </div>
+ </div>
+ </div>
+
+ <h3>Sintaxe dos comandos do Git</h3>
+ <span style="padding-bottom:5px;">Se você ainda não tem um repositório local do Git, então você deve primeiro clonar este repositório, fazer commit de alguns arquivos e então fazer push desses commits para o Gitblit.</span>
+ <p></p>
+ <pre style="padding: 5px 30px;" wicket:id="cloneSyntax"></pre>
+ <p></p>
+ <span style="padding-bottom:5px;">Se você já tem um repositório Git local com alguns commits, então você deve adicionar este repositório como uma referência remota e então fazer push.</span>
+ <p></p>
+ <pre wicket:id="remoteSyntax" style="padding: 5px 30px;"></pre>
+ <p></p>
+ <h3>Aprenda Git</h3>
+ Se você estiver com dúvidas sobre como ultilizar essas informações, uma sugestão seria dar uma olhada no livro <a href="http://book.git-scm.com">Git Community Book</a> ou <a href="http://progit.org/book" target="_blank">Pro Git</a> para entender melhor como usar o Git.
+ <p></p>
+ <h4>Alguns clients do Git que são Open Source</h4>
+ <ul>
+ <li><a href="http://git-scm.com">Git</a> - o Git oficial através de linhas de comando</li>
+ <li><a href="http://tortoisegit.googlecode.com">TortoiseGit</a> - Faz integração do Explorer do Windows com o Git (por isso requer o Git Oficial)</li>
+ <li><a href="http://eclipse.org/egit">Eclipse/EGit</a> - Git para a IDE Eclipse (baseada no JGit, como o Gitblit)</li>
+ <li><a href="https://code.google.com/p/gitextensions/">Git Extensions</a> - Interface (em C#) para o Git cuja a caracterÃstica é a integração com o Windows Explorer e o Visual Studio</li>
+ <li><a href="http://gitx.laullon.com/">GitX (L)</a> - um Cliente do Git para Mac OS X</li>
+ </ul>
+ <p></p>
+ <h4>Clients do Git proprietários ou com Código Fechado</h4>
+ <ul>
+ <li><a href="http://www.syntevo.com/smartgit">SmartGit</a> - Aplicação Client (em Java) para Git, Mercurial, e SVN (por isso requer o Git Oficial)</li>
+ <li><a href="http://www.sourcetreeapp.com/">SourceTree</a> - Client gratuito para o Mac que suporta Git, Mercurial e SVN</li>
+ </ul>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file 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 new file mode 100644 index 00000000..4b21800e --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_zh_CN.html @@ -0,0 +1,55 @@ +<!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="zh-CN" + lang="zh-CN"> + +<body> +<wicket:extend> + + <h2>空版本库</h2> + <p></p> + <div class="row"> + <div class="span10"> + <div class="alert alert-success"> + <span wicket:id="repository" style="font-weight: bold;">[repository]</span> 版本库目å‰ä¸ºç©ºã€‚ + Gitblit æ— æ³•æŸ¥çœ‹ã€‚ + <p></p> + 请往æ¤ç½‘å€è¿›è¡ŒæŽ¨é€ <span wicket:id="pushurl"></span> + <p></p> + <hr/> + å½“ä½ æŽ¨é€å®Œæ¯•åŽä½ å¯ä»¥ <b>刷新</b> æ¤é¡µé¢é‡æ–°æŸ¥çœ‹æ‚¨çš„版本库。 + </div> + </div> + </div> + + <h3>Git å‘½ä»¤è¡Œæ ¼å¼</h3> + <span style="padding-bottom:5px;">如果您没有本地 Git 版本库, 您å¯ä»¥å…‹éš†æ¤ç‰ˆæœ¬åº“, æ交一些文件, 然åŽå°†æ‚¨çš„æ交推é€å›žGitblit。</span> + <p></p> + <pre style="padding: 5px 30px;" wicket:id="cloneSyntax"></pre> + <p></p> + <span style="padding-bottom:5px;">如果您已ç»æœ‰ä¸€ä¸ªæœ¬åœ°çš„æ交过的版本库, 那么您å¯ä»¥å°†æ¤ç‰ˆæœ¬åº“åŠ ä¸ºè¿œç¨‹ + 版本库,并进行推é€ã€‚</span> + <p></p> + <pre wicket:id="remoteSyntax" style="padding: 5px 30px;"></pre> + <p></p> + <h3>å¦ä¹ Git</h3> + 如果您ä¸æ˜Žç™½è¿™äº›ä¿¡æ¯ä»€ä¹ˆæ„æ€, 您å¯ä»¥å‚考 <a href="http://book.git-scm.com">Git Community Book</a> 或者 <a href="http://progit.org/book" target="_blank">Pro Git</a> åŽ»æ›´åŠ æ·±å…¥çš„å¦ä¹ Git 的用法。 + <p></p> + <h4>å¼€æº Git 客户端</h4> + <ul> + <li><a href="http://git-scm.com">Git</a> - 官方, 命令行版本 Git</li> + <li><a href="http://tortoisegit.googlecode.com">TortoiseGit</a> - 与 Windows 资æºç®¡ç†å™¨é›†æˆ (需è¦å®˜æ–¹, 命令行 Git 的支æŒ)</li> + <li><a href="http://eclipse.org/egit">Eclipse/EGit</a> - Git for the Eclipse IDE (基于 JGit, 类似 Gitblit)</li> + <li><a href="https://code.google.com/p/gitextensions/">Git Extensions</a> - C# 版本的 Git å‰ç«¯ï¼Œä¸Ž Windows 资æºç®¡ç†å™¨å’Œ Visual Studio 集æˆ</li> + <li><a href="http://gitx.laullon.com/">GitX (L)</a> - Mac OS X Git 客户端</li> + </ul> + <p></p> + <h4>商业/é—æº Git 客户端</h4> + <ul> + <li><a href="http://www.syntevo.com/smartgit">SmartGit</a> - Java ç‰ˆæœ¬çš„æ”¯æŒ Git, Mercurial å’Œ SVN 客户端应用 (需è¦å®˜æ–¹, 命令行 Git 的支æŒ)</li> + <li><a href="http://www.sourcetreeapp.com/">SourceTree</a> - å…费的 Mac Git Mercurial ä»¥åŠ SVN 客户端, Mercurial, and SVN</li> + </ul> +</wicket:extend> +</body> +</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/FederationPage.html b/src/main/java/com/gitblit/wicket/pages/FederationPage.html new file mode 100644 index 00000000..bb39d345 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/FederationPage.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:extend>
+
+ <div wicket:id="federationTokensPanel">[federation tokens panel]</div>
+
+ <div style="padding-top: 10px;" wicket:id="federationProposalsPanel">[federation proposals panel]</div>
+
+ <div style="padding-top: 10px;" wicket:id="federationRegistrationsPanel">[federation registrations panel]</div>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/FederationPage.java b/src/main/java/com/gitblit/wicket/pages/FederationPage.java new file mode 100644 index 00000000..1f98c172 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/FederationPage.java @@ -0,0 +1,52 @@ +/*
+ * Copyright 2011 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 com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.wicket.panels.FederationProposalsPanel;
+import com.gitblit.wicket.panels.FederationRegistrationsPanel;
+import com.gitblit.wicket.panels.FederationTokensPanel;
+
+public class FederationPage extends RootPage {
+
+ public FederationPage() {
+ super();
+ setupPage("", "");
+
+ boolean showFederation = showAdmin && GitBlit.canFederate();
+ add(new FederationTokensPanel("federationTokensPanel", showFederation)
+ .setVisible(showFederation));
+ FederationProposalsPanel proposalsPanel = new FederationProposalsPanel(
+ "federationProposalsPanel");
+ if (showFederation) {
+ proposalsPanel.hideIfEmpty();
+ } else {
+ proposalsPanel.setVisible(false);
+ }
+
+ boolean showRegistrations = GitBlit.getBoolean(Keys.web.showFederationRegistrations, false);
+ FederationRegistrationsPanel registrationsPanel = new FederationRegistrationsPanel(
+ "federationRegistrationsPanel");
+ if (showAdmin || showRegistrations) {
+ registrationsPanel.hideIfEmpty();
+ } else {
+ registrationsPanel.setVisible(false);
+ }
+ add(proposalsPanel);
+ add(registrationsPanel);
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/FederationRegistrationPage.html b/src/main/java/com/gitblit/wicket/pages/FederationRegistrationPage.html new file mode 100644 index 00000000..d7b9bdde --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/FederationRegistrationPage.html @@ -0,0 +1,39 @@ +<!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:extend>
+ <!-- registration info -->
+ <table class="plain">
+ <tr><th><wicket:message key="gb.url">url</wicket:message></th><td><img style="border:0px;vertical-align:middle;" wicket:id="typeIcon" /> <span wicket:id="url">[url]</span></td></tr>
+ <tr><th><wicket:message key="gb.token">token</wicket:message></th><td><span class="sha1" wicket:id="token">[token]</span></td></tr>
+ <tr><th><wicket:message key="gb.folder">folder</wicket:message></th><td><span wicket:id="folder">[folder]</span></td></tr>
+ <tr><th><wicket:message key="gb.frequency">frequency</wicket:message></th><td><span wicket:id="frequency">[frequency]</span></td></tr>
+ <tr><th><wicket:message key="gb.lastPull">lastPull</wicket:message></th><td><span wicket:id="lastPull">[lastPull]</span></td></tr>
+ <tr><th><wicket:message key="gb.nextPull">nextPull</wicket:message></th><td><span wicket:id="nextPull">[nextPull]</span></td></tr>
+ <tr><th valign="top"><wicket:message key="gb.exclusions">exclusions</wicket:message></th><td><span class="sha1" wicket:id="exclusions">[exclusions]</span></td></tr>
+ <tr><th valign="top"><wicket:message key="gb.inclusions">inclusions</wicket:message></th><td><span class="sha1" wicket:id="inclusions">[inclusions]</span></td></tr>
+ </table>
+
+ <table class="repositories">
+ <tr>
+ <th class="left">
+ <img style="vertical-align: top; border: 1px solid #888; background-color: white;" src="git-black-16x16.png"/>
+ <wicket:message key="gb.repositories">[repositories]</wicket:message>
+ </th>
+ <th class="right"><wicket:message key="gb.status">[status]</wicket:message></th>
+ </tr>
+ <tbody>
+ <tr wicket:id="row">
+ <td class="left"><img style="border:0px;vertical-align:middle;" wicket:id="statusIcon" /><span wicket:id="name">[name]</span></td>
+ <td class="right"><span wicket:id="status">[status]</span></td>
+ </tr>
+ </tbody>
+ </table>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/FederationRegistrationPage.java b/src/main/java/com/gitblit/wicket/pages/FederationRegistrationPage.java new file mode 100644 index 00000000..19c30a5e --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/FederationRegistrationPage.java @@ -0,0 +1,95 @@ +/*
+ * Copyright 2011 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.util.Collections;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.GitBlit;
+import com.gitblit.models.FederationModel;
+import com.gitblit.models.FederationModel.RepositoryStatus;
+import com.gitblit.wicket.WicketUtils;
+
+public class FederationRegistrationPage extends RootSubPage {
+
+ public FederationRegistrationPage(PageParameters params) {
+ super(params);
+
+ setStatelessHint(true);
+
+ String url = WicketUtils.getUrlParameter(params);
+ String name = WicketUtils.getNameParameter(params);
+
+ FederationModel registration = GitBlit.self().getFederationRegistration(url, name);
+ if (registration == null) {
+ error(getString("gb.couldNotFindFederationRegistration"), true);
+ }
+
+ setupPage(registration.isResultData() ? getString("gb.federationResults")
+ : getString("gb.federationRegistration"), registration.url);
+
+ add(new Label("url", registration.url));
+ add(WicketUtils.getRegistrationImage("typeIcon", registration, this));
+ add(new Label("frequency", registration.frequency));
+ add(new Label("folder", registration.folder));
+ add(new Label("token", showAdmin ? registration.token : "--"));
+ add(WicketUtils.createTimestampLabel("lastPull", registration.lastPull, getTimeZone(), getTimeUtils()));
+ add(WicketUtils.createTimestampLabel("nextPull", registration.nextPull, getTimeZone(), getTimeUtils()));
+
+ StringBuilder inclusions = new StringBuilder();
+ for (String inc : registration.inclusions) {
+ inclusions.append(inc).append("<br/>");
+ }
+ StringBuilder exclusions = new StringBuilder();
+ for (String ex : registration.exclusions) {
+ exclusions.append(ex).append("<br/>");
+ }
+
+ add(new Label("inclusions", inclusions.toString()).setEscapeModelStrings(false));
+
+ add(new Label("exclusions", exclusions.toString()).setEscapeModelStrings(false));
+
+ List<RepositoryStatus> list = registration.getStatusList();
+ Collections.sort(list);
+ DataView<RepositoryStatus> dataView = new DataView<RepositoryStatus>("row",
+ new ListDataProvider<RepositoryStatus>(list)) {
+ private static final long serialVersionUID = 1L;
+ private int counter;
+
+ @Override
+ protected void onBeforeRender() {
+ super.onBeforeRender();
+ counter = 0;
+ }
+
+ public void populateItem(final Item<RepositoryStatus> item) {
+ final RepositoryStatus entry = item.getModelObject();
+ item.add(WicketUtils.getPullStatusImage("statusIcon", entry.status));
+ item.add(new Label("name", entry.name));
+ item.add(new Label("status", entry.status.name()));
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(dataView);
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/ForkPage.html b/src/main/java/com/gitblit/wicket/pages/ForkPage.html new file mode 100644 index 00000000..72093696 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ForkPage.html @@ -0,0 +1,38 @@ +<!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:head>
+ <noscript>
+ <meta http-equiv="refresh" content="5"></meta>
+ </noscript>
+ <script type="text/javascript"">
+ function doLoad() { setTimeout( "refresh()", 5*1000 ); }
+ function refresh() { window.location.reload(); }
+ </script>
+</wicket:head>
+<wicket:extend>
+<!-- need to specify body.onload -->
+<body onload="doLoad()">
+
+ <div class="row">
+ <div class="span6 offset3">
+ <div style="opacity:0.2;">
+ <center><img style="padding:10px" src="git-black_210x210.png"></img></center>
+ </div>
+ <div wicket:id="forkText" class="pageTitle project" style="border:0;font-weight:bold; text-align:center;">[fork text]</div>
+ </div>
+ <div class="span4 offset4">
+ <div class="progress progress-striped active">
+ <div class="bar" style="width: 100%;"></div>
+ </div>
+ </div>
+ </div>
+</body>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/ForkPage.java b/src/main/java/com/gitblit/wicket/pages/ForkPage.java new file mode 100644 index 00000000..340bd823 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ForkPage.java @@ -0,0 +1,107 @@ +/*
+ * Copyright 2012 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.text.MessageFormat;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.GitBlit;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.GitblitRedirectException;
+import com.gitblit.wicket.WicketUtils;
+
+public class ForkPage extends RepositoryPage {
+
+
+ public ForkPage(PageParameters params) {
+ super(params);
+
+ setVersioned(false);
+
+ GitBlitWebSession session = GitBlitWebSession.get();
+
+ RepositoryModel repository = getRepositoryModel();
+ UserModel user = session.getUser();
+ boolean canFork = user.canFork(repository);
+
+ if (!canFork) {
+ // redirect to the summary page if this repository is not empty
+ GitBlitWebSession.get().cacheErrorMessage(
+ MessageFormat.format(getString("gb.forkNotAuthorized"), repository.name));
+ throw new GitblitRedirectException(SummaryPage.class, WicketUtils.newRepositoryParameter(repository.name));
+ }
+
+ String fork = GitBlit.self().getFork(user.username, repository.name);
+ if (fork != null) {
+ // redirect to user's fork
+ throw new GitblitRedirectException(SummaryPage.class, WicketUtils.newRepositoryParameter(fork));
+ }
+
+ add(new Label("forkText", getString("gb.preparingFork")));
+
+ if (!session.isForking()) {
+ // prepare session
+ session.isForking(true);
+
+ // fork it
+ ForkThread forker = new ForkThread(repository, session);
+ forker.start();
+ }
+ }
+
+ @Override
+ protected boolean allowForkControls() {
+ return false;
+ }
+
+ @Override
+ protected String getPageName() {
+ return "fork";
+ }
+
+ /**
+ * ForkThread does the work of working the repository in a background
+ * thread. The completion status is tracked through a session variable and
+ * monitored by this page.
+ */
+ private static class ForkThread extends Thread {
+
+ private final RepositoryModel repository;
+ private final GitBlitWebSession session;
+
+ public ForkThread(RepositoryModel repository, GitBlitWebSession session) {
+ this.repository = repository;
+ this.session = session;
+ }
+
+ @Override
+ public void run() {
+ UserModel user = session.getUser();
+ try {
+ GitBlit.self().fork(repository, user);
+ } catch (Exception e) {
+ LoggerFactory.getLogger(ForkPage.class).error(MessageFormat.format("Failed to fork {0} for {1}", repository.name, user.username), e);
+ } finally {
+ session.isForking(false);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/ForksPage.html b/src/main/java/com/gitblit/wicket/pages/ForksPage.html new file mode 100644 index 00000000..c18d2a49 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ForksPage.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:extend>
+
+ <div wicket:id="fork">
+ <div>
+ <span wicket:id="anAvatar" style="vertical-align: baseline;font-weight:bold;"></span>
+ <span wicket:id="aProject">[a project]</span> / <span wicket:id="aFork">[a fork]</span>
+ <span style="padding-left:10px;" wicket:id="lastChange"></span>
+ </div>
+ </div>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/ForksPage.java b/src/main/java/com/gitblit/wicket/pages/ForksPage.java new file mode 100644 index 00000000..cc483878 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ForksPage.java @@ -0,0 +1,156 @@ +/*
+ * Copyright 2012 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.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.eclipse.jgit.lib.PersonIdent;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.ForkModel;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.GravatarImage;
+import com.gitblit.wicket.panels.LinkPanel;
+
+public class ForksPage extends RepositoryPage {
+
+ public ForksPage(PageParameters params) {
+ super(params);
+
+ final RepositoryModel pageRepository = getRepositoryModel();
+
+ ForkModel root = GitBlit.self().getForkNetwork(pageRepository.name);
+ List<FlatFork> network = flatten(root);
+
+ ListDataProvider<FlatFork> forksDp = new ListDataProvider<FlatFork>(network);
+ DataView<FlatFork> forksList = new DataView<FlatFork>("fork", forksDp) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<FlatFork> item) {
+ FlatFork fork = item.getModelObject();
+ RepositoryModel repository = fork.repository;
+
+ if (repository.isPersonalRepository()) {
+ UserModel user = GitBlit.self().getUserModel(repository.projectPath.substring(1));
+ PersonIdent ident = new PersonIdent(user.getDisplayName(), user.emailAddress == null ? user.getDisplayName() : user.emailAddress);
+ item.add(new GravatarImage("anAvatar", ident, 20));
+ if (pageRepository.equals(repository)) {
+ // do not link to self
+ item.add(new Label("aProject", user.getDisplayName()));
+ } else {
+ item.add(new LinkPanel("aProject", null, user.getDisplayName(), UserPage.class, WicketUtils.newUsernameParameter(user.username)));
+ }
+ } else {
+ Component swatch;
+ if (repository.isBare){
+ swatch = new Label("anAvatar", " ").setEscapeModelStrings(false);
+ } else {
+ swatch = new Label("anAvatar", "!");
+ WicketUtils.setHtmlTooltip(swatch, getString("gb.workingCopyWarning"));
+ }
+ WicketUtils.setCssClass(swatch, "repositorySwatch");
+ WicketUtils.setCssBackground(swatch, repository.toString());
+ item.add(swatch);
+ String projectName = repository.projectPath;
+ if (StringUtils.isEmpty(projectName)) {
+ projectName = GitBlit.getString(Keys.web.repositoryRootGroupName, "main");
+ }
+ if (pageRepository.equals(repository)) {
+ // do not link to self
+ item.add(new Label("aProject", projectName));
+ } else {
+ item.add(new LinkPanel("aProject", null, projectName, ProjectPage.class, WicketUtils.newProjectParameter(projectName)));
+ }
+ }
+
+ String repo = StringUtils.getLastPathElement(repository.name);
+ UserModel user = GitBlitWebSession.get().getUser();
+ if (user == null) {
+ user = UserModel.ANONYMOUS;
+ }
+ if (user.canView(repository)) {
+ if (pageRepository.equals(repository)) {
+ // do not link to self
+ item.add(new Label("aFork", StringUtils.stripDotGit(repo)));
+ } else {
+ item.add(new LinkPanel("aFork", null, StringUtils.stripDotGit(repo), SummaryPage.class, WicketUtils.newRepositoryParameter(repository.name)));
+ }
+ item.add(WicketUtils.createDateLabel("lastChange", repository.lastChange, getTimeZone(), getTimeUtils()));
+ } else {
+ item.add(new Label("aFork", repo));
+ item.add(new Label("lastChange").setVisible(false));
+ }
+
+ WicketUtils.setCssStyle(item, "margin-left:" + (32*fork.level) + "px;");
+ if (fork.level == 0) {
+ WicketUtils.setCssClass(item, "forkSource");
+ } else {
+ WicketUtils.setCssClass(item, "forkEntry");
+ }
+ }
+ };
+
+ add(forksList);
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.forks");
+ }
+
+ protected List<FlatFork> flatten(ForkModel root) {
+ List<FlatFork> list = new ArrayList<FlatFork>();
+ list.addAll(flatten(root, 0));
+ return list;
+ }
+
+ protected List<FlatFork> flatten(ForkModel node, int level) {
+ List<FlatFork> list = new ArrayList<FlatFork>();
+ list.add(new FlatFork(node.repository, level));
+ if (!node.isLeaf()) {
+ for (ForkModel fork : node.forks) {
+ list.addAll(flatten(fork, level + 1));
+ }
+ }
+ return list;
+ }
+
+ private class FlatFork implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ public final RepositoryModel repository;
+ public final int level;
+
+ public FlatFork(RepositoryModel repository, int level) {
+ this.repository = repository;
+ this.level = level;
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/GitSearchPage.html b/src/main/java/com/gitblit/wicket/pages/GitSearchPage.html new file mode 100644 index 00000000..9bb1f418 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/GitSearchPage.html @@ -0,0 +1,25 @@ +<!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:extend>
+
+ <!-- pager links -->
+ <div style="padding-top:5px;">
+ <a wicket:id="firstPageTop"><wicket:message key="gb.pageFirst"></wicket:message></a> | <a wicket:id="prevPageTop"><wicket:message key="gb.pagePrevious"></wicket:message></a> | <a wicket:id="nextPageTop"><wicket:message key="gb.pageNext"></wicket:message></a>
+ </div>
+
+ <!-- history -->
+ <div style="margin-top:5px;" wicket:id="searchPanel">[search panel]</div>
+
+ <!-- pager links -->
+ <div style="padding-bottom:5px;">
+ <a wicket:id="firstPageBottom"><wicket:message key="gb.pageFirst"></wicket:message></a> | <a wicket:id="prevPageBottom"><wicket:message key="gb.pagePrevious"></wicket:message></a> | <a wicket:id="nextPageBottom"><wicket:message key="gb.pageNext"></wicket:message></a>
+ </div>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/GitSearchPage.java b/src/main/java/com/gitblit/wicket/pages/GitSearchPage.java new file mode 100644 index 00000000..6b0714f0 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/GitSearchPage.java @@ -0,0 +1,69 @@ +/*
+ * Copyright 2011 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 org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+
+import com.gitblit.Constants;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.SearchPanel;
+
+public class GitSearchPage extends RepositoryPage {
+
+ public GitSearchPage(PageParameters params) {
+ super(params);
+
+ String value = WicketUtils.getSearchString(params);
+ String type = WicketUtils.getSearchType(params);
+ Constants.SearchType searchType = Constants.SearchType.forName(type);
+
+ int pageNumber = WicketUtils.getPage(params);
+ int prevPage = Math.max(0, pageNumber - 1);
+ int nextPage = pageNumber + 1;
+
+ SearchPanel search = new SearchPanel("searchPanel", repositoryName, objectId, value,
+ searchType, getRepository(), -1, pageNumber - 1, getRepositoryModel().showRemoteBranches);
+ boolean hasMore = search.hasMore();
+ add(search);
+
+ add(new BookmarkablePageLink<Void>("firstPageTop", GitSearchPage.class,
+ WicketUtils.newSearchParameter(repositoryName, objectId, value, searchType))
+ .setEnabled(pageNumber > 1));
+ add(new BookmarkablePageLink<Void>("prevPageTop", GitSearchPage.class,
+ WicketUtils.newSearchParameter(repositoryName, objectId, value, searchType,
+ prevPage)).setEnabled(pageNumber > 1));
+ add(new BookmarkablePageLink<Void>("nextPageTop", GitSearchPage.class,
+ WicketUtils.newSearchParameter(repositoryName, objectId, value, searchType,
+ nextPage)).setEnabled(hasMore));
+
+ add(new BookmarkablePageLink<Void>("firstPageBottom", GitSearchPage.class,
+ WicketUtils.newSearchParameter(repositoryName, objectId, value, searchType))
+ .setEnabled(pageNumber > 1));
+ add(new BookmarkablePageLink<Void>("prevPageBottom", GitSearchPage.class,
+ WicketUtils.newSearchParameter(repositoryName, objectId, value, searchType,
+ prevPage)).setEnabled(pageNumber > 1));
+ add(new BookmarkablePageLink<Void>("nextPageBottom", GitSearchPage.class,
+ WicketUtils.newSearchParameter(repositoryName, objectId, value, searchType,
+ nextPage)).setEnabled(hasMore));
+
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.search");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/GravatarProfilePage.html b/src/main/java/com/gitblit/wicket/pages/GravatarProfilePage.html new file mode 100644 index 00000000..0cc0f1fc --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/GravatarProfilePage.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:extend>
+ <div class="pageTitle">
+ <h2>Gravatar<small> / <span wicket:id="username">[username]</span></small></h2>
+ </div>
+ <img class="gravatar" wicket:id="profileImage"></img>
+ <h2 wicket:id="displayName"></h2>
+ <div style="color:#888;"wicket:id="location"></div>
+ <div style="padding-top:5px;" wicket:id="aboutMe"></div>
+ <p></p>
+ <a wicket:id="profileLink"><wicket:message key="gb.completeGravatarProfile">[Complete profile on Gravatar.com]</wicket:message></a>
+ <p></p>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/GravatarProfilePage.java b/src/main/java/com/gitblit/wicket/pages/GravatarProfilePage.java new file mode 100644 index 00000000..ee567d75 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/GravatarProfilePage.java @@ -0,0 +1,64 @@ +/*
+ * Copyright 2011 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.IOException;
+import java.text.MessageFormat;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.ExternalLink;
+
+import com.gitblit.models.GravatarProfile;
+import com.gitblit.utils.ActivityUtils;
+import com.gitblit.wicket.ExternalImage;
+import com.gitblit.wicket.WicketUtils;
+
+/**
+ * Gravatar Profile Page shows the Gravatar information, if available.
+ *
+ * @author James Moger
+ *
+ */
+public class GravatarProfilePage extends RootPage {
+
+ public GravatarProfilePage(PageParameters params) {
+ super();
+ setupPage("", "");
+ String object = WicketUtils.getObject(params);
+ GravatarProfile profile = null;
+ try {
+ if (object.indexOf('@') > -1) {
+ profile = ActivityUtils.getGravatarProfileFromAddress(object);
+ } else {
+ profile = ActivityUtils.getGravatarProfile(object);
+ }
+ } catch (IOException e) {
+ error(MessageFormat.format(getString("gb.failedToFindGravatarProfile"), object), e, true);
+ }
+
+ if (profile == null) {
+ error(MessageFormat.format(getString("gb.failedToFindGravatarProfile"), object), true);
+ }
+ add(new Label("displayName", profile.displayName));
+ add(new Label("username", profile.preferredUsername));
+ add(new Label("location", profile.currentLocation));
+ add(new Label("aboutMe", profile.aboutMe));
+ ExternalImage image = new ExternalImage("profileImage", profile.thumbnailUrl + "?s=256&d=identicon");
+ add(image);
+ add(new ExternalLink("profileLink", profile.profileUrl));
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/HistoryPage.html b/src/main/java/com/gitblit/wicket/pages/HistoryPage.html new file mode 100644 index 00000000..f9bd2f69 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/HistoryPage.html @@ -0,0 +1,25 @@ +<!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:extend>
+
+ <!-- pager links -->
+ <div style="padding-top:5px;">
+ <a wicket:id="firstPageTop"><wicket:message key="gb.pageFirst"></wicket:message></a> | <a wicket:id="prevPageTop"><wicket:message key="gb.pagePrevious"></wicket:message></a> | <a wicket:id="nextPageTop"><wicket:message key="gb.pageNext"></wicket:message></a>
+ </div>
+
+ <!-- history -->
+ <div style="margin-top:5px;" wicket:id="historyPanel">[history panel]</div>
+
+ <!-- pager links -->
+ <div style="padding-bottom:5px;">
+ <a wicket:id="firstPageBottom"><wicket:message key="gb.pageFirst"></wicket:message></a> | <a wicket:id="prevPageBottom"><wicket:message key="gb.pagePrevious"></wicket:message></a> | <a wicket:id="nextPageBottom"><wicket:message key="gb.pageNext"></wicket:message></a>
+ </div>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/HistoryPage.java b/src/main/java/com/gitblit/wicket/pages/HistoryPage.java new file mode 100644 index 00000000..563202e6 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/HistoryPage.java @@ -0,0 +1,65 @@ +/*
+ * Copyright 2011 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 org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.HistoryPanel;
+
+public class HistoryPage extends RepositoryPage {
+
+ public HistoryPage(PageParameters params) {
+ super(params);
+
+ String path = WicketUtils.getPath(params);
+ int pageNumber = WicketUtils.getPage(params);
+ int prevPage = Math.max(0, pageNumber - 1);
+ int nextPage = pageNumber + 1;
+
+ HistoryPanel history = new HistoryPanel("historyPanel", repositoryName, objectId, path,
+ getRepository(), -1, pageNumber - 1, getRepositoryModel().showRemoteBranches);
+ boolean hasMore = history.hasMore();
+ add(history);
+
+ add(new BookmarkablePageLink<Void>("firstPageTop", HistoryPage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, path))
+ .setEnabled(pageNumber > 1));
+ add(new BookmarkablePageLink<Void>("prevPageTop", HistoryPage.class,
+ WicketUtils.newHistoryPageParameter(repositoryName, objectId, path, prevPage))
+ .setEnabled(pageNumber > 1));
+ add(new BookmarkablePageLink<Void>("nextPageTop", HistoryPage.class,
+ WicketUtils.newHistoryPageParameter(repositoryName, objectId, path, nextPage))
+ .setEnabled(hasMore));
+
+ add(new BookmarkablePageLink<Void>("firstPageBottom", HistoryPage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, path))
+ .setEnabled(pageNumber > 1));
+ add(new BookmarkablePageLink<Void>("prevPageBottom", HistoryPage.class,
+ WicketUtils.newHistoryPageParameter(repositoryName, objectId, path, prevPage))
+ .setEnabled(pageNumber > 1));
+ add(new BookmarkablePageLink<Void>("nextPageBottom", HistoryPage.class,
+ WicketUtils.newHistoryPageParameter(repositoryName, objectId, path, nextPage))
+ .setEnabled(hasMore));
+
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.history");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/LogPage.html b/src/main/java/com/gitblit/wicket/pages/LogPage.html new file mode 100644 index 00000000..8e5cb96a --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/LogPage.html @@ -0,0 +1,25 @@ +<!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:extend>
+
+ <!-- pager links -->
+ <div style="padding-top:5px;">
+ <a wicket:id="firstPageTop"><wicket:message key="gb.pageFirst"></wicket:message></a> | <a wicket:id="prevPageTop"><wicket:message key="gb.pagePrevious"></wicket:message></a> | <a wicket:id="nextPageTop"><wicket:message key="gb.pageNext"></wicket:message></a>
+ </div>
+
+ <!-- log -->
+ <div style="margin-top:5px;" wicket:id="logPanel">[log panel]</div>
+
+ <!-- pager links -->
+ <div style="padding-bottom:5px;">
+ <a wicket:id="firstPageBottom"><wicket:message key="gb.pageFirst"></wicket:message></a> | <a wicket:id="prevPageBottom"><wicket:message key="gb.pagePrevious"></wicket:message></a> | <a wicket:id="nextPageBottom"><wicket:message key="gb.pageNext"></wicket:message></a>
+ </div>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/LogPage.java b/src/main/java/com/gitblit/wicket/pages/LogPage.java new file mode 100644 index 00000000..ee8ddfef --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/LogPage.java @@ -0,0 +1,69 @@ +/*
+ * Copyright 2011 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 org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.LogPanel;
+
+public class LogPage extends RepositoryPage {
+
+ public LogPage(PageParameters params) {
+ super(params);
+
+ addSyndicationDiscoveryLink();
+
+ int pageNumber = WicketUtils.getPage(params);
+ int prevPage = Math.max(0, pageNumber - 1);
+ int nextPage = pageNumber + 1;
+ String refid = objectId;
+ if (StringUtils.isEmpty(refid)) {
+ refid = getRepositoryModel().HEAD;
+ }
+ LogPanel logPanel = new LogPanel("logPanel", repositoryName, refid, getRepository(), -1,
+ pageNumber - 1, getRepositoryModel().showRemoteBranches);
+ boolean hasMore = logPanel.hasMore();
+ add(logPanel);
+
+ add(new BookmarkablePageLink<Void>("firstPageTop", LogPage.class,
+ WicketUtils.newObjectParameter(repositoryName, objectId))
+ .setEnabled(pageNumber > 1));
+ add(new BookmarkablePageLink<Void>("prevPageTop", LogPage.class,
+ WicketUtils.newLogPageParameter(repositoryName, objectId, prevPage))
+ .setEnabled(pageNumber > 1));
+ add(new BookmarkablePageLink<Void>("nextPageTop", LogPage.class,
+ WicketUtils.newLogPageParameter(repositoryName, objectId, nextPage))
+ .setEnabled(hasMore));
+
+ add(new BookmarkablePageLink<Void>("firstPageBottom", LogPage.class,
+ WicketUtils.newObjectParameter(repositoryName, objectId))
+ .setEnabled(pageNumber > 1));
+ add(new BookmarkablePageLink<Void>("prevPageBottom", LogPage.class,
+ WicketUtils.newLogPageParameter(repositoryName, objectId, prevPage))
+ .setEnabled(pageNumber > 1));
+ add(new BookmarkablePageLink<Void>("nextPageBottom", LogPage.class,
+ WicketUtils.newLogPageParameter(repositoryName, objectId, nextPage))
+ .setEnabled(hasMore));
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.log");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/LogoutPage.html b/src/main/java/com/gitblit/wicket/pages/LogoutPage.html new file mode 100644 index 00000000..d4077830 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/LogoutPage.html @@ -0,0 +1,33 @@ +<!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:extend> + <div class="navbar navbar-fixed-top"> + <div class="navbar-inner"> + <div class="container"> + <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </a> + <a class="brand" wicket:id="rootLink"> + <img src="gitblt_25_white.png" width="79" height="25" alt="gitblit" class="logo"/> + </a> + + </div> + </div> + </div> + + <!-- subclass content --> + <div class="container"> + <div style="text-align:center" wicket:id="feedback">[Feedback Panel]</div> + + <h1><wicket:message key="gb.sessionEnded">[Session has ended]</wicket:message></h1> + <p><wicket:message key="gb.closeBrowser">[Please close the browser]</wicket:message></p> + </div> +</wicket:extend> +</body> +</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/LogoutPage.java b/src/main/java/com/gitblit/wicket/pages/LogoutPage.java new file mode 100644 index 00000000..982de0ec --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/LogoutPage.java @@ -0,0 +1,51 @@ +/*
+ * Copyright 2011 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 org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.protocol.http.WebRequest;
+import org.apache.wicket.protocol.http.WebResponse;
+
+import com.gitblit.GitBlit;
+import com.gitblit.models.UserModel;
+import com.gitblit.wicket.GitBlitWebSession;
+
+public class LogoutPage extends BasePage {
+
+ public LogoutPage() {
+ super();
+ GitBlitWebSession session = GitBlitWebSession.get();
+ UserModel user = session.getUser();
+ GitBlit.self().setCookie((WebResponse) getResponse(), null);
+ GitBlit.self().logout(user);
+ session.invalidate();
+
+ /*
+ * Now check whether the authentication was realized via the Authorization in the header.
+ * If so, it is likely to be cached by the browser, and cannot be undone. Effectively, this means
+ * that you cannot log out...
+ */
+ if ( ((WebRequest)getRequest()).getHttpServletRequest().getHeader("Authorization") != null ) {
+ // authentication will be done via this route anyway, show a page to close the browser:
+ // this will be done by Wicket.
+ setupPage(null, getString("gb.logout"));
+
+ } else {
+ setRedirect(true);
+ setResponsePage(getApplication().getHomePage());
+ } // not via WWW-Auth
+ } // LogoutPage
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.html b/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.html new file mode 100644 index 00000000..aba43de8 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.html @@ -0,0 +1,92 @@ +<!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">
+
+<!-- contribute google-code-prettify resources to the page header -->
+<wicket:head>
+ <wicket:link>
+ <link href="prettify/prettify.css" type="text/css" rel="stylesheet" />
+ <script type="text/javascript" src="prettify/prettify.js"></script>
+ </wicket:link>
+</wicket:head>
+
+<wicket:extend>
+<body onload="document.getElementById('query').focus(); prettyPrint();">
+ <div class="pageTitle">
+ <h2><wicket:message key="gb.search"></wicket:message></h2>
+ </div>
+ <form class="form-inline" wicket:id="searchForm">
+ <div class="row">
+ <div class="span3">
+ <h3><wicket:message key="gb.repositories"></wicket:message></h3>
+ <select wicket:id="repositories" ></select>
+ </div>
+ <div class="span9" style="margin-left:10px">
+ <div>
+ <h3><wicket:message key="gb.query"></wicket:message></h3>
+ <input class="span8" id="query" type="text" wicket:id="query" placeholder="enter search text"></input>
+ <button class="btn btn-primary" type="submit" value="Search"><wicket:message key="gb.search"></wicket:message></button>
+ </div>
+ <div style="margin-top:10px;">
+ <div style="margin-left:0px;" class="span3">
+ <div class="alert alert">
+ <b>type:</b> commit or blob<br/>
+ <b>commit:</b> commit id<br/>
+ <b>path:</b> "path/to/blob"<br/>
+ <b>branch:</b> "refs/heads/master"<br/>
+ <b>author:</b> or <b>committer:</b>
+ </div>
+ </div>
+ <div style="margin-left:10px;" class="span4">
+ <div class="alert alert-info">
+ type:commit AND "bug fix"<br/>
+ type:commit AND author:james*<br/>
+ type:blob AND "int errorCode"<br/>
+ type:blob AND test AND path:*.java<br/>
+ commit:d91e5*
+ </div>
+ </div>
+ <div style="margin-left:10px;" class="span2">
+ <wicket:message key="gb.queryHelp"></wicket:message>
+ </div>
+ </div>
+ </div>
+ </div>
+ </form>
+
+ <div class="row-fluid">
+ <!-- results header -->
+ <div class="span8">
+ <h3><span wicket:id="resultsHeader"></span> <small><br/><span wicket:id="resultsCount"></span></small></h3>
+ </div>
+ <!-- pager links -->
+ <div class="span4" wicket:id="topPager"></div>
+ </div>
+
+ <div class="row-fluid">
+ <!-- search result repeater -->
+ <div class="searchResult" wicket:id="searchResults">
+ <div><i wicket:id="type"></i><span class="summary" wicket:id="summary"></span> <span wicket:id="tags" style="padding-left:10px;"></span></div>
+ <div class="body">
+ <div class="fragment" wicket:id="fragment"></div>
+ <div><span class="author" wicket:id="author"></span> <span class="date" ><wicket:message key="gb.authored"></wicket:message> <span class="date" wicket:id="date"></span></span></div>
+ <span class="repository" wicket:id="repository"></span>:<span class="branch" wicket:id="branch"></span>
+ </div>
+ </div>
+
+ <!-- pager links -->
+ <div wicket:id="bottomPager"></div>
+
+ </div>
+</body>
+
+ <wicket:fragment wicket:id="tagsPanel">
+ <span wicket:id="tag">
+ <span wicket:id="tagLink">[tag]</span>
+ </span>
+ </wicket:fragment>
+
+</wicket:extend>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.java b/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.java new file mode 100644 index 00000000..79795ff2 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.java @@ -0,0 +1,257 @@ +/*
+ * Copyright 2012 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.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.ListMultipleChoice;
+import org.apache.wicket.markup.html.form.TextField;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.apache.wicket.model.Model;
+import org.eclipse.jgit.lib.Constants;
+
+import com.gitblit.Constants.SearchType;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.SearchResult;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.SessionlessForm;
+import com.gitblit.wicket.StringChoiceRenderer;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.LinkPanel;
+import com.gitblit.wicket.panels.PagerPanel;
+
+public class LuceneSearchPage extends RootPage {
+
+ public LuceneSearchPage() {
+ super();
+ setup(null);
+ }
+
+ public LuceneSearchPage(PageParameters params) {
+ super(params);
+ setup(params);
+ }
+
+ private void setup(PageParameters params) {
+ setupPage("", "");
+
+ // default values
+ ArrayList<String> repositories = new ArrayList<String>();
+ String query = "";
+ int page = 1;
+ int pageSize = GitBlit.getInteger(Keys.web.itemsPerPage, 50);
+
+ if (params != null) {
+ String repository = WicketUtils.getRepositoryName(params);
+ if (!StringUtils.isEmpty(repository)) {
+ repositories.add(repository);
+ }
+
+ page = WicketUtils.getPage(params);
+
+ if (params.containsKey("repositories")) {
+ String value = params.getString("repositories", "");
+ List<String> list = StringUtils.getStringsFromValue(value);
+ repositories.addAll(list);
+ }
+
+ if (params.containsKey("query")) {
+ query = params.getString("query", "");
+ } else {
+ String value = WicketUtils.getSearchString(params);
+ String type = WicketUtils.getSearchType(params);
+ com.gitblit.Constants.SearchType searchType = com.gitblit.Constants.SearchType.forName(type);
+ if (!StringUtils.isEmpty(value)) {
+ if (searchType == SearchType.COMMIT) {
+ query = "type:" + searchType.name().toLowerCase() + " AND \"" + value + "\"";
+ } else {
+ query = searchType.name().toLowerCase() + ":\"" + value + "\"";
+ }
+ }
+ }
+ }
+
+ // display user-accessible selections
+ UserModel user = GitBlitWebSession.get().getUser();
+ List<String> availableRepositories = new ArrayList<String>();
+ for (RepositoryModel model : GitBlit.self().getRepositoryModels(user)) {
+ if (model.hasCommits && !ArrayUtils.isEmpty(model.indexedBranches)) {
+ availableRepositories.add(model.name);
+ }
+ }
+ boolean luceneEnabled = GitBlit.getBoolean(Keys.web.allowLuceneIndexing, true);
+ if (luceneEnabled) {
+ if (availableRepositories.size() == 0) {
+ info(getString("gb.noIndexedRepositoriesWarning"));
+ }
+ } else {
+ error(getString("gb.luceneDisabled"));
+ }
+
+ // enforce user-accessible repository selections
+ ArrayList<String> searchRepositories = new ArrayList<String>();
+ for (String selectedRepository : repositories) {
+ if (availableRepositories.contains(selectedRepository)) {
+ searchRepositories.add(selectedRepository);
+ }
+ }
+
+ // search form
+ final Model<String> queryModel = new Model<String>(query);
+ final Model<ArrayList<String>> repositoriesModel = new Model<ArrayList<String>>(searchRepositories);
+ SessionlessForm<Void> form = new SessionlessForm<Void>("searchForm", getClass()) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onSubmit() {
+ String q = queryModel.getObject();
+ if (StringUtils.isEmpty(q)) {
+ error(getString("gb.undefinedQueryWarning"));
+ return;
+ }
+ if (repositoriesModel.getObject().size() == 0) {
+ error(getString("gb.noSelectedRepositoriesWarning"));
+ return;
+ }
+ PageParameters params = new PageParameters();
+ params.put("repositories", StringUtils.flattenStrings(repositoriesModel.getObject()));
+ params.put("query", queryModel.getObject());
+ LuceneSearchPage page = new LuceneSearchPage(params);
+ setResponsePage(page);
+ }
+ };
+
+ ListMultipleChoice<String> selections = new ListMultipleChoice<String>("repositories",
+ repositoriesModel, availableRepositories, new StringChoiceRenderer());
+ selections.setMaxRows(8);
+ form.add(selections.setEnabled(luceneEnabled));
+ form.add(new TextField<String>("query", queryModel).setEnabled(luceneEnabled));
+ add(form.setEnabled(luceneEnabled));
+
+ // execute search
+ final List<SearchResult> results = new ArrayList<SearchResult>();
+ if (!ArrayUtils.isEmpty(searchRepositories) && !StringUtils.isEmpty(query)) {
+ results.addAll(GitBlit.self().search(query, page, pageSize, searchRepositories));
+ }
+
+ // results header
+ if (results.size() == 0) {
+ if (!ArrayUtils.isEmpty(searchRepositories) && !StringUtils.isEmpty(query)) {
+ add(new Label("resultsHeader", query).setRenderBodyOnly(true));
+ add(new Label("resultsCount", getString("gb.noHits")).setRenderBodyOnly(true));
+ } else {
+ add(new Label("resultsHeader").setVisible(false));
+ add(new Label("resultsCount").setVisible(false));
+ }
+ } else {
+ add(new Label("resultsHeader", query).setRenderBodyOnly(true));
+ add(new Label("resultsCount", MessageFormat.format(getString("gb.queryResults"),
+ results.get(0).hitId, results.get(results.size() - 1).hitId, results.get(0).totalHits)).
+ setRenderBodyOnly(true));
+ }
+
+ // search results view
+ ListDataProvider<SearchResult> resultsDp = new ListDataProvider<SearchResult>(results);
+ final DataView<SearchResult> resultsView = new DataView<SearchResult>("searchResults", resultsDp) {
+ private static final long serialVersionUID = 1L;
+ public void populateItem(final Item<SearchResult> item) {
+ final SearchResult sr = item.getModelObject();
+ switch(sr.type) {
+ case commit: {
+ Label icon = WicketUtils.newIcon("type", "icon-refresh");
+ WicketUtils.setHtmlTooltip(icon, "commit");
+ item.add(icon);
+ item.add(new LinkPanel("summary", null, sr.summary, CommitPage.class, WicketUtils.newObjectParameter(sr.repository, sr.commitId)));
+ // show tags
+ Fragment fragment = new Fragment("tags", "tagsPanel", LuceneSearchPage.this);
+ List<String> tags = sr.tags;
+ if (tags == null) {
+ tags = new ArrayList<String>();
+ }
+ ListDataProvider<String> tagsDp = new ListDataProvider<String>(tags);
+ final DataView<String> tagsView = new DataView<String>("tag", tagsDp) {
+ private static final long serialVersionUID = 1L;
+ public void populateItem(final Item<String> item) {
+ String tag = item.getModelObject();
+ Component c = new LinkPanel("tagLink", null, tag, TagPage.class,
+ WicketUtils.newObjectParameter(sr.repository, Constants.R_TAGS + tag));
+ WicketUtils.setCssClass(c, "tagRef");
+ item.add(c);
+ }
+ };
+ fragment.add(tagsView);
+ item.add(fragment);
+ break;
+ }
+ case blob: {
+ Label icon = WicketUtils.newIcon("type", "icon-file");
+ WicketUtils.setHtmlTooltip(icon, "blob");
+ item.add(icon);
+ item.add(new LinkPanel("summary", null, sr.path, BlobPage.class, WicketUtils.newPathParameter(sr.repository, sr.branch, sr.path)));
+ item.add(new Label("tags").setVisible(false));
+ break;
+ }
+ case issue: {
+ Label icon = WicketUtils.newIcon("type", "icon-file");
+ WicketUtils.setHtmlTooltip(icon, "issue");
+ item.add(icon);
+ item.add(new Label("summary", "issue: " + sr.issueId));
+ item.add(new Label("tags").setVisible(false));
+ break;
+ }
+ }
+ item.add(new Label("fragment", sr.fragment).setEscapeModelStrings(false).setVisible(!StringUtils.isEmpty(sr.fragment)));
+ item.add(new LinkPanel("repository", null, sr.repository, SummaryPage.class, WicketUtils.newRepositoryParameter(sr.repository)));
+ if (StringUtils.isEmpty(sr.branch)) {
+ item.add(new Label("branch", "null"));
+ } else {
+ item.add(new LinkPanel("branch", "branch", StringUtils.getRelativePath(Constants.R_HEADS, sr.branch), LogPage.class, WicketUtils.newObjectParameter(sr.repository, sr.branch)));
+ }
+ item.add(new Label("author", sr.author));
+ item.add(WicketUtils.createDatestampLabel("date", sr.date, getTimeZone(), getTimeUtils()));
+ }
+ };
+ add(resultsView.setVisible(results.size() > 0));
+
+ PageParameters pagerParams = new PageParameters();
+ pagerParams.put("repositories", StringUtils.flattenStrings(repositoriesModel.getObject()));
+ pagerParams.put("query", queryModel.getObject());
+
+ boolean showPager = false;
+ int totalPages = 0;
+ if (results.size() > 0) {
+ totalPages = (results.get(0).totalHits / pageSize) + (results.get(0).totalHits % pageSize > 0 ? 1 : 0);
+ showPager = results.get(0).totalHits > pageSize;
+ }
+
+ add(new PagerPanel("topPager", page, totalPages, LuceneSearchPage.class, pagerParams).setVisible(showPager));
+ add(new PagerPanel("bottomPager", page, totalPages, LuceneSearchPage.class, pagerParams).setVisible(showPager));
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/MarkdownPage.html b/src/main/java/com/gitblit/wicket/pages/MarkdownPage.html new file mode 100644 index 00000000..7900625b --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/MarkdownPage.html @@ -0,0 +1,18 @@ +<!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:extend>
+ <!-- markdown nav links -->
+ <div class="page_nav2">
+ <a wicket:id="blameLink"><wicket:message key="gb.blame"></wicket:message></a> | <a wicket:id="historyLink"><wicket:message key="gb.history"></wicket:message></a> | <a wicket:id="rawLink"><wicket:message key="gb.raw"></wicket:message></a> | <a wicket:id="headLink"><wicket:message key="gb.head"></wicket:message></a>
+ </div>
+
+ <!-- markdown content -->
+ <div class="markdown" style="padding-bottom:5px;" wicket:id="markdownText">[markdown content]</div>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/MarkdownPage.java b/src/main/java/com/gitblit/wicket/pages/MarkdownPage.java new file mode 100644 index 00000000..e032cbf9 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/MarkdownPage.java @@ -0,0 +1,73 @@ +/*
+ * Copyright 2011 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.text.MessageFormat;
+import java.text.ParseException;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import com.gitblit.GitBlit;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.MarkdownUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+
+public class MarkdownPage extends RepositoryPage {
+
+ public MarkdownPage(PageParameters params) {
+ super(params);
+
+ final String markdownPath = WicketUtils.getPath(params);
+
+ Repository r = getRepository();
+ RevCommit commit = JGitUtils.getCommit(r, objectId);
+ String [] encodings = GitBlit.getEncodings();
+
+ // markdown page links
+ add(new BookmarkablePageLink<Void>("blameLink", BlamePage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, markdownPath)));
+ add(new BookmarkablePageLink<Void>("historyLink", HistoryPage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, markdownPath)));
+ add(new BookmarkablePageLink<Void>("rawLink", RawPage.class, WicketUtils.newPathParameter(
+ repositoryName, objectId, markdownPath)));
+ add(new BookmarkablePageLink<Void>("headLink", MarkdownPage.class,
+ WicketUtils.newPathParameter(repositoryName, Constants.HEAD, markdownPath)));
+
+ // Read raw markdown content and transform it to html
+ String markdownText = JGitUtils.getStringContent(r, commit.getTree(), markdownPath, encodings);
+ String htmlText;
+ try {
+ htmlText = MarkdownUtils.transformMarkdown(markdownText);
+ } catch (ParseException p) {
+ markdownText = MessageFormat.format("<div class=\"alert alert-error\"><strong>{0}:</strong> {1}</div>{2}", getString("gb.error"), getString("gb.markdownFailure"), markdownText);
+ htmlText = StringUtils.breakLinesForHtml(markdownText);
+ }
+
+ // Add the html to the page
+ add(new Label("markdownText", htmlText).setEscapeModelStrings(false));
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.markdown");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/MetricsPage.html b/src/main/java/com/gitblit/wicket/pages/MetricsPage.html new file mode 100644 index 00000000..4aefc798 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/MetricsPage.html @@ -0,0 +1,44 @@ +<!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:extend>
+<div style="padding-top:10px;">
+ <!-- branch name -->
+ <div><span class="metricsTitle" wicket:id="branchTitle"></span></div>
+
+ <table style="width:100%;">
+ <tr>
+ <!-- branch stats -->
+ <td colspan=2>
+ <h2><wicket:message key="gb.stats"></wicket:message></h2>
+ <span wicket:id="branchStats"></span>
+ </td>
+ </tr>
+ <tr>
+ <!-- commit activity trend -->
+ <td>
+ <h2><wicket:message key="gb.commitActivityTrend"></wicket:message></h2>
+ <div><img wicket:id="commitsChart" /></div>
+ </td>
+ <!-- commit activity by day of week -->
+ <td>
+ <h2><wicket:message key="gb.commitActivityDOW"></wicket:message></h2>
+ <div><img wicket:id="dayOfWeekChart" /></div>
+ </td>
+ </tr>
+ <tr>
+ <!-- commit activity by primary authors -->
+ <td colspan=2>
+ <h2><wicket:message key="gb.commitActivityAuthors"></wicket:message></h2>
+ <div style="text-align: center;"><img wicket:id="authorsChart" /></div>
+ </td>
+ </tr>
+ </table>
+</div>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/MetricsPage.java b/src/main/java/com/gitblit/wicket/pages/MetricsPage.java new file mode 100644 index 00000000..5904a64a --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/MetricsPage.java @@ -0,0 +1,184 @@ +/*
+ * Copyright 2011 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.awt.Color;
+import java.awt.Dimension;
+import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.eclipse.jgit.lib.Repository;
+import org.wicketstuff.googlecharts.Chart;
+import org.wicketstuff.googlecharts.ChartAxis;
+import org.wicketstuff.googlecharts.ChartAxisType;
+import org.wicketstuff.googlecharts.ChartProvider;
+import org.wicketstuff.googlecharts.ChartType;
+import org.wicketstuff.googlecharts.IChartData;
+import org.wicketstuff.googlecharts.LineStyle;
+import org.wicketstuff.googlecharts.MarkerType;
+import org.wicketstuff.googlecharts.ShapeMarker;
+
+import com.gitblit.models.Metric;
+import com.gitblit.utils.MetricUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+
+public class MetricsPage extends RepositoryPage {
+
+ public MetricsPage(PageParameters params) {
+ super(params);
+ Repository r = getRepository();
+ if (StringUtils.isEmpty(objectId)) {
+ add(new Label("branchTitle", getRepositoryModel().HEAD));
+ } else {
+ add(new Label("branchTitle", objectId));
+ }
+ Metric metricsTotal = null;
+ List<Metric> metrics = MetricUtils.getDateMetrics(r, objectId, true, null, getTimeZone());
+ metricsTotal = metrics.remove(0);
+ if (metricsTotal == null) {
+ add(new Label("branchStats", ""));
+ } else {
+ add(new Label("branchStats",
+ MessageFormat.format(getString("gb.branchStats"), metricsTotal.count,
+ metricsTotal.tag, getTimeUtils().duration(metricsTotal.duration))));
+ }
+ insertLinePlot("commitsChart", metrics);
+ insertBarPlot("dayOfWeekChart", getDayOfWeekMetrics(r, objectId));
+ insertPieChart("authorsChart", getAuthorMetrics(r, objectId));
+ }
+
+ private void insertLinePlot(String wicketId, List<Metric> metrics) {
+ if ((metrics != null) && (metrics.size() > 0)) {
+ IChartData data = WicketUtils.getChartData(metrics);
+
+ ChartProvider provider = new ChartProvider(new Dimension(400, 100), ChartType.LINE,
+ data);
+ ChartAxis dateAxis = new ChartAxis(ChartAxisType.BOTTOM);
+ dateAxis.setLabels(new String[] { metrics.get(0).name,
+ metrics.get(metrics.size() / 2).name, metrics.get(metrics.size() - 1).name });
+ provider.addAxis(dateAxis);
+
+ ChartAxis commitAxis = new ChartAxis(ChartAxisType.LEFT);
+ commitAxis.setLabels(new String[] { "",
+ String.valueOf((int) WicketUtils.maxValue(metrics)) });
+ provider.addAxis(commitAxis);
+
+ provider.setLineStyles(new LineStyle[] { new LineStyle(2, 4, 0), new LineStyle(0, 4, 1) });
+ provider.addShapeMarker(new ShapeMarker(MarkerType.CIRCLE, Color.BLUE, 1, -1, 5));
+
+ add(new Chart(wicketId, provider));
+ } else {
+ add(WicketUtils.newBlankImage(wicketId));
+ }
+ }
+
+ private void insertBarPlot(String wicketId, List<Metric> metrics) {
+ if ((metrics != null) && (metrics.size() > 0)) {
+ IChartData data = WicketUtils.getChartData(metrics);
+
+ ChartProvider provider = new ChartProvider(new Dimension(400, 100),
+ ChartType.BAR_VERTICAL_SET, data);
+ ChartAxis dateAxis = new ChartAxis(ChartAxisType.BOTTOM);
+ List<String> labels = new ArrayList<String>();
+ for (Metric metric : metrics) {
+ labels.add(metric.name);
+ }
+ dateAxis.setLabels(labels.toArray(new String[labels.size()]));
+ provider.addAxis(dateAxis);
+
+ ChartAxis commitAxis = new ChartAxis(ChartAxisType.LEFT);
+ commitAxis.setLabels(new String[] { "",
+ String.valueOf((int) WicketUtils.maxValue(metrics)) });
+ provider.addAxis(commitAxis);
+
+ add(new Chart(wicketId, provider));
+ } else {
+ add(WicketUtils.newBlankImage(wicketId));
+ }
+ }
+
+ private void insertPieChart(String wicketId, List<Metric> metrics) {
+ if ((metrics != null) && (metrics.size() > 0)) {
+ IChartData data = WicketUtils.getChartData(metrics);
+ List<String> labels = new ArrayList<String>();
+ for (Metric metric : metrics) {
+ labels.add(metric.name);
+ }
+ ChartProvider provider = new ChartProvider(new Dimension(800, 200), ChartType.PIE, data);
+ provider.setPieLabels(labels.toArray(new String[labels.size()]));
+ add(new Chart(wicketId, provider));
+ } else {
+ add(WicketUtils.newBlankImage(wicketId));
+ }
+ }
+
+ private List<Metric> getDayOfWeekMetrics(Repository repository, String objectId) {
+ List<Metric> list = MetricUtils.getDateMetrics(repository, objectId, false, "E", getTimeZone());
+ SimpleDateFormat sdf = new SimpleDateFormat("E");
+ Calendar cal = Calendar.getInstance();
+
+ List<Metric> sorted = new ArrayList<Metric>();
+ int firstDayOfWeek = cal.getFirstDayOfWeek();
+ int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
+
+ // rewind date to first day of week
+ cal.add(Calendar.DATE, firstDayOfWeek - dayOfWeek);
+ for (int i = 0; i < 7; i++) {
+ String day = sdf.format(cal.getTime());
+ for (Metric metric : list) {
+ if (metric.name.equals(day)) {
+ sorted.add(metric);
+ list.remove(metric);
+ break;
+ }
+ }
+ cal.add(Calendar.DATE, 1);
+ }
+ return sorted;
+ }
+
+ private List<Metric> getAuthorMetrics(Repository repository, String objectId) {
+ List<Metric> authors = MetricUtils.getAuthorMetrics(repository, objectId, true);
+ Collections.sort(authors, new Comparator<Metric>() {
+ @Override
+ public int compare(Metric o1, Metric o2) {
+ if (o1.count > o2.count) {
+ return -1;
+ } else if (o1.count < o2.count) {
+ return 1;
+ }
+ return 0;
+ }
+ });
+ if (authors.size() > 10) {
+ return authors.subList(0, 9);
+ }
+ return authors;
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.metrics");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/PatchPage.html b/src/main/java/com/gitblit/wicket/pages/PatchPage.html new file mode 100644 index 00000000..719a46d1 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/PatchPage.html @@ -0,0 +1,13 @@ +<!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>
+
+ <!-- patch content -->
+ <pre style="border:0px;" wicket:id="patchText">[patch content]</pre>
+
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/PatchPage.java b/src/main/java/com/gitblit/wicket/pages/PatchPage.java new file mode 100644 index 00000000..878cfb45 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/PatchPage.java @@ -0,0 +1,69 @@ +/*
+ * Copyright 2011 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 org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.markup.html.basic.Label;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import com.gitblit.GitBlit;
+import com.gitblit.utils.DiffUtils;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.WicketUtils;
+
+public class PatchPage extends WebPage {
+
+ public PatchPage(PageParameters params) {
+ super(params);
+
+ if (!params.containsKey("r")) {
+ GitBlitWebSession.get().cacheErrorMessage(getString("gb.repositoryNotSpecified"));
+ redirectToInterceptPage(new RepositoriesPage());
+ return;
+ }
+
+ final String repositoryName = WicketUtils.getRepositoryName(params);
+ final String baseObjectId = WicketUtils.getBaseObjectId(params);
+ final String objectId = WicketUtils.getObject(params);
+ final String blobPath = WicketUtils.getPath(params);
+
+ Repository r = GitBlit.self().getRepository(repositoryName);
+ if (r == null) {
+ GitBlitWebSession.get().cacheErrorMessage(getString("gb.canNotLoadRepository") + " " + repositoryName);
+ redirectToInterceptPage(new RepositoriesPage());
+ return;
+ }
+
+ RevCommit commit = JGitUtils.getCommit(r, objectId);
+ if (commit == null) {
+ GitBlitWebSession.get().cacheErrorMessage(getString("gb.commitIsNull"));
+ redirectToInterceptPage(new RepositoriesPage());
+ return;
+ }
+
+ RevCommit baseCommit = null;
+ if (!StringUtils.isEmpty(baseObjectId)) {
+ baseCommit = JGitUtils.getCommit(r, baseObjectId);
+ }
+ String patch = DiffUtils.getCommitPatch(r, baseCommit, commit, blobPath);
+ add(new Label("patchText", patch));
+ r.close();
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/ProjectPage.html b/src/main/java/com/gitblit/wicket/pages/ProjectPage.html new file mode 100644 index 00000000..3e73ba52 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ProjectPage.html @@ -0,0 +1,70 @@ +<!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:extend>
+
+
+ <div class="row">
+ <div class="span12">
+ <h2><span wicket:id="projectTitle"></span> <small><span wicket:id="projectDescription"></span></small>
+ <a class="hidden-phone hidden-tablet brand" style="text-decoration: none;" wicket:id="syndication" wicket:message="title:gb.feed">
+ <img style="border:0px;vertical-align:middle;" src="feed_16x16.png"></img>
+ </a>
+ </h2>
+ <div class="markdown" wicket:id="projectMessage">[project message]</div>
+ </div>
+ </div>
+
+ <div class="tabbable">
+ <!-- tab titles -->
+ <ul class="nav nav-tabs">
+ <li class="active"><a href="#repositories" data-toggle="tab"><wicket:message key="gb.repositories"></wicket:message></a></li>
+ <li ><a href="#activity" data-toggle="tab"><wicket:message key="gb.activity"></wicket:message></a></li>
+ </ul>
+
+ <!-- tab content -->
+ <div class="tab-content">
+
+ <!-- repositories tab -->
+ <div class="tab-pane active" id="repositories">
+ <!-- markdown -->
+ <div class="row">
+ <div class="span12">
+ <div class="markdown" wicket:id="repositoriesMessage">[repositories message]</div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="span6" style="border-bottom:1px solid #eee;" wicket:id="repositoryList">
+ <span wicket:id="repository"></span>
+ </div>
+ </div>
+ </div>
+
+ <!-- activity tab -->
+ <div class="tab-pane" id="activity">
+ <div class="pageTitle">
+ <h2><wicket:message key="gb.recentActivity"></wicket:message><small> <span class="hidden-phone">/ <span wicket:id="subheader">[days back]</span></span></small></h2>
+ </div>
+
+ <div class="hidden-phone" style="height: 155px;text-align: center;">
+ <table>
+ <tr>
+ <td><span class="hidden-tablet" id="chartDaily"></span></td>
+ <td><span id="chartRepositories"></span></td>
+ <td><span id="chartAuthors"></span></td>
+ </tr>
+ </table>
+ </div>
+
+ <div wicket:id="activityPanel">[activity panel]</div>
+ </div>
+
+ </div>
+ </div>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/ProjectPage.java b/src/main/java/com/gitblit/wicket/pages/ProjectPage.java new file mode 100644 index 00000000..7eba0331 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ProjectPage.java @@ -0,0 +1,355 @@ +/*
+ * Copyright 2012 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.text.MessageFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.behavior.HeaderContributor;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.ExternalLink;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.SyndicationServlet;
+import com.gitblit.models.Activity;
+import com.gitblit.models.Metric;
+import com.gitblit.models.ProjectModel;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.utils.ActivityUtils;
+import com.gitblit.utils.MarkdownUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebApp;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.GitblitRedirectException;
+import com.gitblit.wicket.PageRegistration;
+import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
+import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.charting.GoogleChart;
+import com.gitblit.wicket.charting.GoogleCharts;
+import com.gitblit.wicket.charting.GoogleLineChart;
+import com.gitblit.wicket.charting.GooglePieChart;
+import com.gitblit.wicket.panels.ActivityPanel;
+import com.gitblit.wicket.panels.ProjectRepositoryPanel;
+
+public class ProjectPage extends RootPage {
+
+ List<ProjectModel> projectModels = new ArrayList<ProjectModel>();
+
+ public ProjectPage() {
+ super();
+ throw new GitblitRedirectException(GitBlitWebApp.get().getHomePage());
+ }
+
+ public ProjectPage(PageParameters params) {
+ super(params);
+ setup(params);
+ }
+
+ @Override
+ protected boolean reusePageParameters() {
+ return true;
+ }
+
+ private void setup(PageParameters params) {
+ setupPage("", "");
+ // check to see if we should display a login message
+ boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, true);
+ if (authenticateView && !GitBlitWebSession.get().isLoggedIn()) {
+ authenticationError("Please login");
+ return;
+ }
+
+ String projectName = WicketUtils.getProjectName(params);
+ if (StringUtils.isEmpty(projectName)) {
+ throw new GitblitRedirectException(GitBlitWebApp.get().getHomePage());
+ }
+
+ ProjectModel project = getProjectModel(projectName);
+ if (project == null) {
+ throw new GitblitRedirectException(GitBlitWebApp.get().getHomePage());
+ }
+
+ add(new Label("projectTitle", project.getDisplayName()));
+ add(new Label("projectDescription", project.description));
+
+ String feedLink = SyndicationServlet.asLink(getRequest().getRelativePathPrefixToContextRoot(), projectName, null, 0);
+ add(new ExternalLink("syndication", feedLink));
+
+ add(WicketUtils.syndicationDiscoveryLink(SyndicationServlet.getTitle(project.getDisplayName(),
+ null), feedLink));
+
+ // project markdown message
+ String pmessage = transformMarkdown(project.projectMarkdown);
+ Component projectMessage = new Label("projectMessage", pmessage)
+ .setEscapeModelStrings(false).setVisible(pmessage.length() > 0);
+ add(projectMessage);
+
+ // markdown message above repositories list
+ String rmessage = transformMarkdown(project.repositoriesMarkdown);
+ Component repositoriesMessage = new Label("repositoriesMessage", rmessage)
+ .setEscapeModelStrings(false).setVisible(rmessage.length() > 0);
+ add(repositoriesMessage);
+
+ List<RepositoryModel> repositories = getRepositories(params);
+
+ Collections.sort(repositories, new Comparator<RepositoryModel>() {
+ @Override
+ public int compare(RepositoryModel o1, RepositoryModel o2) {
+ // reverse-chronological sort
+ return o2.lastChange.compareTo(o1.lastChange);
+ }
+ });
+
+ final ListDataProvider<RepositoryModel> dp = new ListDataProvider<RepositoryModel>(repositories);
+ DataView<RepositoryModel> dataView = new DataView<RepositoryModel>("repositoryList", dp) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<RepositoryModel> item) {
+ final RepositoryModel entry = item.getModelObject();
+
+ ProjectRepositoryPanel row = new ProjectRepositoryPanel("repository",
+ getLocalizer(), this, showAdmin, entry, getAccessRestrictions());
+ item.add(row);
+ }
+ };
+ add(dataView);
+
+ // project activity
+ // parameters
+ int daysBack = WicketUtils.getDaysBack(params);
+ if (daysBack < 1) {
+ daysBack = 14;
+ }
+ String objectId = WicketUtils.getObject(params);
+
+ List<Activity> recentActivity = ActivityUtils.getRecentActivity(repositories,
+ daysBack, objectId, getTimeZone());
+ if (recentActivity.size() == 0) {
+ // no activity, skip graphs and activity panel
+ add(new Label("subheader", MessageFormat.format(getString("gb.recentActivityNone"),
+ daysBack)));
+ add(new Label("activityPanel"));
+ } else {
+ // calculate total commits and total authors
+ int totalCommits = 0;
+ Set<String> uniqueAuthors = new HashSet<String>();
+ for (Activity activity : recentActivity) {
+ totalCommits += activity.getCommitCount();
+ uniqueAuthors.addAll(activity.getAuthorMetrics().keySet());
+ }
+ int totalAuthors = uniqueAuthors.size();
+
+ // add the subheader with stat numbers
+ add(new Label("subheader", MessageFormat.format(getString("gb.recentActivityStats"),
+ daysBack, totalCommits, totalAuthors)));
+
+ // create the activity charts
+ GoogleCharts charts = createCharts(recentActivity);
+ add(new HeaderContributor(charts));
+
+ // add activity panel
+ add(new ActivityPanel("activityPanel", recentActivity));
+ }
+ }
+
+ /**
+ * Creates the daily activity line chart, the active repositories pie chart,
+ * and the active authors pie chart
+ *
+ * @param recentActivity
+ * @return
+ */
+ private GoogleCharts createCharts(List<Activity> recentActivity) {
+ // activity metrics
+ Map<String, Metric> repositoryMetrics = new HashMap<String, Metric>();
+ Map<String, Metric> authorMetrics = new HashMap<String, Metric>();
+
+ // aggregate repository and author metrics
+ for (Activity activity : recentActivity) {
+
+ // aggregate author metrics
+ for (Map.Entry<String, Metric> entry : activity.getAuthorMetrics().entrySet()) {
+ String author = entry.getKey();
+ if (!authorMetrics.containsKey(author)) {
+ authorMetrics.put(author, new Metric(author));
+ }
+ authorMetrics.get(author).count += entry.getValue().count;
+ }
+
+ // aggregate repository metrics
+ for (Map.Entry<String, Metric> entry : activity.getRepositoryMetrics().entrySet()) {
+ String repository = StringUtils.stripDotGit(entry.getKey());
+ if (!repositoryMetrics.containsKey(repository)) {
+ repositoryMetrics.put(repository, new Metric(repository));
+ }
+ repositoryMetrics.get(repository).count += entry.getValue().count;
+ }
+ }
+
+ // build google charts
+ int w = 310;
+ int h = 150;
+ GoogleCharts charts = new GoogleCharts();
+
+ // sort in reverse-chronological order and then reverse that
+ Collections.sort(recentActivity);
+ Collections.reverse(recentActivity);
+
+ // daily line chart
+ GoogleChart chart = new GoogleLineChart("chartDaily", getString("gb.dailyActivity"), "day",
+ getString("gb.commits"));
+ SimpleDateFormat df = new SimpleDateFormat("MMM dd");
+ df.setTimeZone(getTimeZone());
+ for (Activity metric : recentActivity) {
+ chart.addValue(df.format(metric.startDate), metric.getCommitCount());
+ }
+ chart.setWidth(w);
+ chart.setHeight(h);
+ charts.addChart(chart);
+
+ // active repositories pie chart
+ chart = new GooglePieChart("chartRepositories", getString("gb.activeRepositories"),
+ getString("gb.repository"), getString("gb.commits"));
+ for (Metric metric : repositoryMetrics.values()) {
+ chart.addValue(metric.name, metric.count);
+ }
+ chart.setWidth(w);
+ chart.setHeight(h);
+ charts.addChart(chart);
+
+ // active authors pie chart
+ chart = new GooglePieChart("chartAuthors", getString("gb.activeAuthors"),
+ getString("gb.author"), getString("gb.commits"));
+ for (Metric metric : authorMetrics.values()) {
+ chart.addValue(metric.name, metric.count);
+ }
+ chart.setWidth(w);
+ chart.setHeight(h);
+ charts.addChart(chart);
+
+ return charts;
+ }
+
+ @Override
+ protected void addDropDownMenus(List<PageRegistration> pages) {
+ PageParameters params = getPageParameters();
+
+ DropDownMenuRegistration projects = new DropDownMenuRegistration("gb.projects",
+ ProjectPage.class);
+ projects.menuItems.addAll(getProjectsMenu());
+ pages.add(0, projects);
+
+ DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters",
+ ProjectPage.class);
+ // preserve time filter option on repository choices
+ menu.menuItems.addAll(getRepositoryFilterItems(params));
+
+ // preserve repository filter option on time choices
+ menu.menuItems.addAll(getTimeFilterItems(params));
+
+ if (menu.menuItems.size() > 0) {
+ // Reset Filter
+ menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null));
+ }
+
+ pages.add(menu);
+ }
+
+ @Override
+ protected List<ProjectModel> getProjectModels() {
+ if (projectModels.isEmpty()) {
+ List<RepositoryModel> repositories = getRepositoryModels();
+ List<ProjectModel> projects = GitBlit.self().getProjectModels(repositories, false);
+ projectModels.addAll(projects);
+ }
+ return projectModels;
+ }
+
+ private ProjectModel getProjectModel(String name) {
+ for (ProjectModel project : getProjectModels()) {
+ if (name.equalsIgnoreCase(project.name)) {
+ return project;
+ }
+ }
+ return null;
+ }
+
+ protected List<DropDownMenuItem> getProjectsMenu() {
+ List<DropDownMenuItem> menu = new ArrayList<DropDownMenuItem>();
+ List<ProjectModel> projects = new ArrayList<ProjectModel>();
+ for (ProjectModel model : getProjectModels()) {
+ if (!model.isUserProject()) {
+ projects.add(model);
+ }
+ }
+ int maxProjects = 15;
+ boolean showAllProjects = projects.size() > maxProjects;
+ if (showAllProjects) {
+
+ // sort by last changed
+ Collections.sort(projects, new Comparator<ProjectModel>() {
+ @Override
+ public int compare(ProjectModel o1, ProjectModel o2) {
+ return o2.lastChange.compareTo(o1.lastChange);
+ }
+ });
+
+ // take most recent subset
+ projects = projects.subList(0, maxProjects);
+
+ // sort those by name
+ Collections.sort(projects);
+ }
+
+ for (ProjectModel project : projects) {
+ menu.add(new DropDownMenuItem(project.getDisplayName(), "p", project.name));
+ }
+ if (showAllProjects) {
+ menu.add(new DropDownMenuItem());
+ menu.add(new DropDownMenuItem("all projects", null, null));
+ }
+ return menu;
+ }
+
+ private String transformMarkdown(String markdown) {
+ String message = "";
+ if (!StringUtils.isEmpty(markdown)) {
+ // Read user-supplied message
+ try {
+ message = MarkdownUtils.transformMarkdown(markdown);
+ } catch (Throwable t) {
+ message = getString("gb.failedToRead") + " " + markdown;
+ warn(message, t);
+ }
+ }
+ return message;
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/ProjectsPage.html b/src/main/java/com/gitblit/wicket/pages/ProjectsPage.html new file mode 100644 index 00000000..528ed48f --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ProjectsPage.html @@ -0,0 +1,37 @@ +<!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:extend>
+ <div class="markdown" style="padding-bottom:5px;" wicket:id="projectsMessage">[projects message]</div>
+
+ <table class="repositories">
+ <thead>
+ <tr>
+ <th class="left">
+ <i class="icon-folder-close" ></i>
+ <wicket:message key="gb.project">Project</wicket:message>
+ </th>
+ <th class="hidden-phone" ><span><wicket:message key="gb.description">Description</wicket:message></span></th>
+ <th class="hidden-phone"><wicket:message key="gb.repositories">Repositories</wicket:message></th>
+ <th><wicket:message key="gb.lastChange">Last Change</wicket:message></th>
+ <th class="right"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr wicket:id="project">
+ <td class="left" style="padding-left:3px;" ><span style="padding-left:3px;" wicket:id="projectTitle">[project title]</span></td>
+ <td class="hidden-phone"><span class="list" wicket:id="projectDescription">[project description]</span></td>
+ <td class="hidden-phone" style="padding-right:15px;"><span style="font-size:0.8em;" wicket:id="repositoryCount">[repository count]</span></td>
+ <td><span wicket:id="projectLastChange">[last change]</span></td>
+ <td class="rightAlign"></td>
+ </tr>
+ </tbody>
+ </table>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/ProjectsPage.java b/src/main/java/com/gitblit/wicket/pages/ProjectsPage.java new file mode 100644 index 00000000..7f0b002e --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ProjectsPage.java @@ -0,0 +1,235 @@ +/*
+ * Copyright 2012 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.FileInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.apache.wicket.resource.ContextRelativeResource;
+import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
+import org.eclipse.jgit.lib.Constants;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.ProjectModel;
+import com.gitblit.utils.MarkdownUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.PageRegistration;
+import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
+import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.LinkPanel;
+
+public class ProjectsPage extends RootPage {
+
+ public ProjectsPage() {
+ super();
+ setup(null);
+ }
+
+ public ProjectsPage(PageParameters params) {
+ super(params);
+ setup(params);
+ }
+
+ @Override
+ protected boolean reusePageParameters() {
+ return true;
+ }
+
+ @Override
+ protected List<ProjectModel> getProjectModels() {
+ return GitBlit.self().getProjectModels(getRepositoryModels(), false);
+ }
+
+ private void setup(PageParameters params) {
+ setupPage("", "");
+ // check to see if we should display a login message
+ boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, true);
+ if (authenticateView && !GitBlitWebSession.get().isLoggedIn()) {
+ String messageSource = GitBlit.getString(Keys.web.loginMessage, "gitblit");
+ String message = readMarkdown(messageSource, "login.mkd");
+ Component repositoriesMessage = new Label("projectsMessage", message);
+ add(repositoriesMessage.setEscapeModelStrings(false));
+ add(new Label("projectsPanel"));
+ return;
+ }
+
+ // Load the markdown welcome message
+ String messageSource = GitBlit.getString(Keys.web.repositoriesMessage, "gitblit");
+ String message = readMarkdown(messageSource, "welcome.mkd");
+ Component projectsMessage = new Label("projectsMessage", message).setEscapeModelStrings(
+ false).setVisible(message.length() > 0);
+ add(projectsMessage);
+
+ List<ProjectModel> projects = getProjects(params);
+
+ ListDataProvider<ProjectModel> dp = new ListDataProvider<ProjectModel>(projects);
+
+ DataView<ProjectModel> dataView = new DataView<ProjectModel>("project", dp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+
+ @Override
+ protected void onBeforeRender() {
+ super.onBeforeRender();
+ counter = 0;
+ }
+
+ public void populateItem(final Item<ProjectModel> item) {
+ final ProjectModel entry = item.getModelObject();
+
+ PageParameters pp = WicketUtils.newProjectParameter(entry.name);
+ item.add(new LinkPanel("projectTitle", "list", entry.getDisplayName(),
+ ProjectPage.class, pp));
+ item.add(new LinkPanel("projectDescription", "list", entry.description,
+ ProjectPage.class, pp));
+
+ item.add(new Label("repositoryCount", entry.repositories.size()
+ + " "
+ + (entry.repositories.size() == 1 ? getString("gb.repository")
+ : getString("gb.repositories"))));
+
+ String lastChange;
+ if (entry.lastChange.getTime() == 0) {
+ lastChange = "--";
+ } else {
+ lastChange = getTimeUtils().timeAgo(entry.lastChange);
+ }
+ Label lastChangeLabel = new Label("projectLastChange", lastChange);
+ item.add(lastChangeLabel);
+ WicketUtils.setCssClass(lastChangeLabel, getTimeUtils()
+ .timeAgoCss(entry.lastChange));
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(dataView);
+
+ // push the panel down if we are hiding the admin controls and the
+ // welcome message
+ if (!showAdmin && !projectsMessage.isVisible()) {
+ WicketUtils.setCssStyle(dataView, "padding-top:5px;");
+ }
+ }
+
+ @Override
+ protected void addDropDownMenus(List<PageRegistration> pages) {
+ PageParameters params = getPageParameters();
+
+ pages.add(0, new PageRegistration("gb.projects", ProjectsPage.class, params));
+
+ DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters",
+ ProjectsPage.class);
+ // preserve time filter option on repository choices
+ menu.menuItems.addAll(getRepositoryFilterItems(params));
+
+ // preserve repository filter option on time choices
+ menu.menuItems.addAll(getTimeFilterItems(params));
+
+ if (menu.menuItems.size() > 0) {
+ // Reset Filter
+ menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null));
+ }
+
+ pages.add(menu);
+ }
+
+ private String readMarkdown(String messageSource, String resource) {
+ String message = "";
+ if (messageSource.equalsIgnoreCase("gitblit")) {
+ // Read default message
+ message = readDefaultMarkdown(resource);
+ } else {
+ // Read user-supplied message
+ if (!StringUtils.isEmpty(messageSource)) {
+ File file = new File(messageSource);
+ if (file.exists()) {
+ try {
+ FileInputStream fis = new FileInputStream(file);
+ InputStreamReader reader = new InputStreamReader(fis,
+ Constants.CHARACTER_ENCODING);
+ message = MarkdownUtils.transformMarkdown(reader);
+ reader.close();
+ } catch (Throwable t) {
+ message = getString("gb.failedToRead") + " " + file;
+ warn(message, t);
+ }
+ } else {
+ message = messageSource + " " + getString("gb.isNotValidFile");
+ }
+ }
+ }
+ return message;
+ }
+
+ private String readDefaultMarkdown(String file) {
+ String base = file.substring(0, file.lastIndexOf('.'));
+ String ext = file.substring(file.lastIndexOf('.'));
+ String lc = getLanguageCode();
+ String cc = getCountryCode();
+
+ // try to read file_en-us.ext, file_en.ext, file.ext
+ List<String> files = new ArrayList<String>();
+ if (!StringUtils.isEmpty(lc)) {
+ if (!StringUtils.isEmpty(cc)) {
+ files.add(base + "_" + lc + "-" + cc + ext);
+ files.add(base + "_" + lc + "_" + cc + ext);
+ }
+ files.add(base + "_" + lc + ext);
+ }
+ files.add(file);
+
+ for (String name : files) {
+ String message;
+ InputStreamReader reader = null;
+ try {
+ ContextRelativeResource res = WicketUtils.getResource(name);
+ InputStream is = res.getResourceStream().getInputStream();
+ reader = new InputStreamReader(is, Constants.CHARACTER_ENCODING);
+ message = MarkdownUtils.transformMarkdown(reader);
+ reader.close();
+ return message;
+ } catch (ResourceStreamNotFoundException t) {
+ continue;
+ } catch (Throwable t) {
+ message = MessageFormat.format(getString("gb.failedToReadMessage"), file);
+ error(message, t, false);
+ return message;
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+ }
+ return MessageFormat.format(getString("gb.failedToReadMessage"), file);
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/RawPage.java b/src/main/java/com/gitblit/wicket/pages/RawPage.java new file mode 100644 index 00000000..28e8bae2 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/RawPage.java @@ -0,0 +1,161 @@ +/*
+ * Copyright 2011 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.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.wicket.IRequestTarget;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.RequestCycle;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.protocol.http.WebResponse;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+
+public class RawPage extends WebPage {
+
+ private final Logger logger = LoggerFactory.getLogger(getClass().getSimpleName());
+
+ public RawPage(final PageParameters params) {
+ super(params);
+
+ if (!params.containsKey("r")) {
+ error(getString("gb.repositoryNotSpecified"));
+ redirectToInterceptPage(new RepositoriesPage());
+ }
+
+ getRequestCycle().setRequestTarget(new IRequestTarget() {
+ @Override
+ public void detach(RequestCycle requestCycle) {
+ }
+
+ @Override
+ public void respond(RequestCycle requestCycle) {
+ WebResponse response = (WebResponse) requestCycle.getResponse();
+
+ final String repositoryName = WicketUtils.getRepositoryName(params);
+ final String objectId = WicketUtils.getObject(params);
+ final String blobPath = WicketUtils.getPath(params);
+ String[] encodings = GitBlit.getEncodings();
+
+ Repository r = GitBlit.self().getRepository(repositoryName);
+ if (r == null) {
+ error(getString("gb.canNotLoadRepository") + " " + repositoryName);
+ redirectToInterceptPage(new RepositoriesPage());
+ return;
+ }
+
+ if (StringUtils.isEmpty(blobPath)) {
+ // objectid referenced raw view
+ byte [] binary = JGitUtils.getByteContent(r, objectId);
+ response.setContentType("application/octet-stream");
+ response.setContentLength(binary.length);
+ try {
+ response.getOutputStream().write(binary);
+ } catch (Exception e) {
+ logger.error("Failed to write binary response", e);
+ }
+ } else {
+ // standard raw blob view
+ RevCommit commit = JGitUtils.getCommit(r, objectId);
+
+ String filename = blobPath;
+ if (blobPath.indexOf('/') > -1) {
+ filename = blobPath.substring(blobPath.lastIndexOf('/') + 1);
+ }
+
+ String extension = null;
+ if (blobPath.lastIndexOf('.') > -1) {
+ extension = blobPath.substring(blobPath.lastIndexOf('.') + 1);
+ }
+
+ // Map the extensions to types
+ Map<String, Integer> map = new HashMap<String, Integer>();
+ for (String ext : GitBlit.getStrings(Keys.web.imageExtensions)) {
+ map.put(ext.toLowerCase(), 2);
+ }
+ for (String ext : GitBlit.getStrings(Keys.web.binaryExtensions)) {
+ map.put(ext.toLowerCase(), 3);
+ }
+
+ if (extension != null) {
+ int type = 0;
+ if (map.containsKey(extension)) {
+ type = map.get(extension);
+ }
+ switch (type) {
+ case 2:
+ // image blobs
+ byte[] image = JGitUtils.getByteContent(r, commit.getTree(), blobPath, true);
+ response.setContentType("image/" + extension.toLowerCase());
+ response.setContentLength(image.length);
+ try {
+ response.getOutputStream().write(image);
+ } catch (IOException e) {
+ logger.error("Failed to write image response", e);
+ }
+ break;
+ case 3:
+ // binary blobs (download)
+ byte[] binary = JGitUtils.getByteContent(r, commit.getTree(), blobPath, true);
+ response.setContentLength(binary.length);
+ response.setContentType("application/octet-stream");
+ response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
+ try {
+ response.getOutputStream().write(binary);
+ } catch (IOException e) {
+ logger.error("Failed to write binary response", e);
+ }
+ break;
+ default:
+ // plain text
+ String content = JGitUtils.getStringContent(r, commit.getTree(),
+ blobPath, encodings);
+ response.setContentType("text/plain; charset=UTF-8");
+ try {
+ response.getOutputStream().write(content.getBytes("UTF-8"));
+ } catch (Exception e) {
+ logger.error("Failed to write text response", e);
+ }
+ }
+
+ } else {
+ // plain text
+ String content = JGitUtils.getStringContent(r, commit.getTree(), blobPath,
+ encodings);
+ response.setContentType("text/plain; charset=UTF-8");
+ try {
+ response.getOutputStream().write(content.getBytes("UTF-8"));
+ } catch (Exception e) {
+ logger.error("Failed to write text response", e);
+ }
+ }
+ }
+ r.close();
+ }
+ });
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.html b/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.html new file mode 100644 index 00000000..d2d27157 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.html @@ -0,0 +1,14 @@ +<!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:extend>
+ <div class="markdown" style="padding-bottom:5px;" wicket:id="repositoriesMessage">[repositories message]</div>
+
+ <div wicket:id="repositoriesPanel">[repositories panel]</div>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.java b/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.java new file mode 100644 index 00000000..4bce77f5 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.java @@ -0,0 +1,186 @@ +/*
+ * Copyright 2011 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.FileInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.resource.ContextRelativeResource;
+import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
+import org.eclipse.jgit.lib.Constants;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.utils.MarkdownUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.PageRegistration;
+import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
+import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.RepositoriesPanel;
+
+public class RepositoriesPage extends RootPage {
+
+ public RepositoriesPage() {
+ super();
+ setup(null);
+ }
+
+ public RepositoriesPage(PageParameters params) {
+ super(params);
+ setup(params);
+ }
+
+ @Override
+ protected boolean reusePageParameters() {
+ return true;
+ }
+
+ private void setup(PageParameters params) {
+ setupPage("", "");
+ // check to see if we should display a login message
+ boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, true);
+ if (authenticateView && !GitBlitWebSession.get().isLoggedIn()) {
+ String messageSource = GitBlit.getString(Keys.web.loginMessage, "gitblit");
+ String message = readMarkdown(messageSource, "login.mkd");
+ Component repositoriesMessage = new Label("repositoriesMessage", message);
+ add(repositoriesMessage.setEscapeModelStrings(false));
+ add(new Label("repositoriesPanel"));
+ return;
+ }
+
+ // Load the markdown welcome message
+ String messageSource = GitBlit.getString(Keys.web.repositoriesMessage, "gitblit");
+ String message = readMarkdown(messageSource, "welcome.mkd");
+ Component repositoriesMessage = new Label("repositoriesMessage", message)
+ .setEscapeModelStrings(false).setVisible(message.length() > 0);
+ add(repositoriesMessage);
+
+ List<RepositoryModel> repositories = getRepositories(params);
+
+ RepositoriesPanel repositoriesPanel = new RepositoriesPanel("repositoriesPanel", showAdmin,
+ true, repositories, true, getAccessRestrictions());
+ // push the panel down if we are hiding the admin controls and the
+ // welcome message
+ if (!showAdmin && !repositoriesMessage.isVisible()) {
+ WicketUtils.setCssStyle(repositoriesPanel, "padding-top:5px;");
+ }
+ add(repositoriesPanel);
+ }
+
+ @Override
+ protected void addDropDownMenus(List<PageRegistration> pages) {
+ PageParameters params = getPageParameters();
+
+ DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters",
+ RepositoriesPage.class);
+ // preserve time filter option on repository choices
+ menu.menuItems.addAll(getRepositoryFilterItems(params));
+
+ // preserve repository filter option on time choices
+ menu.menuItems.addAll(getTimeFilterItems(params));
+
+ if (menu.menuItems.size() > 0) {
+ // Reset Filter
+ menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null));
+ }
+
+ pages.add(menu);
+ }
+
+ private String readMarkdown(String messageSource, String resource) {
+ String message = "";
+ if (messageSource.equalsIgnoreCase("gitblit")) {
+ // Read default message
+ message = readDefaultMarkdown(resource);
+ } else {
+ // Read user-supplied message
+ if (!StringUtils.isEmpty(messageSource)) {
+ File file = GitBlit.getFileOrFolder(messageSource);
+ if (file.exists()) {
+ try {
+ FileInputStream fis = new FileInputStream(file);
+ InputStreamReader reader = new InputStreamReader(fis,
+ Constants.CHARACTER_ENCODING);
+ message = MarkdownUtils.transformMarkdown(reader);
+ reader.close();
+ } catch (Throwable t) {
+ message = getString("gb.failedToRead") + " " + file;
+ warn(message, t);
+ }
+ } else {
+ message = messageSource + " " + getString("gb.isNotValidFile");
+ }
+ }
+ }
+ return message;
+ }
+
+ private String readDefaultMarkdown(String file) {
+ String base = file.substring(0, file.lastIndexOf('.'));
+ String ext = file.substring(file.lastIndexOf('.'));
+ String lc = getLanguageCode();
+ String cc = getCountryCode();
+
+ // try to read file_en-us.ext, file_en.ext, file.ext
+ List<String> files = new ArrayList<String>();
+ if (!StringUtils.isEmpty(lc)) {
+ if (!StringUtils.isEmpty(cc)) {
+ files.add(base + "_" + lc + "-" + cc + ext);
+ files.add(base + "_" + lc + "_" + cc + ext);
+ }
+ files.add(base + "_" + lc + ext);
+ }
+ files.add(file);
+
+ for (String name : files) {
+ String message;
+ InputStreamReader reader = null;
+ try {
+ ContextRelativeResource res = WicketUtils.getResource(name);
+ InputStream is = res.getResourceStream().getInputStream();
+ reader = new InputStreamReader(is, Constants.CHARACTER_ENCODING);
+ message = MarkdownUtils.transformMarkdown(reader);
+ reader.close();
+ return message;
+ } catch (ResourceStreamNotFoundException t) {
+ continue;
+ } catch (Throwable t) {
+ message = MessageFormat.format(getString("gb.failedToReadMessage"), file);
+ error(message, t, false);
+ return message;
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+ }
+ return MessageFormat.format(getString("gb.failedToReadMessage"), file);
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.html new file mode 100644 index 00000000..d49f0188 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.html @@ -0,0 +1,82 @@ +<!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:extend>
+ <!-- page nav links -->
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </a>
+ <a class="brand" wicket:id="rootLink">
+ <img src="gitblt_25_white.png" width="79" height="25" alt="gitblit" class="logo"/>
+ </a>
+
+ <div class="nav-collapse" wicket:id="navPanel"></div>
+
+ <a class="hidden-phone hidden-tablet brand" style="text-decoration: none;" wicket:id="syndication" wicket:message="title:gb.feed">
+ <img style="border:0px;vertical-align:middle;" src="feed_16x16.png"></img>
+ </a>
+
+ <form class="hidden-phone hidden-tablet pull-right" style="margin-top:10px;" wicket:id="searchForm">
+ <span class="search">
+ <select class="small" wicket:id="searchType"/>
+ <input type="text" id="searchBox" wicket:id="searchBox" value=""/>
+ </span>
+ </form>
+ </div>
+ </div>
+ </div>
+
+ <!-- page content -->
+ <div class="container">
+ <div style="text-align:center;" wicket:id="feedback">[Feedback Panel]</div>
+
+ <!-- page header -->
+ <div class="pageTitle">
+ <div class="row">
+ <div class="controls">
+ <span wicket:id="workingCopyIndicator"></span>
+ <span class="hidden-phone hidden-tablet" wicket:id="forksProhibitedIndicator"></span>
+ <div class="hidden-phone btn-group pull-right">
+ <!-- future spot for other repo buttons -->
+ <a class="btn btn-info" wicket:id="myForkLink"><img style="border:0px;vertical-align:middle;" src="fork_16x16.png"></img> <wicket:message key="gb.myFork"></wicket:message></a>
+ <a class="btn btn-info" wicket:id="forkLink"><img style="border:0px;vertical-align:middle;" src="fork_16x16.png"></img> <wicket:message key="gb.fork"></wicket:message></a>
+ </div>
+ </div>
+ <div class="span7">
+ <div><span class="project" wicket:id="projectTitle">[project title]</span>/<img wicket:id="repositoryIcon" style="padding-left: 10px;"></img><span class="repository" wicket:id="repositoryName">[repository name]</span> <span class="hidden-phone"><span wicket:id="pageName">[page name]</span></span></div>
+ <span wicket:id="originRepository">[origin repository]</span>
+ </div>
+ </div>
+ </div>
+
+ <wicket:child />
+ </div>
+
+ <wicket:fragment wicket:id="originFragment">
+ <p class="originRepository"><wicket:message key="gb.forkedFrom">[forked from]</wicket:message> <span wicket:id="originRepository">[origin repository]</span></p>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="workingCopyFragment">
+ <div class="pull-right" style="padding-top:0px;margin-bottom:0px;padding-left:5px">
+ <span class="alert alert-info" style="padding: 6px 14px 6px 14px;vertical-align: middle;"><i class="icon-exclamation-sign"></i> <span class="hidden-phone" wicket:id="workingCopy" style="font-weight:bold;">[working copy]</span></span>
+ </div>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="forksProhibitedFragment">
+ <div class="pull-right" style="padding-top:0px;margin-bottom:0px;padding-left:5px">
+ <span class="alert alert-error" style="padding: 6px 14px 6px 14px;vertical-align: middle;"><i class="icon-ban-circle"></i> <span class="hidden-phone" wicket:id="forksProhibited" style="font-weight:bold;">[forks prohibited]</span></span>
+ </div>
+ </wicket:fragment>
+
+ </wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java new file mode 100644 index 00000000..a477b741 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java @@ -0,0 +1,608 @@ +/*
+ * Copyright 2011 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.Serializable;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.DropDownChoice;
+import org.apache.wicket.markup.html.form.TextField;
+import org.apache.wicket.markup.html.link.ExternalLink;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.protocol.http.RequestUtils;
+import org.apache.wicket.request.target.basic.RedirectRequestTarget;
+import org.eclipse.jgit.diff.DiffEntry.ChangeType;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import com.gitblit.Constants;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.PagesServlet;
+import com.gitblit.SyndicationServlet;
+import com.gitblit.models.ProjectModel;
+import com.gitblit.models.RefModel;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.SubmoduleModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.TicgitUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.PageRegistration;
+import com.gitblit.wicket.PageRegistration.OtherPageLink;
+import com.gitblit.wicket.SessionlessForm;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.LinkPanel;
+import com.gitblit.wicket.panels.NavigationPanel;
+import com.gitblit.wicket.panels.RefsPanel;
+
+public abstract class RepositoryPage extends BasePage {
+
+ protected final String projectName;
+ protected final String repositoryName;
+ protected final String objectId;
+
+ private transient Repository r;
+
+ private RepositoryModel m;
+
+ private Map<String, SubmoduleModel> submodules;
+
+ private final Map<String, PageRegistration> registeredPages;
+ private boolean showAdmin;
+ private boolean isOwner;
+
+ public RepositoryPage(PageParameters params) {
+ super(params);
+ repositoryName = WicketUtils.getRepositoryName(params);
+ String root =StringUtils.getFirstPathElement(repositoryName);
+ if (StringUtils.isEmpty(root)) {
+ projectName = GitBlit.getString(Keys.web.repositoryRootGroupName, "main");
+ } else {
+ projectName = root;
+ }
+ objectId = WicketUtils.getObject(params);
+
+ if (StringUtils.isEmpty(repositoryName)) {
+ error(MessageFormat.format(getString("gb.repositoryNotSpecifiedFor"), getPageName()), true);
+ }
+
+ if (!getRepositoryModel().hasCommits) {
+ setResponsePage(EmptyRepositoryPage.class, params);
+ }
+
+ if (getRepositoryModel().isCollectingGarbage) {
+ error(MessageFormat.format(getString("gb.busyCollectingGarbage"), getRepositoryModel().name), true);
+ }
+
+ if (objectId != null) {
+ RefModel branch = null;
+ if ((branch = JGitUtils.getBranch(getRepository(), objectId)) != null) {
+ UserModel user = GitBlitWebSession.get().getUser();
+ if (user == null) {
+ // workaround until get().getUser() is reviewed throughout the app
+ user = UserModel.ANONYMOUS;
+ }
+ boolean canAccess = user.canView(getRepositoryModel(),
+ branch.reference.getName());
+ if (!canAccess) {
+ error(getString("gb.accessDenied"), true);
+ }
+ }
+ }
+
+ // register the available page links for this page and user
+ registeredPages = registerPages();
+
+ // standard page links
+ List<PageRegistration> pages = new ArrayList<PageRegistration>(registeredPages.values());
+ NavigationPanel navigationPanel = new NavigationPanel("navPanel", getClass(), pages);
+ add(navigationPanel);
+
+ add(new ExternalLink("syndication", SyndicationServlet.asLink(getRequest()
+ .getRelativePathPrefixToContextRoot(), repositoryName, null, 0)));
+
+ // add floating search form
+ SearchForm searchForm = new SearchForm("searchForm", repositoryName);
+ add(searchForm);
+ searchForm.setTranslatedAttributes();
+
+ // set stateless page preference
+ setStatelessHint(true);
+ }
+
+ private Map<String, PageRegistration> registerPages() {
+ PageParameters params = null;
+ if (!StringUtils.isEmpty(repositoryName)) {
+ params = WicketUtils.newRepositoryParameter(repositoryName);
+ }
+ Map<String, PageRegistration> pages = new LinkedHashMap<String, PageRegistration>();
+
+ // standard links
+ pages.put("repositories", new PageRegistration("gb.repositories", RepositoriesPage.class));
+ pages.put("summary", new PageRegistration("gb.summary", SummaryPage.class, params));
+ pages.put("log", new PageRegistration("gb.log", LogPage.class, params));
+ pages.put("branches", new PageRegistration("gb.branches", BranchesPage.class, params));
+ pages.put("tags", new PageRegistration("gb.tags", TagsPage.class, params));
+ pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params));
+ if (GitBlit.getBoolean(Keys.web.allowForking, true)) {
+ pages.put("forks", new PageRegistration("gb.forks", ForksPage.class, params));
+ }
+
+ // conditional links
+ Repository r = getRepository();
+ RepositoryModel model = getRepositoryModel();
+
+ // per-repository extra page links
+ if (model.useTickets && TicgitUtils.getTicketsBranch(r) != null) {
+ pages.put("tickets", new PageRegistration("gb.tickets", TicketsPage.class, params));
+ }
+ if (model.useDocs) {
+ pages.put("docs", new PageRegistration("gb.docs", DocsPage.class, params));
+ }
+ if (JGitUtils.getPagesBranch(r) != null) {
+ OtherPageLink pagesLink = new OtherPageLink("gb.pages", PagesServlet.asLink(
+ getRequest().getRelativePathPrefixToContextRoot(), repositoryName, null));
+ pages.put("pages", pagesLink);
+ }
+
+ // Conditionally add edit link
+ showAdmin = false;
+ if (GitBlit.getBoolean(Keys.web.authenticateAdminPages, true)) {
+ boolean allowAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, false);
+ showAdmin = allowAdmin && GitBlitWebSession.get().canAdmin();
+ } else {
+ showAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, false);
+ }
+ isOwner = GitBlitWebSession.get().isLoggedIn()
+ && (model.isOwner(GitBlitWebSession.get()
+ .getUsername()));
+ if (showAdmin || isOwner) {
+ pages.put("edit", new PageRegistration("gb.edit", EditRepositoryPage.class, params));
+ }
+ return pages;
+ }
+
+ protected boolean allowForkControls() {
+ return GitBlit.getBoolean(Keys.web.allowForking, true);
+ }
+
+ @Override
+ protected void setupPage(String repositoryName, String pageName) {
+ String projectName = StringUtils.getFirstPathElement(repositoryName);
+ ProjectModel project = GitBlit.self().getProjectModel(projectName);
+ if (project.isUserProject()) {
+ // user-as-project
+ add(new LinkPanel("projectTitle", null, project.getDisplayName(),
+ UserPage.class, WicketUtils.newUsernameParameter(project.name.substring(1))));
+ } else {
+ // project
+ add(new LinkPanel("projectTitle", null, project.name,
+ ProjectPage.class, WicketUtils.newProjectParameter(project.name)));
+ }
+
+ String name = StringUtils.stripDotGit(repositoryName);
+ if (!StringUtils.isEmpty(projectName) && name.startsWith(projectName)) {
+ name = name.substring(projectName.length() + 1);
+ }
+ add(new LinkPanel("repositoryName", null, name, SummaryPage.class,
+ WicketUtils.newRepositoryParameter(repositoryName)));
+ add(new Label("pageName", pageName).setRenderBodyOnly(true));
+
+ UserModel user = GitBlitWebSession.get().getUser();
+ if (user == null) {
+ user = UserModel.ANONYMOUS;
+ }
+
+ // indicate origin repository
+ RepositoryModel model = getRepositoryModel();
+ if (StringUtils.isEmpty(model.originRepository)) {
+ add(new Label("originRepository").setVisible(false));
+ } else {
+ RepositoryModel origin = GitBlit.self().getRepositoryModel(model.originRepository);
+ if (origin == null) {
+ // no origin repository
+ add(new Label("originRepository").setVisible(false));
+ } else if (!user.canView(origin)) {
+ // show origin repository without link
+ Fragment forkFrag = new Fragment("originRepository", "originFragment", this);
+ forkFrag.add(new Label("originRepository", StringUtils.stripDotGit(model.originRepository)));
+ add(forkFrag);
+ } else {
+ // link to origin repository
+ Fragment forkFrag = new Fragment("originRepository", "originFragment", this);
+ forkFrag.add(new LinkPanel("originRepository", null, StringUtils.stripDotGit(model.originRepository),
+ SummaryPage.class, WicketUtils.newRepositoryParameter(model.originRepository)));
+ add(forkFrag);
+ }
+ }
+
+ // show sparkleshare folder icon
+ if (model.isSparkleshared()) {
+ add(WicketUtils.newImage("repositoryIcon", "folder_star_32x32.png",
+ getString("gb.isSparkleshared")));
+ } else {
+ add(WicketUtils.newClearPixel("repositoryIcon").setVisible(false));
+ }
+
+ if (getRepositoryModel().isBare) {
+ add(new Label("workingCopyIndicator").setVisible(false));
+ } else {
+ Fragment wc = new Fragment("workingCopyIndicator", "workingCopyFragment", this);
+ Label lbl = new Label("workingCopy", getString("gb.workingCopy"));
+ WicketUtils.setHtmlTooltip(lbl, getString("gb.workingCopyWarning"));
+ wc.add(lbl);
+ add(wc);
+ }
+
+ // fork controls
+ if (!allowForkControls() || user == null || !user.isAuthenticated) {
+ // must be logged-in to fork, hide all fork controls
+ add(new ExternalLink("forkLink", "").setVisible(false));
+ add(new ExternalLink("myForkLink", "").setVisible(false));
+ add(new Label("forksProhibitedIndicator").setVisible(false));
+ } else {
+ String fork = GitBlit.self().getFork(user.username, model.name);
+ boolean hasFork = fork != null;
+ boolean canFork = user.canFork(model);
+
+ if (hasFork || !canFork) {
+ // user not allowed to fork or fork already exists or repo forbids forking
+ add(new ExternalLink("forkLink", "").setVisible(false));
+
+ if (user.canFork() && !model.allowForks) {
+ // show forks prohibited indicator
+ Fragment wc = new Fragment("forksProhibitedIndicator", "forksProhibitedFragment", this);
+ Label lbl = new Label("forksProhibited", getString("gb.forksProhibited"));
+ WicketUtils.setHtmlTooltip(lbl, getString("gb.forksProhibitedWarning"));
+ wc.add(lbl);
+ add(wc);
+ } else {
+ // can not fork, no need for forks prohibited indicator
+ add(new Label("forksProhibitedIndicator").setVisible(false));
+ }
+
+ if (hasFork && !fork.equals(model.name)) {
+ // user has fork, view my fork link
+ String url = getRequestCycle().urlFor(SummaryPage.class, WicketUtils.newRepositoryParameter(fork)).toString();
+ add(new ExternalLink("myForkLink", url));
+ } else {
+ // no fork, hide view my fork link
+ add(new ExternalLink("myForkLink", "").setVisible(false));
+ }
+ } else if (canFork) {
+ // can fork and we do not have one
+ add(new Label("forksProhibitedIndicator").setVisible(false));
+ add(new ExternalLink("myForkLink", "").setVisible(false));
+ String url = getRequestCycle().urlFor(ForkPage.class, WicketUtils.newRepositoryParameter(model.name)).toString();
+ add(new ExternalLink("forkLink", url));
+ }
+ }
+
+ super.setupPage(repositoryName, pageName);
+ }
+
+ protected void addSyndicationDiscoveryLink() {
+ add(WicketUtils.syndicationDiscoveryLink(SyndicationServlet.getTitle(repositoryName,
+ objectId), SyndicationServlet.asLink(getRequest()
+ .getRelativePathPrefixToContextRoot(), repositoryName, objectId, 0)));
+ }
+
+ protected Repository getRepository() {
+ if (r == null) {
+ Repository r = GitBlit.self().getRepository(repositoryName);
+ if (r == null) {
+ error(getString("gb.canNotLoadRepository") + " " + repositoryName, true);
+ return null;
+ }
+ this.r = r;
+ }
+ return r;
+ }
+
+ protected RepositoryModel getRepositoryModel() {
+ if (m == null) {
+ RepositoryModel model = GitBlit.self().getRepositoryModel(
+ GitBlitWebSession.get().getUser(), repositoryName);
+ if (model == null) {
+ if (GitBlit.self().hasRepository(repositoryName, true)) {
+ // has repository, but unauthorized
+ authenticationError(getString("gb.unauthorizedAccessForRepository") + " " + repositoryName);
+ } else {
+ // does not have repository
+ error(getString("gb.canNotLoadRepository") + " " + repositoryName, true);
+ }
+ return null;
+ }
+ m = model;
+ }
+ return m;
+ }
+
+ protected RevCommit getCommit() {
+ RevCommit commit = JGitUtils.getCommit(r, objectId);
+ if (commit == null) {
+ error(MessageFormat.format(getString("gb.failedToFindCommit"),
+ objectId, repositoryName, getPageName()), true);
+ }
+ getSubmodules(commit);
+ return commit;
+ }
+
+ private Map<String, SubmoduleModel> getSubmodules(RevCommit commit) {
+ if (submodules == null) {
+ submodules = new HashMap<String, SubmoduleModel>();
+ for (SubmoduleModel model : JGitUtils.getSubmodules(r, commit.getTree())) {
+ submodules.put(model.path, model);
+ }
+ }
+ return submodules;
+ }
+
+ protected SubmoduleModel getSubmodule(String path) {
+ SubmoduleModel model = submodules.get(path);
+ if (model == null) {
+ // undefined submodule?!
+ model = new SubmoduleModel(path.substring(path.lastIndexOf('/') + 1), path, path);
+ model.hasSubmodule = false;
+ model.gitblitPath = model.name;
+ return model;
+ } else {
+ // extract the repository name from the clone url
+ List<String> patterns = GitBlit.getStrings(Keys.git.submoduleUrlPatterns);
+ String submoduleName = StringUtils.extractRepositoryPath(model.url, patterns.toArray(new String[0]));
+
+ // determine the current path for constructing paths relative
+ // to the current repository
+ String currentPath = "";
+ if (repositoryName.indexOf('/') > -1) {
+ currentPath = repositoryName.substring(0, repositoryName.lastIndexOf('/') + 1);
+ }
+
+ // try to locate the submodule repository
+ // prefer bare to non-bare names
+ List<String> candidates = new ArrayList<String>();
+
+ // relative
+ candidates.add(currentPath + StringUtils.stripDotGit(submoduleName));
+ candidates.add(candidates.get(candidates.size() - 1) + ".git");
+
+ // relative, no subfolder
+ if (submoduleName.lastIndexOf('/') > -1) {
+ String name = submoduleName.substring(submoduleName.lastIndexOf('/') + 1);
+ candidates.add(currentPath + StringUtils.stripDotGit(name));
+ candidates.add(currentPath + candidates.get(candidates.size() - 1) + ".git");
+ }
+
+ // absolute
+ candidates.add(StringUtils.stripDotGit(submoduleName));
+ candidates.add(candidates.get(candidates.size() - 1) + ".git");
+
+ // absolute, no subfolder
+ if (submoduleName.lastIndexOf('/') > -1) {
+ String name = submoduleName.substring(submoduleName.lastIndexOf('/') + 1);
+ candidates.add(StringUtils.stripDotGit(name));
+ candidates.add(candidates.get(candidates.size() - 1) + ".git");
+ }
+
+ // create a unique, ordered set of candidate paths
+ Set<String> paths = new LinkedHashSet<String>(candidates);
+ for (String candidate : paths) {
+ if (GitBlit.self().hasRepository(candidate)) {
+ model.hasSubmodule = true;
+ model.gitblitPath = candidate;
+ return model;
+ }
+ }
+
+ // we do not have a copy of the submodule, but we need a path
+ model.gitblitPath = candidates.get(0);
+ return model;
+ }
+ }
+
+ protected String getShortObjectId(String objectId) {
+ return objectId.substring(0, GitBlit.getInteger(Keys.web.shortCommitIdLength, 6));
+ }
+
+ protected void addRefs(Repository r, RevCommit c) {
+ add(new RefsPanel("refsPanel", repositoryName, c, JGitUtils.getAllRefs(r, getRepositoryModel().showRemoteBranches)));
+ }
+
+ protected void addFullText(String wicketId, String text, boolean substituteRegex) {
+ String html = StringUtils.escapeForHtml(text, true);
+ if (substituteRegex) {
+ html = GitBlit.self().processCommitMessage(repositoryName, text);
+ } else {
+ html = StringUtils.breakLinesForHtml(html);
+ }
+ add(new Label(wicketId, html).setEscapeModelStrings(false));
+ }
+
+ protected abstract String getPageName();
+
+ protected Component createPersonPanel(String wicketId, PersonIdent identity,
+ Constants.SearchType searchType) {
+ String name = identity == null ? "" : identity.getName();
+ String address = identity == null ? "" : identity.getEmailAddress();
+ name = StringUtils.removeNewlines(name);
+ address = StringUtils.removeNewlines(address);
+ boolean showEmail = GitBlit.getBoolean(Keys.web.showEmailAddresses, false);
+ if (!showEmail || StringUtils.isEmpty(name) || StringUtils.isEmpty(address)) {
+ String value = name;
+ if (StringUtils.isEmpty(value)) {
+ if (showEmail) {
+ value = address;
+ } else {
+ value = getString("gb.missingUsername");
+ }
+ }
+ Fragment partial = new Fragment(wicketId, "partialPersonIdent", this);
+ LinkPanel link = new LinkPanel("personName", "list", value, GitSearchPage.class,
+ WicketUtils.newSearchParameter(repositoryName, objectId, value, searchType));
+ setPersonSearchTooltip(link, value, searchType);
+ partial.add(link);
+ return partial;
+ } else {
+ Fragment fullPerson = new Fragment(wicketId, "fullPersonIdent", this);
+ LinkPanel nameLink = new LinkPanel("personName", "list", name, GitSearchPage.class,
+ WicketUtils.newSearchParameter(repositoryName, objectId, name, searchType));
+ setPersonSearchTooltip(nameLink, name, searchType);
+ fullPerson.add(nameLink);
+
+ LinkPanel addressLink = new LinkPanel("personAddress", "hidden-phone list", "<" + address + ">",
+ GitSearchPage.class, WicketUtils.newSearchParameter(repositoryName, objectId,
+ address, searchType));
+ setPersonSearchTooltip(addressLink, address, searchType);
+ fullPerson.add(addressLink);
+ return fullPerson;
+ }
+ }
+
+ protected void setPersonSearchTooltip(Component component, String value,
+ Constants.SearchType searchType) {
+ if (searchType.equals(Constants.SearchType.AUTHOR)) {
+ WicketUtils.setHtmlTooltip(component, getString("gb.searchForAuthor") + " " + value);
+ } else if (searchType.equals(Constants.SearchType.COMMITTER)) {
+ WicketUtils.setHtmlTooltip(component, getString("gb.searchForCommitter") + " " + value);
+ }
+ }
+
+ protected void setChangeTypeTooltip(Component container, ChangeType type) {
+ switch (type) {
+ case ADD:
+ WicketUtils.setHtmlTooltip(container, getString("gb.addition"));
+ break;
+ case COPY:
+ case RENAME:
+ WicketUtils.setHtmlTooltip(container, getString("gb.rename"));
+ break;
+ case DELETE:
+ WicketUtils.setHtmlTooltip(container, getString("gb.deletion"));
+ break;
+ case MODIFY:
+ WicketUtils.setHtmlTooltip(container, getString("gb.modification"));
+ break;
+ }
+ }
+
+ @Override
+ protected void onBeforeRender() {
+ // dispose of repository object
+ if (r != null) {
+ r.close();
+ r = null;
+ }
+ // setup page header and footer
+ setupPage(repositoryName, "/ " + getPageName());
+ super.onBeforeRender();
+ }
+
+ protected PageParameters newRepositoryParameter() {
+ return WicketUtils.newRepositoryParameter(repositoryName);
+ }
+
+ protected PageParameters newCommitParameter() {
+ return WicketUtils.newObjectParameter(repositoryName, objectId);
+ }
+
+ protected PageParameters newCommitParameter(String commitId) {
+ return WicketUtils.newObjectParameter(repositoryName, commitId);
+ }
+
+ public boolean isShowAdmin() {
+ return showAdmin;
+ }
+
+ public boolean isOwner() {
+ return isOwner;
+ }
+
+ private class SearchForm extends SessionlessForm<Void> implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final String repositoryName;
+
+ private final IModel<String> searchBoxModel = new Model<String>("");
+
+ private final IModel<Constants.SearchType> searchTypeModel = new Model<Constants.SearchType>(
+ Constants.SearchType.COMMIT);
+
+ public SearchForm(String id, String repositoryName) {
+ super(id, RepositoryPage.this.getClass(), RepositoryPage.this.getPageParameters());
+ this.repositoryName = repositoryName;
+ DropDownChoice<Constants.SearchType> searchType = new DropDownChoice<Constants.SearchType>(
+ "searchType", Arrays.asList(Constants.SearchType.values()));
+ searchType.setModel(searchTypeModel);
+ add(searchType.setVisible(GitBlit.getBoolean(Keys.web.showSearchTypeSelection, false)));
+ TextField<String> searchBox = new TextField<String>("searchBox", searchBoxModel);
+ add(searchBox);
+ }
+
+ void setTranslatedAttributes() {
+ WicketUtils.setHtmlTooltip(get("searchType"), getString("gb.searchTypeTooltip"));
+ WicketUtils.setHtmlTooltip(get("searchBox"),
+ MessageFormat.format(getString("gb.searchTooltip"), repositoryName));
+ WicketUtils.setInputPlaceholder(get("searchBox"), getString("gb.search"));
+ }
+
+ @Override
+ public void onSubmit() {
+ Constants.SearchType searchType = searchTypeModel.getObject();
+ String searchString = searchBoxModel.getObject();
+ if (searchString == null) {
+ return;
+ }
+ for (Constants.SearchType type : Constants.SearchType.values()) {
+ if (searchString.toLowerCase().startsWith(type.name().toLowerCase() + ":")) {
+ searchType = type;
+ searchString = searchString.substring(type.name().toLowerCase().length() + 1)
+ .trim();
+ break;
+ }
+ }
+ Class<? extends BasePage> searchPageClass = GitSearchPage.class;
+ RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName);
+ if (GitBlit.getBoolean(Keys.web.allowLuceneIndexing, true)
+ && !ArrayUtils.isEmpty(model.indexedBranches)) {
+ // this repository is Lucene-indexed
+ searchPageClass = LuceneSearchPage.class;
+ }
+ // use an absolute url to workaround Wicket-Tomcat problems with
+ // mounted url parameters (issue-111)
+ PageParameters params = WicketUtils.newSearchParameter(repositoryName, null, searchString, searchType);
+ String relativeUrl = urlFor(searchPageClass, params).toString();
+ String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);
+ getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/ReviewProposalPage.html b/src/main/java/com/gitblit/wicket/pages/ReviewProposalPage.html new file mode 100644 index 00000000..6487a0ac --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ReviewProposalPage.html @@ -0,0 +1,23 @@ +<!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:extend>
+ <!-- proposal info -->
+ <table class="plain">
+ <tr><th><wicket:message key="gb.received">received</wicket:message></th><td><span wicket:id="received">[received]</span></td></tr>
+ <tr><th><wicket:message key="gb.url">url</wicket:message></th><td><span wicket:id="url">[url]</span></td></tr>
+ <tr><th><wicket:message key="gb.message">message</wicket:message></th><td><span wicket:id="message">[message]</span></td></tr>
+ <tr><th><wicket:message key="gb.type">type</wicket:message></th><td><span wicket:id="tokenType">[token type]</span></td></tr>
+ <tr><th><wicket:message key="gb.token">token</wicket:message></th><td><span class="sha1" wicket:id="token">[token]</span></td></tr>
+ <tr><th valign="top"><wicket:message key="gb.proposal">proposal</wicket:message></th><td><span class="sha1" wicket:id="definition">[definition]</span></td></tr>
+ </table>
+
+ <div wicket:id="repositoriesPanel"></div>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/ReviewProposalPage.java b/src/main/java/com/gitblit/wicket/pages/ReviewProposalPage.java new file mode 100644 index 00000000..e1813861 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/ReviewProposalPage.java @@ -0,0 +1,102 @@ +/*
+ * Copyright 2011 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.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+
+import com.gitblit.Constants.FederationToken;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.FederationProposal;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.RequiresAdminRole;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.RepositoriesPanel;
+
+@RequiresAdminRole
+public class ReviewProposalPage extends RootSubPage {
+
+ private final String PROPS_PATTERN = "{0} = {1}\n";
+
+ private final String WEBXML_PATTERN = "\n<context-param>\n\t<param-name>{0}</param-name>\n\t<param-value>{1}</param-value>\n</context-param>\n";
+
+ public ReviewProposalPage(PageParameters params) {
+ super(params);
+
+ final String token = WicketUtils.getToken(params);
+
+ FederationProposal proposal = GitBlit.self().getPendingFederationProposal(token);
+ if (proposal == null) {
+ error(getString("gb.couldNotFindFederationProposal"), true);
+ }
+
+ setupPage(getString("gb.proposals"), proposal.url);
+
+
+ add(new Label("url", proposal.url));
+ add(new Label("message", proposal.message));
+ add(WicketUtils.createTimestampLabel("received", proposal.received, getTimeZone(), getTimeUtils()));
+ add(new Label("token", proposal.token));
+ add(new Label("tokenType", proposal.tokenType.name()));
+
+ String p;
+ if (GitBlit.isGO()) {
+ // gitblit.properties definition
+ p = PROPS_PATTERN;
+ } else {
+ // web.xml definition
+ p = WEBXML_PATTERN;
+ }
+
+ // build proposed definition
+ StringBuilder sb = new StringBuilder();
+ sb.append(asParam(p, proposal.name, "url", proposal.url));
+ sb.append(asParam(p, proposal.name, "token", proposal.token));
+
+ if (FederationToken.USERS_AND_REPOSITORIES.equals(proposal.tokenType)
+ || FederationToken.ALL.equals(proposal.tokenType)) {
+ sb.append(asParam(p, proposal.name, "mergeAccounts", "false"));
+ }
+ sb.append(asParam(p, proposal.name, "frequency",
+ GitBlit.getString(Keys.federation.defaultFrequency, "60 mins")));
+ sb.append(asParam(p, proposal.name, "folder", proposal.name));
+ sb.append(asParam(p, proposal.name, "bare", "true"));
+ sb.append(asParam(p, proposal.name, "mirror", "true"));
+ sb.append(asParam(p, proposal.name, "sendStatus", "true"));
+ sb.append(asParam(p, proposal.name, "notifyOnError", "true"));
+ sb.append(asParam(p, proposal.name, "exclude", ""));
+ sb.append(asParam(p, proposal.name, "include", ""));
+
+ add(new Label("definition", StringUtils.breakLinesForHtml(StringUtils.escapeForHtml(sb
+ .toString().trim(), true))).setEscapeModelStrings(false));
+
+ List<RepositoryModel> repositories = new ArrayList<RepositoryModel>(
+ proposal.repositories.values());
+ RepositoriesPanel repositoriesPanel = new RepositoriesPanel("repositoriesPanel", false,
+ false, repositories, false, getAccessRestrictions());
+ add(repositoriesPanel);
+ }
+
+ private String asParam(String pattern, String name, String key, String value) {
+ return MessageFormat.format(pattern, Keys.federation._ROOT + "." + name + "." + key, value);
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.html b/src/main/java/com/gitblit/wicket/pages/RootPage.html new file mode 100644 index 00000000..b35b1b3a --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.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">
+<body>
+<wicket:extend>
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </a>
+ <a class="brand" wicket:id="rootLink">
+ <img src="gitblt_25_white.png" width="79" height="25" alt="gitblit" class="logo"/>
+ </a>
+
+ <div class="nav-collapse" wicket:id="navPanel"></div>
+
+ <form class="pull-right" wicket:id="loginForm" style="padding-top:3px;">
+ <span class="form-search">
+ <input wicket:id="username" class="input-small" type="text" />
+ <input wicket:id="password" class="input-small" type="password" />
+ <button class="btn btn-primary" type="submit"><wicket:message key="gb.login"></wicket:message></button>
+ </span>
+ </form>
+ </div>
+ </div>
+ </div>
+
+ <!-- subclass content -->
+ <div class="container">
+ <div style="text-align:center" wicket:id="feedback">[Feedback Panel]</div>
+
+ <wicket:child/>
+ </div>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java new file mode 100644 index 00000000..adcd7b16 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -0,0 +1,454 @@ +/*
+ * Copyright 2011 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.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Pattern;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.form.PasswordTextField;
+import org.apache.wicket.markup.html.form.TextField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.protocol.http.WebResponse;
+
+import com.gitblit.Constants;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.TeamModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.PageRegistration;
+import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
+import com.gitblit.wicket.SessionlessForm;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.NavigationPanel;
+
+/**
+ * Root page is a topbar, navigable page like Repositories, Users, or
+ * Federation.
+ *
+ * @author James Moger
+ *
+ */
+public abstract class RootPage extends BasePage {
+
+ boolean showAdmin;
+
+ IModel<String> username = new Model<String>("");
+ IModel<String> password = new Model<String>("");
+ List<RepositoryModel> repositoryModels = new ArrayList<RepositoryModel>();
+
+ public RootPage() {
+ super();
+ }
+
+ public RootPage(PageParameters params) {
+ super(params);
+ }
+
+ @Override
+ protected void setupPage(String repositoryName, String pageName) {
+ boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, false);
+ boolean authenticateAdmin = GitBlit.getBoolean(Keys.web.authenticateAdminPages, true);
+ boolean allowAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, true);
+
+ if (authenticateAdmin) {
+ showAdmin = allowAdmin && GitBlitWebSession.get().canAdmin();
+ // authentication requires state and session
+ setStatelessHint(false);
+ } else {
+ showAdmin = allowAdmin;
+ if (authenticateView) {
+ // authentication requires state and session
+ setStatelessHint(false);
+ } else {
+ // no authentication required, no state and no session required
+ setStatelessHint(true);
+ }
+ }
+ boolean showRegistrations = GitBlit.canFederate()
+ && GitBlit.getBoolean(Keys.web.showFederationRegistrations, false);
+
+ // navigation links
+ List<PageRegistration> pages = new ArrayList<PageRegistration>();
+ pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class,
+ getRootPageParameters()));
+ pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters()));
+ if (GitBlit.getBoolean(Keys.web.allowLuceneIndexing, true)) {
+ pages.add(new PageRegistration("gb.search", LuceneSearchPage.class));
+ }
+ if (showAdmin) {
+ pages.add(new PageRegistration("gb.users", UsersPage.class));
+ }
+ if (showAdmin || showRegistrations) {
+ pages.add(new PageRegistration("gb.federation", FederationPage.class));
+ }
+
+ if (!authenticateView || (authenticateView && GitBlitWebSession.get().isLoggedIn())) {
+ addDropDownMenus(pages);
+ }
+
+ NavigationPanel navPanel = new NavigationPanel("navPanel", getClass(), pages);
+ add(navPanel);
+
+ // login form
+ SessionlessForm<Void> loginForm = new SessionlessForm<Void>("loginForm", getClass(), getPageParameters()) {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onSubmit() {
+ String username = RootPage.this.username.getObject();
+ char[] password = RootPage.this.password.getObject().toCharArray();
+
+ UserModel user = GitBlit.self().authenticate(username, password);
+ if (user == null) {
+ error(getString("gb.invalidUsernameOrPassword"));
+ } else if (user.username.equals(Constants.FEDERATION_USER)) {
+ // disallow the federation user from logging in via the
+ // web ui
+ error(getString("gb.invalidUsernameOrPassword"));
+ user = null;
+ } else {
+ loginUser(user);
+ }
+ }
+ };
+ TextField<String> unameField = new TextField<String>("username", username);
+ WicketUtils.setInputPlaceholder(unameField, getString("gb.username"));
+ loginForm.add(unameField);
+ PasswordTextField pwField = new PasswordTextField("password", password);
+ WicketUtils.setInputPlaceholder(pwField, getString("gb.password"));
+ loginForm.add(pwField);
+ add(loginForm);
+
+ if (authenticateView || authenticateAdmin) {
+ loginForm.setVisible(!GitBlitWebSession.get().isLoggedIn());
+ } else {
+ loginForm.setVisible(false);
+ }
+
+ // display an error message cached from a redirect
+ String cachedMessage = GitBlitWebSession.get().clearErrorMessage();
+ if (!StringUtils.isEmpty(cachedMessage)) {
+ error(cachedMessage);
+ } else if (showAdmin) {
+ int pendingProposals = GitBlit.self().getPendingFederationProposals().size();
+ if (pendingProposals == 1) {
+ info(getString("gb.OneProposalToReview"));
+ } else if (pendingProposals > 1) {
+ info(MessageFormat.format(getString("gb.nFederationProposalsToReview"),
+ pendingProposals));
+ }
+ }
+
+ super.setupPage(repositoryName, pageName);
+ }
+
+ private PageParameters getRootPageParameters() {
+ if (reusePageParameters()) {
+ PageParameters pp = getPageParameters();
+ if (pp != null) {
+ PageParameters params = new PageParameters(pp);
+ // remove named project parameter
+ params.remove("p");
+
+ // remove named repository parameter
+ params.remove("r");
+
+ // remove named user parameter
+ params.remove("user");
+
+ // remove days back parameter if it is the default value
+ if (params.containsKey("db")
+ && params.getInt("db") == GitBlit.getInteger(Keys.web.activityDuration, 14)) {
+ params.remove("db");
+ }
+ return params;
+ }
+ }
+ return null;
+ }
+
+ protected boolean reusePageParameters() {
+ return false;
+ }
+
+ private void loginUser(UserModel user) {
+ if (user != null) {
+ // Set the user into the session
+ GitBlitWebSession session = GitBlitWebSession.get();
+ // issue 62: fix session fixation vulnerability
+ session.replaceSession();
+ session.setUser(user);
+
+ // Set Cookie
+ if (GitBlit.getBoolean(Keys.web.allowCookieAuthentication, false)) {
+ WebResponse response = (WebResponse) getRequestCycle().getResponse();
+ GitBlit.self().setCookie(response, user);
+ }
+
+ if (!session.continueRequest()) {
+ PageParameters params = getPageParameters();
+ if (params == null) {
+ // redirect to this page
+ setResponsePage(getClass());
+ } else {
+ // Strip username and password and redirect to this page
+ params.remove("username");
+ params.remove("password");
+ setResponsePage(getClass(), params);
+ }
+ }
+ }
+ }
+
+ protected List<RepositoryModel> getRepositoryModels() {
+ if (repositoryModels.isEmpty()) {
+ final UserModel user = GitBlitWebSession.get().getUser();
+ List<RepositoryModel> repositories = GitBlit.self().getRepositoryModels(user);
+ repositoryModels.addAll(repositories);
+ Collections.sort(repositoryModels);
+ }
+ return repositoryModels;
+ }
+
+ protected void addDropDownMenus(List<PageRegistration> pages) {
+
+ }
+
+ protected List<DropDownMenuItem> getRepositoryFilterItems(PageParameters params) {
+ final UserModel user = GitBlitWebSession.get().getUser();
+ Set<DropDownMenuItem> filters = new LinkedHashSet<DropDownMenuItem>();
+ List<RepositoryModel> repositories = getRepositoryModels();
+
+ // accessible repositories by federation set
+ Map<String, AtomicInteger> setMap = new HashMap<String, AtomicInteger>();
+ for (RepositoryModel repository : repositories) {
+ for (String set : repository.federationSets) {
+ String key = set.toLowerCase();
+ if (setMap.containsKey(key)) {
+ setMap.get(key).incrementAndGet();
+ } else {
+ setMap.put(key, new AtomicInteger(1));
+ }
+ }
+ }
+ if (setMap.size() > 0) {
+ List<String> sets = new ArrayList<String>(setMap.keySet());
+ Collections.sort(sets);
+ for (String set : sets) {
+ filters.add(new DropDownMenuItem(MessageFormat.format("{0} ({1})", set,
+ setMap.get(set).get()), "set", set, params));
+ }
+ // divider
+ filters.add(new DropDownMenuItem());
+ }
+
+ // user's team memberships
+ if (user != null && user.teams.size() > 0) {
+ List<TeamModel> teams = new ArrayList<TeamModel>(user.teams);
+ Collections.sort(teams);
+ for (TeamModel team : teams) {
+ filters.add(new DropDownMenuItem(MessageFormat.format("{0} ({1})", team.name,
+ team.repositories.size()), "team", team.name, params));
+ }
+ // divider
+ filters.add(new DropDownMenuItem());
+ }
+
+ // custom filters
+ String customFilters = GitBlit.getString(Keys.web.customFilters, null);
+ if (!StringUtils.isEmpty(customFilters)) {
+ boolean addedExpression = false;
+ List<String> expressions = StringUtils.getStringsFromValue(customFilters, "!!!");
+ for (String expression : expressions) {
+ if (!StringUtils.isEmpty(expression)) {
+ addedExpression = true;
+ filters.add(new DropDownMenuItem(null, "x", expression, params));
+ }
+ }
+ // if we added any custom expressions, add a divider
+ if (addedExpression) {
+ filters.add(new DropDownMenuItem());
+ }
+ }
+ return new ArrayList<DropDownMenuItem>(filters);
+ }
+
+ protected List<DropDownMenuItem> getTimeFilterItems(PageParameters params) {
+ // days back choices - additive parameters
+ int daysBack = GitBlit.getInteger(Keys.web.activityDuration, 14);
+ if (daysBack < 1) {
+ daysBack = 14;
+ }
+ List<DropDownMenuItem> items = new ArrayList<DropDownMenuItem>();
+ Set<Integer> choicesSet = new HashSet<Integer>(Arrays.asList(daysBack, 14, 28, 60, 90, 180));
+ List<Integer> choices = new ArrayList<Integer>(choicesSet);
+ Collections.sort(choices);
+ String lastDaysPattern = getString("gb.lastNDays");
+ for (Integer db : choices) {
+ String txt = MessageFormat.format(lastDaysPattern, db);
+ items.add(new DropDownMenuItem(txt, "db", db.toString(), params));
+ }
+ items.add(new DropDownMenuItem());
+ return items;
+ }
+
+ protected List<RepositoryModel> getRepositories(PageParameters params) {
+ if (params == null) {
+ return getRepositoryModels();
+ }
+
+ boolean hasParameter = false;
+ String projectName = WicketUtils.getProjectName(params);
+ String userName = WicketUtils.getUsername(params);
+ if (StringUtils.isEmpty(projectName)) {
+ if (!StringUtils.isEmpty(userName)) {
+ projectName = "~" + userName;
+ }
+ }
+ String repositoryName = WicketUtils.getRepositoryName(params);
+ String set = WicketUtils.getSet(params);
+ String regex = WicketUtils.getRegEx(params);
+ String team = WicketUtils.getTeam(params);
+ int daysBack = params.getInt("db", 0);
+
+ List<RepositoryModel> availableModels = getRepositoryModels();
+ Set<RepositoryModel> models = new HashSet<RepositoryModel>();
+
+ if (!StringUtils.isEmpty(repositoryName)) {
+ // try named repository
+ hasParameter = true;
+ for (RepositoryModel model : availableModels) {
+ if (model.name.equalsIgnoreCase(repositoryName)) {
+ models.add(model);
+ break;
+ }
+ }
+ }
+
+ if (!StringUtils.isEmpty(projectName)) {
+ // try named project
+ hasParameter = true;
+ if (projectName.equalsIgnoreCase(GitBlit.getString(Keys.web.repositoryRootGroupName, "main"))) {
+ // root project/group
+ for (RepositoryModel model : availableModels) {
+ if (model.name.indexOf('/') == -1) {
+ models.add(model);
+ }
+ }
+ } else {
+ // named project/group
+ String group = projectName.toLowerCase() + "/";
+ for (RepositoryModel model : availableModels) {
+ if (model.name.toLowerCase().startsWith(group)) {
+ models.add(model);
+ }
+ }
+ }
+ }
+
+ if (!StringUtils.isEmpty(regex)) {
+ // filter the repositories by the regex
+ hasParameter = true;
+ Pattern pattern = Pattern.compile(regex);
+ for (RepositoryModel model : availableModels) {
+ if (pattern.matcher(model.name).find()) {
+ models.add(model);
+ }
+ }
+ }
+
+ if (!StringUtils.isEmpty(set)) {
+ // filter the repositories by the specified sets
+ hasParameter = true;
+ List<String> sets = StringUtils.getStringsFromValue(set, ",");
+ for (RepositoryModel model : availableModels) {
+ for (String curr : sets) {
+ if (model.federationSets.contains(curr)) {
+ models.add(model);
+ }
+ }
+ }
+ }
+
+ if (!StringUtils.isEmpty(team)) {
+ // filter the repositories by the specified teams
+ hasParameter = true;
+ List<String> teams = StringUtils.getStringsFromValue(team, ",");
+
+ // need TeamModels first
+ List<TeamModel> teamModels = new ArrayList<TeamModel>();
+ for (String name : teams) {
+ TeamModel teamModel = GitBlit.self().getTeamModel(name);
+ if (teamModel != null) {
+ teamModels.add(teamModel);
+ }
+ }
+
+ // brute-force our way through finding the matching models
+ for (RepositoryModel repositoryModel : availableModels) {
+ for (TeamModel teamModel : teamModels) {
+ if (teamModel.hasRepositoryPermission(repositoryModel.name)) {
+ models.add(repositoryModel);
+ }
+ }
+ }
+ }
+
+ if (!hasParameter) {
+ models.addAll(availableModels);
+ }
+
+ // time-filter the list
+ if (daysBack > 0) {
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.HOUR_OF_DAY, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ cal.add(Calendar.DATE, -1 * daysBack);
+ Date threshold = cal.getTime();
+ Set<RepositoryModel> timeFiltered = new HashSet<RepositoryModel>();
+ for (RepositoryModel model : models) {
+ if (model.lastChange.after(threshold)) {
+ timeFiltered.add(model);
+ }
+ }
+ models = timeFiltered;
+ }
+
+ List<RepositoryModel> list = new ArrayList<RepositoryModel>(models);
+ Collections.sort(list);
+ return list;
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/RootSubPage.html b/src/main/java/com/gitblit/wicket/pages/RootSubPage.html new file mode 100644 index 00000000..2b109f9b --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/RootSubPage.html @@ -0,0 +1,18 @@ +<!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:extend>
+ <!-- page header -->
+ <div class="pageTitle">
+ <h2><span wicket:id="pageName">[page name]</span> <small><span wicket:id="pageSubName">[sub name]</span></small></h2>
+ </div>
+
+ <!-- Subclass Content -->
+ <wicket:child/>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/RootSubPage.java b/src/main/java/com/gitblit/wicket/pages/RootSubPage.java new file mode 100644 index 00000000..e7e12ccc --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/RootSubPage.java @@ -0,0 +1,109 @@ +/*
+ * Copyright 2011 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.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.Session;
+import org.apache.wicket.markup.html.basic.Label;
+
+import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.Constants.AuthorizationControl;
+import com.gitblit.GitBlit;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.StringUtils;
+
+/**
+ * RootSubPage is a non-topbar navigable RootPage. It also has a page header.
+ *
+ * @author James Moger
+ *
+ */
+public abstract class RootSubPage extends RootPage {
+
+ public RootSubPage() {
+ super();
+ createPageMapIfNeeded();
+ }
+
+ public RootSubPage(PageParameters params) {
+ super(params);
+ createPageMapIfNeeded();
+ }
+
+ protected boolean requiresPageMap() {
+ return false;
+ }
+
+ protected void createPageMapIfNeeded() {
+ if (requiresPageMap()) {
+ // because Gitblit strives for page-statelessness
+ // Wicket seems to get confused as to when it really should
+ // generate a page map for complex pages. Conditionally ensure we
+ // have a page map for complex AJAX pages like the EditNNN pages.
+ Session.get().pageMapForName(null, true);
+ setVersioned(true);
+ }
+ }
+
+ @Override
+ protected void setupPage(String pageName, String subName) {
+ add(new Label("pageName", pageName));
+ if (!StringUtils.isEmpty(subName)) {
+ subName = "/ " + subName;
+ }
+ add(new Label("pageSubName", subName));
+ super.setupPage("", pageName);
+ }
+
+ protected List<String> getAccessRestrictedRepositoryList(boolean includeWildcards, UserModel user) {
+ // build list of access-restricted projects
+ String lastProject = null;
+ List<String> repos = new ArrayList<String>();
+ if (includeWildcards) {
+ // all repositories
+ repos.add(".*");
+ // all repositories excluding personal repositories
+ repos.add("[^~].*");
+ }
+
+ for (String repo : GitBlit.self().getRepositoryList()) {
+ RepositoryModel repositoryModel = GitBlit.self().getRepositoryModel(repo);
+ if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)
+ && repositoryModel.authorizationControl.equals(AuthorizationControl.NAMED)) {
+ if (user != null &&
+ (repositoryModel.isOwner(user.username) || repositoryModel.isUsersPersonalRepository(user.username))) {
+ // exclude Owner or personal repositories
+ continue;
+ }
+ if (includeWildcards) {
+ if (lastProject == null || !lastProject.equalsIgnoreCase(repositoryModel.projectPath)) {
+ lastProject = repositoryModel.projectPath.toLowerCase();
+ if (!StringUtils.isEmpty(repositoryModel.projectPath)) {
+ // regex for all repositories within a project
+ repos.add(repositoryModel.projectPath + "/.*");
+ }
+ }
+ }
+ repos.add(repo.toLowerCase());
+ }
+ }
+ return repos;
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/SendProposalPage.html b/src/main/java/com/gitblit/wicket/pages/SendProposalPage.html new file mode 100644 index 00000000..cb9f3539 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/SendProposalPage.html @@ -0,0 +1,24 @@ +<!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('myUrl').focus();">
+ <!-- proposal info -->
+ <form wicket:id="editForm">
+ <table class="plain">
+ <tr><th><wicket:message key="gb.url">url</wicket:message></th><td class="edit"><input class="span6" type="text" wicket:id="myUrl" id="myUrl" size="60" /> <i><wicket:message key="gb.myUrlDescription"></wicket:message></i></td></tr>
+ <tr><th><wicket:message key="gb.destinationUrl">destination url</wicket:message></th><td class="edit"><input class="span6" type="text" wicket:id="destinationUrl" size="60" /> <i><wicket:message key="gb.destinationUrlDescription"></wicket:message></i></td></tr>
+ <tr><th valign="top"><wicket:message key="gb.message">message</wicket:message></th><td class="edit"><input class="span8" type="text" wicket:id="message" size="80" /></td></tr>
+ <tr><th><wicket:message key="gb.type">type</wicket:message></th><td><span wicket:id="tokenType">[token type]</span></td></tr>
+ <tr><th><wicket:message key="gb.token">token</wicket:message></th><td><span class="sha1" wicket:id="token">[token]</span></td></tr>
+ <tr><th></th><td class="editButton"><input class="btn btn-primary" type="submit" value="propose" wicket:message="value:gb.sendProposal" wicket:id="save" /> <input class="btn" type="submit" value="Cancel" wicket:message="value:gb.cancel" wicket:id="cancel" /></td></tr>
+ </table>
+ </form>
+
+ <div style="padding-top:10px;" wicket:id="repositoriesPanel"></div>
+</body>
+</wicket:extend>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/SendProposalPage.java b/src/main/java/com/gitblit/wicket/pages/SendProposalPage.java new file mode 100644 index 00000000..fc5f95b5 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/SendProposalPage.java @@ -0,0 +1,152 @@ +/*
+ * Copyright 2011 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.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Button;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.TextField;
+import org.apache.wicket.model.CompoundPropertyModel;
+
+import com.gitblit.Constants.FederationProposalResult;
+import com.gitblit.GitBlit;
+import com.gitblit.models.FederationProposal;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.utils.FederationUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.RequiresAdminRole;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.RepositoriesPanel;
+
+@RequiresAdminRole
+public class SendProposalPage extends RootSubPage {
+
+ public String myUrl;
+
+ public String destinationUrl;
+
+ public String message;
+
+ public SendProposalPage(PageParameters params) {
+ super(params);
+
+ setupPage(getString("gb.sendProposal"), "");
+ setStatelessHint(true);
+
+ final String token = WicketUtils.getToken(params);
+
+ myUrl = WicketUtils.getGitblitURL(getRequest());
+ destinationUrl = "https://";
+
+ // temporary proposal
+ FederationProposal proposal = GitBlit.self().createFederationProposal(myUrl, token);
+ if (proposal == null) {
+ error(getString("gb.couldNotCreateFederationProposal"), true);
+ }
+
+ CompoundPropertyModel<SendProposalPage> model = new CompoundPropertyModel<SendProposalPage>(
+ this);
+
+ Form<SendProposalPage> form = new Form<SendProposalPage>("editForm", model) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void onSubmit() {
+ // confirm a repository name was entered
+ if (StringUtils.isEmpty(myUrl)) {
+ error(getString("gb.pleaseSetGitblitUrl"));
+ return;
+ }
+ if (StringUtils.isEmpty(destinationUrl)) {
+ error(getString("gb.pleaseSetDestinationUrl"));
+ return;
+ }
+
+ // build new proposal
+ FederationProposal proposal = GitBlit.self().createFederationProposal(myUrl, token);
+ proposal.url = myUrl;
+ proposal.message = message;
+ try {
+ FederationProposalResult res = FederationUtils
+ .propose(destinationUrl, proposal);
+ switch (res) {
+ case ACCEPTED:
+ info(MessageFormat.format(getString("gb.proposalReceived"),
+ destinationUrl));
+ setResponsePage(RepositoriesPage.class);
+ break;
+ case NO_POKE:
+ error(MessageFormat.format(getString("noGitblitFound"),
+ destinationUrl, myUrl));
+ break;
+ case NO_PROPOSALS:
+ error(MessageFormat.format(getString("gb.noProposals"),
+ destinationUrl));
+ break;
+ case FEDERATION_DISABLED:
+ error(MessageFormat
+ .format(getString("gb.noFederation"),
+ destinationUrl));
+ break;
+ case MISSING_DATA:
+ error(MessageFormat.format(getString("gb.proposalFailed"),
+ destinationUrl));
+ break;
+ case ERROR:
+ error(MessageFormat.format(getString("gb.proposalError"),
+ destinationUrl));
+ break;
+ }
+ } catch (Exception e) {
+ if (!StringUtils.isEmpty(e.getMessage())) {
+ error(e.getMessage());
+ } else {
+ error(getString("gb.failedToSendProposal"));
+ }
+ }
+ }
+ };
+ form.add(new TextField<String>("myUrl"));
+ form.add(new TextField<String>("destinationUrl"));
+ form.add(new TextField<String>("message"));
+ form.add(new Label("tokenType", proposal.tokenType.name()));
+ form.add(new Label("token", proposal.token));
+
+ form.add(new Button("save"));
+ Button cancel = new Button("cancel") {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onSubmit() {
+ setResponsePage(FederationPage.class);
+ }
+ };
+ cancel.setDefaultFormProcessing(false);
+ form.add(cancel);
+ add(form);
+
+ List<RepositoryModel> repositories = new ArrayList<RepositoryModel>(
+ proposal.repositories.values());
+ RepositoriesPanel repositoriesPanel = new RepositoriesPanel("repositoriesPanel", false,
+ false, repositories, false, getAccessRestrictions());
+ add(repositoriesPanel);
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/SummaryPage.html b/src/main/java/com/gitblit/wicket/pages/SummaryPage.html new file mode 100644 index 00000000..3e85df99 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/SummaryPage.html @@ -0,0 +1,54 @@ +<!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:extend>
+
+ <div style="clear:both;">
+ <!-- Repository Activity Chart -->
+ <div class="hidden-phone" style="float:right;">
+ <img class="activityGraph" wicket:id="commitsChart" />
+ </div>
+
+ <!-- Repository info -->
+ <div class="hidden-phone" style="padding-bottom: 10px;">
+ <table class="plain">
+ <tr><th><wicket:message key="gb.description">[description]</wicket:message></th><td><span wicket:id="repositoryDescription">[repository description]</span></td></tr>
+ <tr><th><wicket:message key="gb.owners">[owner]</wicket:message></th><td><span wicket:id="repositoryOwners"><span wicket:id="owner"></span><span wicket:id="comma"></span></span></td></tr>
+ <tr><th><wicket:message key="gb.lastChange">[last change]</wicket:message></th><td><span wicket:id="repositoryLastChange">[repository last change]</span></td></tr>
+ <tr><th><wicket:message key="gb.stats">[stats]</wicket:message></th><td><span wicket:id="branchStats">[branch stats]</span> <span class="link"><a wicket:id="metrics"><wicket:message key="gb.metrics">[metrics]</wicket:message></a></span></td></tr>
+ <tr><th style="vertical-align:top;"><wicket:message key="gb.repositoryUrl">[URL]</wicket:message> <img style="vertical-align: top;padding-left:3px;" wicket:id="accessRestrictionIcon" /></th><td><span wicket:id="repositoryCloneUrl">[repository clone url]</span><div wicket:id="otherUrls"></div></td></tr>
+ </table>
+ </div>
+ </div>
+
+ <!-- commits -->
+ <div style="padding-bottom:15px;" wicket:id="commitsPanel">[commits panel]</div>
+
+ <!-- tags -->
+ <div style="padding-bottom:15px;" wicket:id="tagsPanel">[tags panel]</div>
+
+ <!-- branches -->
+ <div style="padding-bottom:15px;" wicket:id="branchesPanel">[branches panel]</div>
+
+ <!-- markdown readme -->
+ <div wicket:id="readme"></div>
+
+ <wicket:fragment wicket:id="markdownPanel">
+ <div class="header" style="margin-top:0px;" >
+ <i style="vertical-align: middle;" class="icon-book"></i>
+ <span style="font-weight:bold;vertical-align:middle;" wicket:id="readmeFile"></span>
+ </div>
+ <div style="border:1px solid #ddd;border-radius: 0 0 3px 3px;padding: 20px;">
+ <div wicket:id="readmeContent" class="markdown"></div>
+ </div>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="ownersFragment">
+
+ </wicket:fragment>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/SummaryPage.java b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java new file mode 100644 index 00000000..bd40a1b7 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/SummaryPage.java @@ -0,0 +1,238 @@ +/*
+ * Copyright 2011 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.awt.Color;
+import java.awt.Dimension;
+import java.text.MessageFormat;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.wicketstuff.googlecharts.Chart;
+import org.wicketstuff.googlecharts.ChartAxis;
+import org.wicketstuff.googlecharts.ChartAxisType;
+import org.wicketstuff.googlecharts.ChartProvider;
+import org.wicketstuff.googlecharts.ChartType;
+import org.wicketstuff.googlecharts.IChartData;
+import org.wicketstuff.googlecharts.LineStyle;
+import org.wicketstuff.googlecharts.MarkerType;
+import org.wicketstuff.googlecharts.ShapeMarker;
+
+import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.Metric;
+import com.gitblit.models.PathModel;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.MarkdownUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.BranchesPanel;
+import com.gitblit.wicket.panels.LinkPanel;
+import com.gitblit.wicket.panels.LogPanel;
+import com.gitblit.wicket.panels.RepositoryUrlPanel;
+import com.gitblit.wicket.panels.TagsPanel;
+
+public class SummaryPage extends RepositoryPage {
+
+ public SummaryPage(PageParameters params) {
+ super(params);
+
+ int numberCommits = GitBlit.getInteger(Keys.web.summaryCommitCount, 20);
+ if (numberCommits <= 0) {
+ numberCommits = 20;
+ }
+ int numberRefs = GitBlit.getInteger(Keys.web.summaryRefsCount, 5);
+
+ Repository r = getRepository();
+ RepositoryModel model = getRepositoryModel();
+
+ List<Metric> metrics = null;
+ Metric metricsTotal = null;
+ if (!model.skipSummaryMetrics && GitBlit.getBoolean(Keys.web.generateActivityGraph, true)) {
+ metrics = GitBlit.self().getRepositoryDefaultMetrics(model, r);
+ metricsTotal = metrics.remove(0);
+ }
+
+ addSyndicationDiscoveryLink();
+
+ // repository description
+ add(new Label("repositoryDescription", getRepositoryModel().description));
+
+ // owner links
+ final List<String> owners = new ArrayList<String>(getRepositoryModel().owners);
+ ListDataProvider<String> ownersDp = new ListDataProvider<String>(owners);
+ DataView<String> ownersView = new DataView<String>("repositoryOwners", ownersDp) {
+ private static final long serialVersionUID = 1L;
+ int counter = 0;
+ public void populateItem(final Item<String> item) {
+ UserModel ownerModel = GitBlit.self().getUserModel(item.getModelObject());
+ if (ownerModel != null) {
+ item.add(new LinkPanel("owner", null, ownerModel.getDisplayName(), UserPage.class,
+ WicketUtils.newUsernameParameter(ownerModel.username)).setRenderBodyOnly(true));
+ } else {
+ item.add(new Label("owner").setVisible(false));
+ }
+ counter++;
+ item.add(new Label("comma", ",").setVisible(counter < owners.size()));
+ item.setRenderBodyOnly(true);
+ }
+ };
+ ownersView.setRenderBodyOnly(true);
+ add(ownersView);
+
+ add(WicketUtils.createTimestampLabel("repositoryLastChange",
+ JGitUtils.getLastChange(r), getTimeZone(), getTimeUtils()));
+ if (metricsTotal == null) {
+ add(new Label("branchStats", ""));
+ } else {
+ add(new Label("branchStats",
+ MessageFormat.format(getString("gb.branchStats"), metricsTotal.count,
+ metricsTotal.tag, getTimeUtils().duration(metricsTotal.duration))));
+ }
+ add(new BookmarkablePageLink<Void>("metrics", MetricsPage.class,
+ WicketUtils.newRepositoryParameter(repositoryName)));
+
+ List<String> repositoryUrls = new ArrayList<String>();
+
+ if (GitBlit.getBoolean(Keys.git.enableGitServlet, true)) {
+ AccessRestrictionType accessRestriction = getRepositoryModel().accessRestriction;
+ switch (accessRestriction) {
+ case NONE:
+ add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
+ break;
+ case PUSH:
+ add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png",
+ getAccessRestrictions().get(accessRestriction)));
+ break;
+ case CLONE:
+ add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png",
+ getAccessRestrictions().get(accessRestriction)));
+ break;
+ case VIEW:
+ add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png",
+ getAccessRestrictions().get(accessRestriction)));
+ break;
+ default:
+ add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
+ }
+ // add the Gitblit repository url
+ repositoryUrls.add(getRepositoryUrl(getRepositoryModel()));
+ } else {
+ add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
+ }
+ repositoryUrls.addAll(GitBlit.self().getOtherCloneUrls(repositoryName));
+
+ String primaryUrl = ArrayUtils.isEmpty(repositoryUrls) ? "" : repositoryUrls.remove(0);
+ add(new RepositoryUrlPanel("repositoryCloneUrl", primaryUrl));
+
+ add(new Label("otherUrls", StringUtils.flattenStrings(repositoryUrls, "<br/>"))
+ .setEscapeModelStrings(false));
+
+ add(new LogPanel("commitsPanel", repositoryName, getRepositoryModel().HEAD, r, numberCommits, 0, getRepositoryModel().showRemoteBranches));
+ add(new TagsPanel("tagsPanel", repositoryName, r, numberRefs).hideIfEmpty());
+ add(new BranchesPanel("branchesPanel", getRepositoryModel(), r, numberRefs, false).hideIfEmpty());
+
+ if (getRepositoryModel().showReadme) {
+ String htmlText = null;
+ String markdownText = null;
+ String readme = null;
+ try {
+ RevCommit head = JGitUtils.getCommit(r, null);
+ List<String> markdownExtensions = GitBlit.getStrings(Keys.web.markdownExtensions);
+ List<PathModel> paths = JGitUtils.getFilesInPath(r, null, head);
+ for (PathModel path : paths) {
+ if (!path.isTree()) {
+ String name = path.name.toLowerCase();
+
+ if (name.startsWith("readme")) {
+ if (name.indexOf('.') > -1) {
+ String ext = name.substring(name.lastIndexOf('.') + 1);
+ if (markdownExtensions.contains(ext)) {
+ readme = path.name;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (!StringUtils.isEmpty(readme)) {
+ String [] encodings = GitBlit.getEncodings();
+ markdownText = JGitUtils.getStringContent(r, head.getTree(), readme, encodings);
+ htmlText = MarkdownUtils.transformMarkdown(markdownText);
+ }
+ } catch (ParseException p) {
+ markdownText = MessageFormat.format("<div class=\"alert alert-error\"><strong>{0}:</strong> {1}</div>{2}", getString("gb.error"), getString("gb.markdownFailure"), markdownText);
+ htmlText = StringUtils.breakLinesForHtml(markdownText);
+ }
+ Fragment fragment = new Fragment("readme", "markdownPanel");
+ fragment.add(new Label("readmeFile", readme));
+ // Add the html to the page
+ Component content = new Label("readmeContent", htmlText).setEscapeModelStrings(false);
+ fragment.add(content.setVisible(!StringUtils.isEmpty(htmlText)));
+ add(fragment);
+ } else {
+ add(new Label("readme").setVisible(false));
+ }
+
+ // Display an activity line graph
+ insertActivityGraph(metrics);
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.summary");
+ }
+
+ private void insertActivityGraph(List<Metric> metrics) {
+ if ((metrics != null) && (metrics.size() > 0)
+ && GitBlit.getBoolean(Keys.web.generateActivityGraph, true)) {
+ IChartData data = WicketUtils.getChartData(metrics);
+
+ ChartProvider provider = new ChartProvider(new Dimension(290, 100), ChartType.LINE,
+ data);
+ ChartAxis dateAxis = new ChartAxis(ChartAxisType.BOTTOM);
+ dateAxis.setLabels(new String[] { metrics.get(0).name,
+ metrics.get(metrics.size() / 2).name, metrics.get(metrics.size() - 1).name });
+ provider.addAxis(dateAxis);
+
+ ChartAxis commitAxis = new ChartAxis(ChartAxisType.LEFT);
+ commitAxis.setLabels(new String[] { "",
+ String.valueOf((int) WicketUtils.maxValue(metrics)) });
+ provider.addAxis(commitAxis);
+ provider.setLineStyles(new LineStyle[] { new LineStyle(2, 4, 0), new LineStyle(0, 4, 1) });
+ provider.addShapeMarker(new ShapeMarker(MarkerType.CIRCLE, Color.BLUE, 1, -1, 5));
+
+ add(new Chart("commitsChart", provider));
+ } else {
+ add(WicketUtils.newBlankImage("commitsChart"));
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/TagPage.html b/src/main/java/com/gitblit/wicket/pages/TagPage.html new file mode 100644 index 00000000..19f828e3 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/TagPage.html @@ -0,0 +1,38 @@ +<!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:extend>
+
+ <!-- summary header -->
+ <div style="margin-top: 5px;" class="header" wicket:id="commit">[shortlog header]</div>
+
+ <!-- Tagger Gravatar -->
+ <span style="float:right;vertical-align: top;" wicket:id="taggerAvatar" />
+
+ <!-- commit info -->
+ <table class="plain">
+ <tr><th><wicket:message key="gb.name">[name]</wicket:message></th><td><span wicket:id="tagName">[tag name]</span></td></tr>
+ <tr><th><wicket:message key="gb.tag">[tag]</wicket:message></th><td><span class="sha1" wicket:id="tagId">[tag id]</span></td></tr>
+ <tr><th><wicket:message key="gb.object">[object]</wicket:message></th><td><span class="sha1" wicket:id="taggedObject">[tagged object]</span> <span class="link" wicket:id="taggedObjectType"></span></td></tr>
+ <tr><th><wicket:message key="gb.tagger">[tagger]</wicket:message></th><td><span class="sha1" wicket:id="tagger">[tagger]</span></td></tr>
+ <tr><th></th><td><span class="sha1" wicket:id="tagDate">[tag date]</span></td></tr>
+ </table>
+
+ <!-- full message -->
+ <div style="border-bottom:0px;" class="commit_message" wicket:id="fullMessage">[tag full message]</div>
+
+ <wicket:fragment wicket:id="fullPersonIdent">
+ <span wicket:id="personName"></span><span wicket:id="personAddress"></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="partialPersonIdent">
+ <span wicket:id="personName"></span>
+ </wicket:fragment>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/TagPage.java b/src/main/java/com/gitblit/wicket/pages/TagPage.java new file mode 100644 index 00000000..91c913d2 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/TagPage.java @@ -0,0 +1,99 @@ +/*
+ * Copyright 2011 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.text.MessageFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+
+import com.gitblit.models.RefModel;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.GravatarImage;
+import com.gitblit.wicket.panels.LinkPanel;
+import com.gitblit.wicket.panels.RefsPanel;
+
+public class TagPage extends RepositoryPage {
+
+ public TagPage(PageParameters params) {
+ super(params);
+
+ Repository r = getRepository();
+
+ // Find tag in repository
+ List<RefModel> tags = JGitUtils.getTags(r, true, -1);
+ RefModel tagRef = null;
+ for (RefModel tag : tags) {
+ if (tag.getName().equals(objectId) || tag.getObjectId().getName().equals(objectId)) {
+ tagRef = tag;
+ break;
+ }
+ }
+
+ // Failed to find tag!
+ if (tagRef == null) {
+ error(MessageFormat.format(getString("gb.couldNotFindTag"), objectId), true);
+ }
+
+ // Display tag.
+ Class<? extends RepositoryPage> linkClass;
+ PageParameters linkParameters = newCommitParameter(tagRef.getReferencedObjectId().getName());
+ String typeKey;
+ switch (tagRef.getReferencedObjectType()) {
+ case Constants.OBJ_BLOB:
+ typeKey = "gb.blob";
+ linkClass = BlobPage.class;
+ break;
+ case Constants.OBJ_TREE:
+ typeKey = "gb.tree";
+ linkClass = TreePage.class;
+ break;
+ case Constants.OBJ_COMMIT:
+ default:
+ typeKey = "gb.commit";
+ linkClass = CommitPage.class;
+ break;
+ }
+ add(new LinkPanel("commit", "title", tagRef.displayName, linkClass, linkParameters));
+ add(new GravatarImage("taggerAvatar", tagRef.getAuthorIdent()));
+
+ add(new RefsPanel("tagName", repositoryName, Arrays.asList(tagRef)));
+ add(new Label("tagId", tagRef.getObjectId().getName()));
+ add(new LinkPanel("taggedObject", "list", tagRef.getReferencedObjectId().getName(),
+ linkClass, linkParameters));
+ add(new Label("taggedObjectType", getString(typeKey)));
+
+ add(createPersonPanel("tagger", tagRef.getAuthorIdent(), com.gitblit.Constants.SearchType.AUTHOR));
+ Date when = new Date(0);
+ if (tagRef.getAuthorIdent() != null) {
+ when = tagRef.getAuthorIdent().getWhen();
+ }
+ add(WicketUtils.createTimestampLabel("tagDate", when, getTimeZone(), getTimeUtils()));
+
+ addFullText("fullMessage", tagRef.getFullMessage(), true);
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.tag");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/TagsPage.html b/src/main/java/com/gitblit/wicket/pages/TagsPage.html new file mode 100644 index 00000000..03f1a0d7 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/TagsPage.html @@ -0,0 +1,15 @@ +<!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:extend>
+
+ <!-- tags panel -->
+ <div style="margin-top:5px;" wicket:id="tagsPanel">[tags panel]</div>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/TagsPage.java b/src/main/java/com/gitblit/wicket/pages/TagsPage.java new file mode 100644 index 00000000..3ddbde9b --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/TagsPage.java @@ -0,0 +1,35 @@ +/*
+ * Copyright 2011 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 org.apache.wicket.PageParameters;
+
+import com.gitblit.wicket.panels.TagsPanel;
+
+public class TagsPage extends RepositoryPage {
+
+ public TagsPage(PageParameters params) {
+ super(params);
+
+ add(new TagsPanel("tagsPanel", repositoryName, getRepository(), -1));
+
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.tags");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/TicketPage.html b/src/main/java/com/gitblit/wicket/pages/TicketPage.html new file mode 100644 index 00000000..ed3eb229 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/TicketPage.html @@ -0,0 +1,39 @@ +<!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:extend>
+
+ <!-- ticket title -->
+ <div style="font-size:150%;padding-top:5px;padding-bottom:5px;" wicket:id="ticketTitle">[ticket title]</div>
+
+ <!-- ticket info -->
+ <table class="plain">
+ <tr><th><wicket:message key="gb.ticketId">ticket id</wicket:message></th><td><span class="sha1" wicket:id="ticketId">[ticket id]</span></td></tr>
+ <tr><th><wicket:message key="gb.ticketAssigned">assigned</wicket:message></th><td><span wicket:id=ticketHandler>[ticket title]</span></td></tr>
+ <tr><th><wicket:message key="gb.ticketOpenDate">open date</wicket:message></th><td><span wicket:id="ticketOpenDate">[ticket open date]</span></td></tr>
+ <tr><th><wicket:message key="gb.ticketState">state</wicket:message></th><td><span wicket:id="ticketState">[ticket state]</span></td></tr>
+ <tr><th><wicket:message key="gb.tags">tags</wicket:message></th><td><span wicket:id="ticketTags">[ticket tags]</span></td></tr>
+ </table>
+
+ <!-- comments header -->
+ <div class="header"><wicket:message key="gb.ticketComments">comments</wicket:message></div>
+
+ <!-- comments -->
+ <table class="comments">
+ <tbody>
+ <tr valign="top" wicket:id="comment">
+ <td><span class="author" wicket:id="commentAuthor">[comment author]</span><br/>
+ <span class="date" wicket:id="commentDate">[comment date]</span>
+ </td>
+ <td><span wicket:id="commentText">[comment text]</span></td>
+ </tr>
+ </tbody>
+ </table>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/TicketPage.java b/src/main/java/com/gitblit/wicket/pages/TicketPage.java new file mode 100644 index 00000000..57233867 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/TicketPage.java @@ -0,0 +1,81 @@ +/*
+ * Copyright 2011 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 org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.eclipse.jgit.lib.Repository;
+
+import com.gitblit.models.TicketModel;
+import com.gitblit.models.TicketModel.Comment;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.TicgitUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.WicketUtils;
+
+public class TicketPage extends RepositoryPage {
+
+ public TicketPage(PageParameters params) {
+ super(params);
+
+ final String ticketFolder = WicketUtils.getPath(params);
+
+ Repository r = getRepository();
+ TicketModel t = TicgitUtils.getTicket(r, ticketFolder);
+
+ add(new Label("ticketTitle", t.title));
+ add(new Label("ticketId", t.id));
+ add(new Label("ticketHandler", t.handler.toLowerCase()));
+ add(WicketUtils.createTimestampLabel("ticketOpenDate", t.date, getTimeZone(), getTimeUtils()));
+ Label stateLabel = new Label("ticketState", t.state);
+ WicketUtils.setTicketCssClass(stateLabel, t.state);
+ add(stateLabel);
+ add(new Label("ticketTags", StringUtils.flattenStrings(t.tags)));
+
+ ListDataProvider<Comment> commentsDp = new ListDataProvider<Comment>(t.comments);
+ DataView<Comment> commentsView = new DataView<Comment>("comment", commentsDp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+
+ public void populateItem(final Item<Comment> item) {
+ final Comment entry = item.getModelObject();
+ item.add(WicketUtils.createDateLabel("commentDate", entry.date, GitBlitWebSession
+ .get().getTimezone(), getTimeUtils()));
+ item.add(new Label("commentAuthor", entry.author.toLowerCase()));
+ item.add(new Label("commentText", prepareComment(entry.text))
+ .setEscapeModelStrings(false));
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(commentsView);
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.ticket");
+ }
+
+ private String prepareComment(String comment) {
+ String html = StringUtils.escapeForHtml(comment, false);
+ html = StringUtils.breakLinesForHtml(comment).trim();
+ return html.replaceAll("\\bcommit\\s*([A-Za-z0-9]*)\\b", "<a href=\"/commit/"
+ + repositoryName + "/$1\">commit $1</a>");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.html b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html new file mode 100644 index 00000000..0913dc2c --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html @@ -0,0 +1,27 @@ +<!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:extend>
+
+ <!-- header -->
+ <div style="margin-top:5px;" class="header" wicket:id="header">[header]</div>
+
+ <!-- tickets -->
+ <table class="pretty">
+ <tbody>
+ <tr wicket:id="ticket">
+ <td style="padding:0; margin:0;"><div wicket:id="ticketState">[ticket state]</div></td>
+ <td class="date"><span wicket:id="ticketDate">[ticket date]</span></td>
+ <td class="author"><div wicket:id="ticketHandler">[ticket handler]</div></td>
+ <td><div wicket:id="ticketTitle">[ticket title]</div></td>
+ </tr>
+ </tbody>
+ </table>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java new file mode 100644 index 00000000..b68b7e42 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java @@ -0,0 +1,76 @@ +/*
+ * Copyright 2011 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.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.models.TicketModel;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.TicgitUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.LinkPanel;
+
+public class TicketsPage extends RepositoryPage {
+
+ public TicketsPage(PageParameters params) {
+ super(params);
+
+ List<TicketModel> tickets = TicgitUtils.getTickets(getRepository());
+
+ // header
+ add(new LinkPanel("header", "title", repositoryName, SummaryPage.class,
+ newRepositoryParameter()));
+
+ ListDataProvider<TicketModel> ticketsDp = new ListDataProvider<TicketModel>(tickets);
+ DataView<TicketModel> ticketsView = new DataView<TicketModel>("ticket", ticketsDp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+
+ public void populateItem(final Item<TicketModel> item) {
+ final TicketModel entry = item.getModelObject();
+ Label stateLabel = new Label("ticketState", entry.state);
+ WicketUtils.setTicketCssClass(stateLabel, entry.state);
+ item.add(stateLabel);
+ item.add(WicketUtils.createDateLabel("ticketDate", entry.date, GitBlitWebSession
+ .get().getTimezone(), getTimeUtils()));
+ item.add(new Label("ticketHandler", StringUtils.trimString(
+ entry.handler.toLowerCase(), 30)));
+ item.add(new LinkPanel("ticketTitle", "list subject", StringUtils.trimString(
+ entry.title, 80), TicketPage.class, newPathParameter(entry.name)));
+
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(ticketsView);
+ }
+
+ protected PageParameters newPathParameter(String path) {
+ return WicketUtils.newPathParameter(repositoryName, objectId, path);
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.tickets");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/TreePage.html b/src/main/java/com/gitblit/wicket/pages/TreePage.html new file mode 100644 index 00000000..b7e55ed6 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/TreePage.html @@ -0,0 +1,55 @@ +<!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:extend>
+
+ <!-- blob nav links -->
+ <div class="page_nav2">
+ <a wicket:id="historyLink"><wicket:message key="gb.history"></wicket:message></a> | <a wicket:id="headLink"><wicket:message key="gb.head"></wicket:message></a> | <span wicket:id="compressedLinks"></span>
+ </div>
+
+ <!-- commit header -->
+ <div wicket:id="commitHeader">[commit header]</div>
+
+ <!-- breadcrumbs -->
+ <div wicket:id="breadcrumbs">[breadcrumbs]</div>
+
+ <!-- changed paths -->
+ <table style="width:100%" class="pretty">
+ <tr wicket:id="changedPath">
+ <td class="icon"><img wicket:id="pathIcon" /></td>
+ <td><span wicket:id="pathName"></span></td>
+ <td class="hidden-phone size"><span wicket:id="pathSize">[path size]</span></td>
+ <td class="hidden-phone mode"><span wicket:id="pathPermissions">[path permissions]</span></td>
+ <td class="treeLinks"><span wicket:id="pathLinks">[path links]</span></td>
+ </tr>
+ </table>
+
+ <!-- submodule links -->
+ <wicket:fragment wicket:id="submoduleLinks">
+ <span class="link">
+ <a wicket:id="view"><wicket:message key="gb.view"></wicket:message></a> | <span class="hidden-phone"><a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | </span><a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a> | <span wicket:id="compressedLinks"></span>
+ </span>
+ </wicket:fragment>
+
+ <!-- tree links -->
+ <wicket:fragment wicket:id="treeLinks">
+ <span class="link">
+ <span class="hidden-phone"><a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | </span><a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a> | <span wicket:id="compressedLinks"></span>
+ </span>
+ </wicket:fragment>
+
+ <!-- blob links -->
+ <wicket:fragment wicket:id="blobLinks">
+ <span class="link">
+ <span class="hidden-phone"><a wicket:id="view"><wicket:message key="gb.view"></wicket:message></a> | <a wicket:id="raw"><wicket:message key="gb.raw"></wicket:message></a> | <a wicket:id="blame"><wicket:message key="gb.blame"></wicket:message></a> | </span> <a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a>
+ </span>
+ </wicket:fragment>
+
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/TreePage.java b/src/main/java/com/gitblit/wicket/pages/TreePage.java new file mode 100644 index 00000000..bc27f0c2 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/TreePage.java @@ -0,0 +1,186 @@ +/*
+ * Copyright 2011 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.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import com.gitblit.models.PathModel;
+import com.gitblit.models.SubmoduleModel;
+import com.gitblit.utils.ByteFormat;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.CommitHeaderPanel;
+import com.gitblit.wicket.panels.CompressedDownloadsPanel;
+import com.gitblit.wicket.panels.LinkPanel;
+import com.gitblit.wicket.panels.PathBreadcrumbsPanel;
+
+public class TreePage extends RepositoryPage {
+
+ public TreePage(PageParameters params) {
+ super(params);
+
+ final String path = WicketUtils.getPath(params);
+
+ Repository r = getRepository();
+ RevCommit commit = getCommit();
+ List<PathModel> paths = JGitUtils.getFilesInPath(r, path, commit);
+
+ // tree page links
+ add(new BookmarkablePageLink<Void>("historyLink", HistoryPage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, path)));
+ add(new BookmarkablePageLink<Void>("headLink", TreePage.class,
+ WicketUtils.newPathParameter(repositoryName, Constants.HEAD, path)));
+ add(new CompressedDownloadsPanel("compressedLinks", getRequest()
+ .getRelativePathPrefixToContextRoot(), repositoryName, objectId, path));
+
+ add(new CommitHeaderPanel("commitHeader", repositoryName, commit));
+
+ // breadcrumbs
+ add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, path, objectId));
+ if (path != null && path.trim().length() > 0) {
+ // add .. parent path entry
+ String parentPath = null;
+ if (path.lastIndexOf('/') > -1) {
+ parentPath = path.substring(0, path.lastIndexOf('/'));
+ }
+ PathModel model = new PathModel("..", parentPath, 0, FileMode.TREE.getBits(), null, objectId);
+ model.isParentPath = true;
+ paths.add(0, model);
+ }
+
+ final ByteFormat byteFormat = new ByteFormat();
+
+ final String baseUrl = WicketUtils.getGitblitURL(getRequest());
+
+ // changed paths list
+ ListDataProvider<PathModel> pathsDp = new ListDataProvider<PathModel>(paths);
+ DataView<PathModel> pathsView = new DataView<PathModel>("changedPath", pathsDp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+
+ public void populateItem(final Item<PathModel> item) {
+ PathModel entry = item.getModelObject();
+ item.add(new Label("pathPermissions", JGitUtils.getPermissionsFromMode(entry.mode)));
+ if (entry.isParentPath) {
+ // parent .. path
+ item.add(WicketUtils.newBlankImage("pathIcon"));
+ item.add(new Label("pathSize", ""));
+ item.add(new LinkPanel("pathName", null, entry.name, TreePage.class,
+ WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path)));
+ item.add(new Label("pathLinks", ""));
+ } else {
+ if (entry.isTree()) {
+ // folder/tree link
+ item.add(WicketUtils.newImage("pathIcon", "folder_16x16.png"));
+ item.add(new Label("pathSize", ""));
+ item.add(new LinkPanel("pathName", "list", entry.name, TreePage.class,
+ WicketUtils.newPathParameter(repositoryName, entry.commitId,
+ entry.path)));
+
+ // links
+ Fragment links = new Fragment("pathLinks", "treeLinks", this);
+ links.add(new BookmarkablePageLink<Void>("tree", TreePage.class,
+ WicketUtils.newPathParameter(repositoryName, entry.commitId,
+ entry.path)));
+ links.add(new BookmarkablePageLink<Void>("history", HistoryPage.class,
+ WicketUtils.newPathParameter(repositoryName, entry.commitId,
+ entry.path)));
+ links.add(new CompressedDownloadsPanel("compressedLinks", baseUrl,
+ repositoryName, objectId, entry.path));
+
+ item.add(links);
+ } else if (entry.isSubmodule()) {
+ // submodule
+ String submoduleId = entry.objectId;
+ String submodulePath;
+ boolean hasSubmodule = false;
+ SubmoduleModel submodule = getSubmodule(entry.path);
+ submodulePath = submodule.gitblitPath;
+ hasSubmodule = submodule.hasSubmodule;
+
+ item.add(WicketUtils.newImage("pathIcon", "git-orange-16x16.png"));
+ item.add(new Label("pathSize", ""));
+ item.add(new LinkPanel("pathName", "list", entry.name + " @ " +
+ getShortObjectId(submoduleId), TreePage.class,
+ WicketUtils.newPathParameter(submodulePath, submoduleId, "")).setEnabled(hasSubmodule));
+
+ Fragment links = new Fragment("pathLinks", "submoduleLinks", this);
+ links.add(new BookmarkablePageLink<Void>("view", SummaryPage.class,
+ WicketUtils.newRepositoryParameter(submodulePath)).setEnabled(hasSubmodule));
+ links.add(new BookmarkablePageLink<Void>("tree", TreePage.class,
+ WicketUtils.newPathParameter(submodulePath, submoduleId,
+ "")).setEnabled(hasSubmodule));
+ links.add(new BookmarkablePageLink<Void>("history", HistoryPage.class,
+ WicketUtils.newPathParameter(repositoryName, entry.commitId,
+ entry.path)));
+ links.add(new CompressedDownloadsPanel("compressedLinks", baseUrl,
+ submodulePath, submoduleId, "").setEnabled(hasSubmodule));
+ item.add(links);
+ } else {
+ // blob link
+ String displayPath = entry.name;
+ String path = entry.path;
+ if (entry.isSymlink()) {
+ path = JGitUtils.getStringContent(getRepository(), getCommit().getTree(), path);
+ displayPath = entry.name + " -> " + path;
+ }
+ item.add(WicketUtils.getFileImage("pathIcon", entry.name));
+ item.add(new Label("pathSize", byteFormat.format(entry.size)));
+ item.add(new LinkPanel("pathName", "list", displayPath, BlobPage.class,
+ WicketUtils.newPathParameter(repositoryName, entry.commitId,
+ path)));
+
+ // links
+ Fragment links = new Fragment("pathLinks", "blobLinks", this);
+ links.add(new BookmarkablePageLink<Void>("view", BlobPage.class,
+ WicketUtils.newPathParameter(repositoryName, entry.commitId,
+ path)));
+ links.add(new BookmarkablePageLink<Void>("raw", RawPage.class, WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, path)));
+ links.add(new BookmarkablePageLink<Void>("blame", BlamePage.class,
+ WicketUtils.newPathParameter(repositoryName, entry.commitId,
+ path)));
+ links.add(new BookmarkablePageLink<Void>("history", HistoryPage.class,
+ WicketUtils.newPathParameter(repositoryName, entry.commitId,
+ path)));
+ item.add(links);
+ }
+ }
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(pathsView);
+ }
+
+ @Override
+ protected String getPageName() {
+ return getString("gb.tree");
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.html b/src/main/java/com/gitblit/wicket/pages/UserPage.html new file mode 100644 index 00000000..c7131c09 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.html @@ -0,0 +1,50 @@ +<!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:extend>
+
+ <div class="row">
+ <div class="span4">
+ <div wicket:id="gravatar"></div>
+ <div style="text-align: left;">
+ <h2><span wicket:id="userDisplayName"></span></h2>
+ <div><i class="icon-user"></i> <span wicket:id="userUsername"></span></div>
+ <div><i class="icon-envelope"></i><span wicket:id="userEmail"></span></div>
+ </div>
+ </div>
+
+ <div class="span8">
+ <div class="pull-right">
+ <a class="btn-small" wicket:id="newRepository" style="padding-right:0px;">
+ <i class="icon icon-plus-sign"></i>
+ <wicket:message key="gb.newRepository"></wicket:message>
+ </a>
+ </div>
+ <div class="tabbable">
+ <!-- tab titles -->
+ <ul class="nav nav-tabs">
+ <li class="active"><a href="#repositories" data-toggle="tab"><wicket:message key="gb.repositories"></wicket:message></a></li>
+ </ul>
+
+ <!-- tab content -->
+ <div class="tab-content">
+
+ <!-- repositories tab -->
+ <div class="tab-pane active" id="repositories">
+ <table width="100%">
+ <tbody>
+ <tr wicket:id="repositoryList"><td style="border-bottom:1px solid #eee;"><span wicket:id="repository"></span></td></tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java new file mode 100644 index 00000000..f4331dd1 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java @@ -0,0 +1,155 @@ +/*
+ * Copyright 2012 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.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.eclipse.jgit.lib.PersonIdent;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.ProjectModel;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebApp;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.GitblitRedirectException;
+import com.gitblit.wicket.PageRegistration;
+import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
+import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.panels.GravatarImage;
+import com.gitblit.wicket.panels.LinkPanel;
+import com.gitblit.wicket.panels.ProjectRepositoryPanel;
+
+public class UserPage extends RootPage {
+
+ List<ProjectModel> projectModels = new ArrayList<ProjectModel>();
+
+ public UserPage() {
+ super();
+ throw new GitblitRedirectException(GitBlitWebApp.get().getHomePage());
+ }
+
+ public UserPage(PageParameters params) {
+ super(params);
+ setup(params);
+ }
+
+ @Override
+ protected boolean reusePageParameters() {
+ return true;
+ }
+
+ private void setup(PageParameters params) {
+ setupPage("", "");
+ // check to see if we should display a login message
+ boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, true);
+ if (authenticateView && !GitBlitWebSession.get().isLoggedIn()) {
+ authenticationError("Please login");
+ return;
+ }
+
+ String userName = WicketUtils.getUsername(params);
+ if (StringUtils.isEmpty(userName)) {
+ throw new GitblitRedirectException(GitBlitWebApp.get().getHomePage());
+ }
+
+ UserModel user = GitBlit.self().getUserModel(userName);
+ if (user == null) {
+ // construct a temporary user model
+ user = new UserModel(userName);
+ }
+
+ String projectName = "~" + userName;
+
+ ProjectModel project = GitBlit.self().getProjectModel(projectName);
+ if (project == null) {
+ project = new ProjectModel(projectName);
+ }
+
+ add(new Label("userDisplayName", user.getDisplayName()));
+ add(new Label("userUsername", user.username));
+ LinkPanel email = new LinkPanel("userEmail", null, user.emailAddress, "mailto:#");
+ email.setRenderBodyOnly(true);
+ add(email.setVisible(GitBlit.getBoolean(Keys.web.showEmailAddresses, true) && !StringUtils.isEmpty(user.emailAddress)));
+
+ PersonIdent person = new PersonIdent(user.getDisplayName(), user.emailAddress == null ? user.getDisplayName() : user.emailAddress);
+ add(new GravatarImage("gravatar", person, 210));
+
+ 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));
+ } else {
+ add(new Label("newRepository").setVisible(false));
+ }
+
+ List<RepositoryModel> repositories = getRepositories(params);
+
+ Collections.sort(repositories, new Comparator<RepositoryModel>() {
+ @Override
+ public int compare(RepositoryModel o1, RepositoryModel o2) {
+ // reverse-chronological sort
+ return o2.lastChange.compareTo(o1.lastChange);
+ }
+ });
+
+ final ListDataProvider<RepositoryModel> dp = new ListDataProvider<RepositoryModel>(repositories);
+ DataView<RepositoryModel> dataView = new DataView<RepositoryModel>("repositoryList", dp) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<RepositoryModel> item) {
+ final RepositoryModel entry = item.getModelObject();
+
+ ProjectRepositoryPanel row = new ProjectRepositoryPanel("repository",
+ getLocalizer(), this, showAdmin, entry, getAccessRestrictions());
+ item.add(row);
+ }
+ };
+ add(dataView);
+ }
+
+ @Override
+ protected void addDropDownMenus(List<PageRegistration> pages) {
+ PageParameters params = getPageParameters();
+
+ DropDownMenuRegistration menu = new DropDownMenuRegistration("gb.filters",
+ UserPage.class);
+ // preserve time filter option on repository choices
+ menu.menuItems.addAll(getRepositoryFilterItems(params));
+
+ // preserve repository filter option on time choices
+ menu.menuItems.addAll(getTimeFilterItems(params));
+
+ if (menu.menuItems.size() > 0) {
+ // Reset Filter
+ menu.menuItems.add(new DropDownMenuItem(getString("gb.reset"), null, null));
+ }
+
+ pages.add(menu);
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/UsersPage.html b/src/main/java/com/gitblit/wicket/pages/UsersPage.html new file mode 100644 index 00000000..edb85f7d --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/UsersPage.html @@ -0,0 +1,13 @@ +<!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:extend>
+ <div wicket:id="teamsPanel">[teams panel]</div>
+
+ <div wicket:id="usersPanel">[users panel]</div>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/UsersPage.java b/src/main/java/com/gitblit/wicket/pages/UsersPage.java new file mode 100644 index 00000000..9526deae --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/UsersPage.java @@ -0,0 +1,33 @@ +/*
+ * Copyright 2011 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 com.gitblit.wicket.RequiresAdminRole;
+import com.gitblit.wicket.panels.TeamsPanel;
+import com.gitblit.wicket.panels.UsersPanel;
+
+@RequiresAdminRole
+public class UsersPage extends RootPage {
+
+ public UsersPage() {
+ super();
+ setupPage("", "");
+
+ add(new TeamsPanel("teamsPanel", showAdmin).setVisible(showAdmin));
+
+ add(new UsersPanel("usersPanel", showAdmin).setVisible(showAdmin));
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/lang-apollo.js b/src/main/java/com/gitblit/wicket/pages/prettify/lang-apollo.js new file mode 100644 index 00000000..bfc0014c --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/lang-apollo.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["com",/^#[^\r\n]*/,null,"#"],["pln",/^[\t\n\r \xA0]+/,null,"\t\n\r \u00a0"],["str",/^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/,null,'"']],[["kwd",/^(?:ADS|AD|AUG|BZF|BZMF|CAE|CAF|CA|CCS|COM|CS|DAS|DCA|DCOM|DCS|DDOUBL|DIM|DOUBLE|DTCB|DTCF|DV|DXCH|EDRUPT|EXTEND|INCR|INDEX|NDX|INHINT|LXCH|MASK|MSK|MP|MSU|NOOP|OVSK|QXCH|RAND|READ|RELINT|RESUME|RETURN|ROR|RXOR|SQUARE|SU|TCR|TCAA|OVSK|TCF|TC|TS|WAND|WOR|WRITE|XCH|XLQ|XXALQ|ZL|ZQ|ADD|ADZ|SUB|SUZ|MPY|MPR|MPZ|DVP|COM|ABS|CLA|CLZ|LDQ|STO|STQ|ALS|LLS|LRS|TRA|TSQ|TMI|TOV|AXT|TIX|DLY|INP|OUT)\s/, +null],["typ",/^(?:-?GENADR|=MINUS|2BCADR|VN|BOF|MM|-?2CADR|-?[1-6]DNADR|ADRES|BBCON|[SE]?BANK\=?|BLOCK|BNKSUM|E?CADR|COUNT\*?|2?DEC\*?|-?DNCHAN|-?DNPTR|EQUALS|ERASE|MEMORY|2?OCT|REMADR|SETLOC|SUBRO|ORG|BSS|BES|SYN|EQU|DEFINE|END)\s/,null],["lit",/^\'(?:-*(?:\w|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?)?/],["pln",/^-*(?:[!-z_]|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?/i],["pun",/^[^\w\t\n\r \xA0()\"\\\';]+/]]),["apollo","agc","aea"])
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/lang-css.js b/src/main/java/com/gitblit/wicket/pages/prettify/lang-css.js new file mode 100644 index 00000000..61157f38 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/lang-css.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[ \t\r\n\f]+/,null," \t\r\n\u000c"]],[["str",/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],["str",/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],["kwd",/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//], +["com",/^(?:<!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#(?:[0-9a-f]{3}){1,2}/i],["pln",/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],["pun",/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^\)\"\']+/]]),["css-str"])
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/lang-hs.js b/src/main/java/com/gitblit/wicket/pages/prettify/lang-hs.js new file mode 100644 index 00000000..00cea7cf --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/lang-hs.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\x0B\x0C\r ]+/,null,"\t\n\u000b\u000c\r "],["str",/^\"(?:[^\"\\\n\x0C\r]|\\[\s\S])*(?:\"|$)/,null,'"'],["str",/^\'(?:[^\'\\\n\x0C\r]|\\[^&])\'?/,null,"'"],["lit",/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+\-]?\d+)?)/i,null,"0123456789"]],[["com",/^(?:(?:--+(?:[^\r\n\x0C]*)?)|(?:\{-(?:[^-]|-+[^-\}])*-\}))/],["kwd",/^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^a-zA-Z0-9\']|$)/, +null],["pln",/^(?:[A-Z][\w\']*\.)*[a-zA-Z][\w\']*/],["pun",/^[^\t\n\x0B\x0C\r a-zA-Z0-9\'\"]+/]]),["hs"])
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/lang-lisp.js b/src/main/java/com/gitblit/wicket/pages/prettify/lang-lisp.js new file mode 100644 index 00000000..fab992b8 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/lang-lisp.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["opn",/^\(/,null,"("],["clo",/^\)/,null,")"],["com",/^;[^\r\n]*/,null,";"],["pln",/^[\t\n\r \xA0]+/,null,"\t\n\r \u00a0"],["str",/^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/,null,'"']],[["kwd",/^(?:block|c[ad]+r|catch|con[ds]|def(?:ine|un)|do|eq|eql|equal|equalp|eval-when|flet|format|go|if|labels|lambda|let|load-time-value|locally|macrolet|multiple-value-call|nil|progn|progv|quote|require|return-from|setq|symbol-macrolet|t|tagbody|the|throw|unwind)\b/, +null],["lit",/^[+\-]?(?:0x[0-9a-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[ed][+\-]?\d+)?)/i],["lit",/^\'(?:-*(?:\w|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?)?/],["pln",/^-*(?:[a-z_]|\\[\x21-\x7e])(?:[\w-]*|\\[\x21-\x7e])[=!?]?/i],["pun",/^[^\w\t\n\r \xA0()\"\\\';]+/]]),["cl","el","lisp","scm"])
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/lang-lua.js b/src/main/java/com/gitblit/wicket/pages/prettify/lang-lua.js new file mode 100644 index 00000000..45d0ba28 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/lang-lua.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xA0]+/,null,"\t\n\r \u00a0"],["str",/^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])*(?:\'|$))/,null,"\"'"]],[["com",/^--(?:\[(=*)\[[\s\S]*?(?:\]\1\]|$)|[^\r\n]*)/],["str",/^\[(=*)\[[\s\S]*?(?:\]\1\]|$)/],["kwd",/^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,null],["lit",/^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i], +["pln",/^[a-z_]\w*/i],["pun",/^[^\w\t\n\r \xA0][^\w\t\n\r \xA0\"\'\-\+=]*/]]),["lua"])
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/lang-ml.js b/src/main/java/com/gitblit/wicket/pages/prettify/lang-ml.js new file mode 100644 index 00000000..5879726e --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/lang-ml.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xA0]+/,null,"\t\n\r \u00a0"],["com",/^#(?:if[\t\n\r \xA0]+(?:[a-z_$][\w\']*|``[^\r\n\t`]*(?:``|$))|else|endif|light)/i,null,"#"],["str",/^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])*(?:\'|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\r\n]*|\(\*[\s\S]*?\*\))/],["kwd",/^(?:abstract|and|as|assert|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|if|in|inherit|inline|interface|internal|lazy|let|match|member|module|mutable|namespace|new|null|of|open|or|override|private|public|rec|return|static|struct|then|to|true|try|type|upcast|use|val|void|when|while|with|yield|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|global|include|method|mixin|object|parallel|process|protected|pure|sealed|trait|virtual|volatile)\b/], +["lit",/^[+\-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],["pln",/^(?:[a-z_]\w*[!?#]?|``[^\r\n\t`]*(?:``|$))/i],["pun",/^[^\t\n\r \xA0\"\'\w]+/]]),["fs","ml"])
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/lang-proto.js b/src/main/java/com/gitblit/wicket/pages/prettify/lang-proto.js new file mode 100644 index 00000000..f713420c --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/lang-proto.js @@ -0,0 +1 @@ +PR.registerLangHandler(PR.sourceDecorator({keywords:"bool bytes default double enum extend extensions false fixed32 fixed64 float group import int32 int64 max message option optional package repeated required returns rpc service sfixed32 sfixed64 sint32 sint64 string syntax to true uint32 uint64",cStyleComments:true}),["proto"])
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/lang-scala.js b/src/main/java/com/gitblit/wicket/pages/prettify/lang-scala.js new file mode 100644 index 00000000..00f4e0c2 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/lang-scala.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xA0]+/,null,"\t\n\r \u00a0"],["str",/^(?:"(?:(?:""(?:""?(?!")|[^\\"]|\\.)*"{0,3})|(?:[^"\r\n\\]|\\.)*"?))/,null,'"'],["lit",/^`(?:[^\r\n\\`]|\\.)*`?/,null,"`"],["pun",/^[!#%&()*+,\-:;<=>?@\[\\\]^{|}~]+/,null,"!#%&()*+,-:;<=>?@[\\]^{|}~"]],[["str",/^'(?:[^\r\n\\']|\\(?:'|[^\r\n']+))'/],["lit",/^'[a-zA-Z_$][\w$]*(?!['$\w])/],["kwd",/^(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|object|override|package|private|protected|requires|return|sealed|super|throw|trait|try|type|val|var|while|with|yield)\b/], +["lit",/^(?:true|false|null|this)\b/],["lit",/^(?:(?:0(?:[0-7]+|X[0-9A-F]+))L?|(?:(?:0|[1-9][0-9]*)(?:(?:\.[0-9]+)?(?:E[+\-]?[0-9]+)?F?|L?))|\\.[0-9]+(?:E[+\-]?[0-9]+)?F?)/i],["typ",/^[$_]*[A-Z][_$A-Z0-9]*[a-z][\w$]*/],["pln",/^[$a-zA-Z_][\w$]*/],["com",/^\/(?:\/.*|\*(?:\/|\**[^*/])*(?:\*+\/?)?)/],["pun",/^(?:\.+|\/)/]]),["scala"])
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/lang-sql.js b/src/main/java/com/gitblit/wicket/pages/prettify/lang-sql.js new file mode 100644 index 00000000..800b13ea --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/lang-sql.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xA0]+/,null,"\t\n\r \u00a0"],["str",/^(?:"(?:[^\"\\]|\\.)*"|'(?:[^\'\\]|\\.)*')/,null,"\"'"]],[["com",/^(?:--[^\r\n]*|\/\*[\s\S]*?(?:\*\/|$))/],["kwd",/^(?:ADD|ALL|ALTER|AND|ANY|AS|ASC|AUTHORIZATION|BACKUP|BEGIN|BETWEEN|BREAK|BROWSE|BULK|BY|CASCADE|CASE|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMN|COMMIT|COMPUTE|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATABASE|DBCC|DEALLOCATE|DECLARE|DEFAULT|DELETE|DENY|DESC|DISK|DISTINCT|DISTRIBUTED|DOUBLE|DROP|DUMMY|DUMP|ELSE|END|ERRLVL|ESCAPE|EXCEPT|EXEC|EXECUTE|EXISTS|EXIT|FETCH|FILE|FILLFACTOR|FOR|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GOTO|GRANT|GROUP|HAVING|HOLDLOCK|IDENTITY|IDENTITYCOL|IDENTITY_INSERT|IF|IN|INDEX|INNER|INSERT|INTERSECT|INTO|IS|JOIN|KEY|KILL|LEFT|LIKE|LINENO|LOAD|NATIONAL|NOCHECK|NONCLUSTERED|NOT|NULL|NULLIF|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPENXML|OPTION|OR|ORDER|OUTER|OVER|PERCENT|PLAN|PRECISION|PRIMARY|PRINT|PROC|PROCEDURE|PUBLIC|RAISERROR|READ|READTEXT|RECONFIGURE|REFERENCES|REPLICATION|RESTORE|RESTRICT|RETURN|REVOKE|RIGHT|ROLLBACK|ROWCOUNT|ROWGUIDCOL|RULE|SAVE|SCHEMA|SELECT|SESSION_USER|SET|SETUSER|SHUTDOWN|SOME|STATISTICS|SYSTEM_USER|TABLE|TEXTSIZE|THEN|TO|TOP|TRAN|TRANSACTION|TRIGGER|TRUNCATE|TSEQUAL|UNION|UNIQUE|UPDATE|UPDATETEXT|USE|USER|VALUES|VARYING|VIEW|WAITFOR|WHEN|WHERE|WHILE|WITH|WRITETEXT)(?=[^\w-]|$)/i, +null],["lit",/^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],["pln",/^[a-z_][\w-]*/i],["pun",/^[^\w\t\n\r \xA0\"\'][^\w\t\n\r \xA0+\-\"\']*/]]),["sql"])
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/lang-vb.js b/src/main/java/com/gitblit/wicket/pages/prettify/lang-vb.js new file mode 100644 index 00000000..c479c11e --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/lang-vb.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xA0\u2028\u2029]+/,null,"\t\n\r \u00a0\u2028\u2029"],["str",/^(?:[\"\u201C\u201D](?:[^\"\u201C\u201D]|[\"\u201C\u201D]{2})(?:[\"\u201C\u201D]c|$)|[\"\u201C\u201D](?:[^\"\u201C\u201D]|[\"\u201C\u201D]{2})*(?:[\"\u201C\u201D]|$))/i,null,'"\u201c\u201d'],["com",/^[\'\u2018\u2019][^\r\n\u2028\u2029]*/,null,"'\u2018\u2019"]],[["kwd",/^(?:AddHandler|AddressOf|Alias|And|AndAlso|Ansi|As|Assembly|Auto|Boolean|ByRef|Byte|ByVal|Call|Case|Catch|CBool|CByte|CChar|CDate|CDbl|CDec|Char|CInt|Class|CLng|CObj|Const|CShort|CSng|CStr|CType|Date|Decimal|Declare|Default|Delegate|Dim|DirectCast|Do|Double|Each|Else|ElseIf|End|EndIf|Enum|Erase|Error|Event|Exit|Finally|For|Friend|Function|Get|GetType|GoSub|GoTo|Handles|If|Implements|Imports|In|Inherits|Integer|Interface|Is|Let|Lib|Like|Long|Loop|Me|Mod|Module|MustInherit|MustOverride|MyBase|MyClass|Namespace|New|Next|Not|NotInheritable|NotOverridable|Object|On|Option|Optional|Or|OrElse|Overloads|Overridable|Overrides|ParamArray|Preserve|Private|Property|Protected|Public|RaiseEvent|ReadOnly|ReDim|RemoveHandler|Resume|Return|Select|Set|Shadows|Shared|Short|Single|Static|Step|Stop|String|Structure|Sub|SyncLock|Then|Throw|To|Try|TypeOf|Unicode|Until|Variant|Wend|When|While|With|WithEvents|WriteOnly|Xor|EndIf|GoSub|Let|Variant|Wend)\b/i, +null],["com",/^REM[^\r\n\u2028\u2029]*/i],["lit",/^(?:True\b|False\b|Nothing\b|\d+(?:E[+\-]?\d+[FRD]?|[FRDSIL])?|(?:&H[0-9A-F]+|&O[0-7]+)[SIL]?|\d*\.\d+(?:E[+\-]?\d+)?[FRD]?|#\s+(?:\d+[\-\/]\d+[\-\/]\d+(?:\s+\d+:\d+(?::\d+)?(\s*(?:AM|PM))?)?|\d+:\d+(?::\d+)?(\s*(?:AM|PM))?)\s+#)/i],["pln",/^(?:(?:[a-z]|_\w)\w*|\[(?:[a-z]|_\w)\w*\])/i],["pun",/^[^\w\t\n\r \"\'\[\]\xA0\u2018\u2019\u201C\u201D\u2028\u2029]+/],["pun",/^(?:\[|\])/]]),["vb","vbs"])
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/lang-vhdl.js b/src/main/java/com/gitblit/wicket/pages/prettify/lang-vhdl.js new file mode 100644 index 00000000..dc81a3fe --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/lang-vhdl.js @@ -0,0 +1,3 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xA0]+/,null,"\t\n\r \u00a0"]],[["str",/^(?:[BOX]?"(?:[^\"]|"")*"|'.')/i],["com",/^--[^\r\n]*/],["kwd",/^(?:abs|access|after|alias|all|and|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|constant|disconnect|downto|else|elsif|end|entity|exit|file|for|function|generate|generic|group|guarded|if|impure|in|inertial|inout|is|label|library|linkage|literal|loop|map|mod|nand|new|next|nor|not|null|of|on|open|or|others|out|package|port|postponed|procedure|process|pure|range|record|register|reject|rem|report|return|rol|ror|select|severity|shared|signal|sla|sll|sra|srl|subtype|then|to|transport|type|unaffected|units|until|use|variable|wait|when|while|with|xnor|xor)(?=[^\w-]|$)/i, +null],["typ",/^(?:bit|bit_vector|character|boolean|integer|real|time|string|severity_level|positive|natural|signed|unsigned|line|text|std_u?logic(?:_vector)?)(?=[^\w-]|$)/i,null],["typ",/^\'(?:ACTIVE|ASCENDING|BASE|DELAYED|DRIVING|DRIVING_VALUE|EVENT|HIGH|IMAGE|INSTANCE_NAME|LAST_ACTIVE|LAST_EVENT|LAST_VALUE|LEFT|LEFTOF|LENGTH|LOW|PATH_NAME|POS|PRED|QUIET|RANGE|REVERSE_RANGE|RIGHT|RIGHTOF|SIMPLE_NAME|STABLE|SUCC|TRANSACTION|VAL|VALUE)(?=[^\w-]|$)/i,null],["lit",/^\d+(?:_\d+)*(?:#[\w\\.]+#(?:[+\-]?\d+(?:_\d+)*)?|(?:\.\d+(?:_\d+)*)?(?:E[+\-]?\d+(?:_\d+)*)?)/i], +["pln",/^(?:[a-z]\w*|\\[^\\]*\\)/i],["pun",/^[^\w\t\n\r \xA0\"\'][^\w\t\n\r \xA0\-\"\']*/]]),["vhdl","vhd"])
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/lang-wiki.js b/src/main/java/com/gitblit/wicket/pages/prettify/lang-wiki.js new file mode 100644 index 00000000..3b8fb500 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/lang-wiki.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t \xA0a-gi-z0-9]+/,null,"\t \u00a0abcdefgijklmnopqrstuvwxyz0123456789"],["pun",/^[=*~\^\[\]]+/,null,"=*~^[]"]],[["lang-wiki.meta",/(?:^^|\r\n?|\n)(#[a-z]+)\b/],["lit",/^(?:[A-Z][a-z][a-z0-9]+[A-Z][a-z][a-zA-Z0-9]+)\b/],["lang-",/^\{\{\{([\s\S]+?)\}\}\}/],["lang-",/^`([^\r\n`]+)`/],["str",/^https?:\/\/[^\/?#\s]*(?:\/[^?#\s]*)?(?:\?[^#\s]*)?(?:#\S*)?/i],["pln",/^(?:\r\n|[\s\S])[^#=*~^A-Zh\{`\[\r\n]*/]]),["wiki"]); +PR.registerLangHandler(PR.createSimpleLexer([["kwd",/^#[a-z]+/i,null,"#"]],[]),["wiki.meta"])
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/lang-yaml.js b/src/main/java/com/gitblit/wicket/pages/prettify/lang-yaml.js new file mode 100644 index 00000000..f2f36070 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/lang-yaml.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pun",/^[:|>?]+/,null,":|>?"],["dec",/^%(?:YAML|TAG)[^#\r\n]+/,null,"%"],["typ",/^[&]\S+/,null,"&"],["typ",/^!\S*/,null,"!"],["str",/^"(?:[^\\"]|\\.)*(?:"|$)/,null,'"'],["str",/^'(?:[^']|'')*(?:'|$)/,null,"'"],["com",/^#[^\r\n]*/,null,"#"],["pln",/^\s+/,null," \t\r\n"]],[["dec",/^(?:---|\.\.\.)(?:[\r\n]|$)/],["pun",/^-/],["kwd",/^\w+:[ \r\n]/],["pln",/^\w+/]]), +["yaml","yml"])
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/prettify.css b/src/main/java/com/gitblit/wicket/pages/prettify/prettify.css new file mode 100644 index 00000000..2925d13a --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/prettify.css @@ -0,0 +1 @@ +.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun{color:#660}.pln{color:#000}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec{color:#606}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}@media print{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun{color:#440}.pln{color:#000}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/prettify/prettify.js b/src/main/java/com/gitblit/wicket/pages/prettify/prettify.js new file mode 100644 index 00000000..c9161da9 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/prettify/prettify.js @@ -0,0 +1,33 @@ +window.PR_SHOULD_USE_CONTINUATION=true;window.PR_TAB_WIDTH=8;window.PR_normalizedHtml=window.PR=window.prettyPrintOne=window.prettyPrint=void 0;window._pr_isIE6=function(){var y=navigator&&navigator.userAgent&&navigator.userAgent.match(/\bMSIE ([678])\./);y=y?+y[1]:false;window._pr_isIE6=function(){return y};return y}; +(function(){function y(b){return b.replace(L,"&").replace(M,"<").replace(N,">")}function H(b,f,i){switch(b.nodeType){case 1:var o=b.tagName.toLowerCase();f.push("<",o);var l=b.attributes,n=l.length;if(n){if(i){for(var r=[],j=n;--j>=0;)r[j]=l[j];r.sort(function(q,m){return q.name<m.name?-1:q.name===m.name?0:1});l=r}for(j=0;j<n;++j){r=l[j];r.specified&&f.push(" ",r.name.toLowerCase(),'="',r.value.replace(L,"&").replace(M,"<").replace(N,">").replace(X,"""),'"')}}f.push(">"); +for(l=b.firstChild;l;l=l.nextSibling)H(l,f,i);if(b.firstChild||!/^(?:br|link|img)$/.test(o))f.push("</",o,">");break;case 3:case 4:f.push(y(b.nodeValue));break}}function O(b){function f(c){if(c.charAt(0)!=="\\")return c.charCodeAt(0);switch(c.charAt(1)){case "b":return 8;case "t":return 9;case "n":return 10;case "v":return 11;case "f":return 12;case "r":return 13;case "u":case "x":return parseInt(c.substring(2),16)||c.charCodeAt(1);case "0":case "1":case "2":case "3":case "4":case "5":case "6":case "7":return parseInt(c.substring(1), +8);default:return c.charCodeAt(1)}}function i(c){if(c<32)return(c<16?"\\x0":"\\x")+c.toString(16);c=String.fromCharCode(c);if(c==="\\"||c==="-"||c==="["||c==="]")c="\\"+c;return c}function o(c){var d=c.substring(1,c.length-1).match(RegExp("\\\\u[0-9A-Fa-f]{4}|\\\\x[0-9A-Fa-f]{2}|\\\\[0-3][0-7]{0,2}|\\\\[0-7]{1,2}|\\\\[\\s\\S]|-|[^-\\\\]","g"));c=[];for(var a=[],k=d[0]==="^",e=k?1:0,h=d.length;e<h;++e){var g=d[e];switch(g){case "\\B":case "\\b":case "\\D":case "\\d":case "\\S":case "\\s":case "\\W":case "\\w":c.push(g); +continue}g=f(g);var s;if(e+2<h&&"-"===d[e+1]){s=f(d[e+2]);e+=2}else s=g;a.push([g,s]);if(!(s<65||g>122)){s<65||g>90||a.push([Math.max(65,g)|32,Math.min(s,90)|32]);s<97||g>122||a.push([Math.max(97,g)&-33,Math.min(s,122)&-33])}}a.sort(function(v,w){return v[0]-w[0]||w[1]-v[1]});d=[];g=[NaN,NaN];for(e=0;e<a.length;++e){h=a[e];if(h[0]<=g[1]+1)g[1]=Math.max(g[1],h[1]);else d.push(g=h)}a=["["];k&&a.push("^");a.push.apply(a,c);for(e=0;e<d.length;++e){h=d[e];a.push(i(h[0]));if(h[1]>h[0]){h[1]+1>h[0]&&a.push("-"); +a.push(i(h[1]))}}a.push("]");return a.join("")}function l(c){for(var d=c.source.match(RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g")),a=d.length,k=[],e=0,h=0;e<a;++e){var g=d[e];if(g==="(")++h;else if("\\"===g.charAt(0))if((g=+g.substring(1))&&g<=h)k[g]=-1}for(e=1;e<k.length;++e)if(-1===k[e])k[e]=++n;for(h=e=0;e<a;++e){g=d[e];if(g==="("){++h;if(k[h]===undefined)d[e]="(?:"}else if("\\"=== +g.charAt(0))if((g=+g.substring(1))&&g<=h)d[e]="\\"+k[h]}for(h=e=0;e<a;++e)if("^"===d[e]&&"^"!==d[e+1])d[e]="";if(c.ignoreCase&&r)for(e=0;e<a;++e){g=d[e];c=g.charAt(0);if(g.length>=2&&c==="[")d[e]=o(g);else if(c!=="\\")d[e]=g.replace(/[a-zA-Z]/g,function(s){s=s.charCodeAt(0);return"["+String.fromCharCode(s&-33,s|32)+"]"})}return d.join("")}for(var n=0,r=false,j=false,q=0,m=b.length;q<m;++q){var t=b[q];if(t.ignoreCase)j=true;else if(/[a-z]/i.test(t.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, +""))){r=true;j=false;break}}var p=[];q=0;for(m=b.length;q<m;++q){t=b[q];if(t.global||t.multiline)throw Error(""+t);p.push("(?:"+l(t)+")")}return RegExp(p.join("|"),j?"gi":"g")}function Y(b){var f=0;return function(i){for(var o=null,l=0,n=0,r=i.length;n<r;++n)switch(i.charAt(n)){case "\t":o||(o=[]);o.push(i.substring(l,n));l=b-f%b;for(f+=l;l>=0;l-=16)o.push(" ".substring(0,l));l=n+1;break;case "\n":f=0;break;default:++f}if(!o)return i;o.push(i.substring(l));return o.join("")}}function I(b, +f,i,o){if(f){b={source:f,c:b};i(b);o.push.apply(o,b.d)}}function B(b,f){var i={},o;(function(){for(var r=b.concat(f),j=[],q={},m=0,t=r.length;m<t;++m){var p=r[m],c=p[3];if(c)for(var d=c.length;--d>=0;)i[c.charAt(d)]=p;p=p[1];c=""+p;if(!q.hasOwnProperty(c)){j.push(p);q[c]=null}}j.push(/[\0-\uffff]/);o=O(j)})();var l=f.length;function n(r){for(var j=r.c,q=[j,z],m=0,t=r.source.match(o)||[],p={},c=0,d=t.length;c<d;++c){var a=t[c],k=p[a],e=void 0,h;if(typeof k==="string")h=false;else{var g=i[a.charAt(0)]; +if(g){e=a.match(g[1]);k=g[0]}else{for(h=0;h<l;++h){g=f[h];if(e=a.match(g[1])){k=g[0];break}}e||(k=z)}if((h=k.length>=5&&"lang-"===k.substring(0,5))&&!(e&&typeof e[1]==="string")){h=false;k=P}h||(p[a]=k)}g=m;m+=a.length;if(h){h=e[1];var s=a.indexOf(h),v=s+h.length;if(e[2]){v=a.length-e[2].length;s=v-h.length}k=k.substring(5);I(j+g,a.substring(0,s),n,q);I(j+g+s,h,Q(k,h),q);I(j+g+v,a.substring(v),n,q)}else q.push(j+g,k)}r.d=q}return n}function x(b){var f=[],i=[];if(b.tripleQuotedStrings)f.push([A,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/, +null,"'\""]);else b.multiLineStrings?f.push([A,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"]):f.push([A,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"]);b.verbatimStrings&&i.push([A,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null]);if(b.hashComments)if(b.cStyleComments){f.push([C,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"]);i.push([A,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/, +null])}else f.push([C,/^#[^\r\n]*/,null,"#"]);if(b.cStyleComments){i.push([C,/^\/\/[^\r\n]*/,null]);i.push([C,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}b.regexLiterals&&i.push(["lang-regex",RegExp("^"+Z+"(/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/)")]);b=b.keywords.replace(/^\s+|\s+$/g,"");b.length&&i.push([R,RegExp("^(?:"+b.replace(/\s+/g,"|")+")\\b"),null]);f.push([z,/^\s+/,null," \r\n\t\u00a0"]);i.push([J,/^@[a-z_$][a-z_$@0-9]*/i,null],[S,/^@?[A-Z]+[a-z][A-Za-z_$@0-9]*/, +null],[z,/^[a-z_$][a-z_$@0-9]*/i,null],[J,/^(?:0x[a-f0-9]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+\-]?\d+)?)[a-z]*/i,null,"0123456789"],[E,/^.[^\s\w\.$@\'\"\`\/\#]*/,null]);return B(f,i)}function $(b){function f(D){if(D>r){if(j&&j!==q){n.push("</span>");j=null}if(!j&&q){j=q;n.push('<span class="',j,'">')}var T=y(p(i.substring(r,D))).replace(e?d:c,"$1 ");e=k.test(T);n.push(T.replace(a,s));r=D}}var i=b.source,o=b.g,l=b.d,n=[],r=0,j=null,q=null,m=0,t=0,p=Y(window.PR_TAB_WIDTH),c=/([\r\n ]) /g, +d=/(^| ) /gm,a=/\r\n?|\n/g,k=/[ \r\n]$/,e=true,h=window._pr_isIE6();h=h?b.b.tagName==="PRE"?h===6?" \r\n":h===7?" <br>\r":" \r":" <br />":"<br />";var g=b.b.className.match(/\blinenums\b(?::(\d+))?/),s;if(g){for(var v=[],w=0;w<10;++w)v[w]=h+'</li><li class="L'+w+'">';var F=g[1]&&g[1].length?g[1]-1:0;n.push('<ol class="linenums"><li class="L',F%10,'"');F&&n.push(' value="',F+1,'"');n.push(">");s=function(){var D=v[++F%10];return j?"</span>"+D+'<span class="'+j+'">':D}}else s=h; +for(;;)if(m<o.length?t<l.length?o[m]<=l[t]:true:false){f(o[m]);if(j){n.push("</span>");j=null}n.push(o[m+1]);m+=2}else if(t<l.length){f(l[t]);q=l[t+1];t+=2}else break;f(i.length);j&&n.push("</span>");g&&n.push("</li></ol>");b.a=n.join("")}function u(b,f){for(var i=f.length;--i>=0;){var o=f[i];if(G.hasOwnProperty(o))"console"in window&&console.warn("cannot override language handler %s",o);else G[o]=b}}function Q(b,f){b&&G.hasOwnProperty(b)||(b=/^\s*</.test(f)?"default-markup":"default-code");return G[b]} +function U(b){var f=b.f,i=b.e;b.a=f;try{var o,l=f.match(aa);f=[];var n=0,r=[];if(l)for(var j=0,q=l.length;j<q;++j){var m=l[j];if(m.length>1&&m.charAt(0)==="<"){if(!ba.test(m))if(ca.test(m)){f.push(m.substring(9,m.length-3));n+=m.length-12}else if(da.test(m)){f.push("\n");++n}else if(m.indexOf(V)>=0&&m.replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,' $1="$2$3$4"').match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/)){var t=m.match(W)[2],p=1,c;c=j+1;a:for(;c<q;++c){var d=l[c].match(W);if(d&& +d[2]===t)if(d[1]==="/"){if(--p===0)break a}else++p}if(c<q){r.push(n,l.slice(j,c+1).join(""));j=c}else r.push(n,m)}else r.push(n,m)}else{var a;p=m;var k=p.indexOf("&");if(k<0)a=p;else{for(--k;(k=p.indexOf("&#",k+1))>=0;){var e=p.indexOf(";",k);if(e>=0){var h=p.substring(k+3,e),g=10;if(h&&h.charAt(0)==="x"){h=h.substring(1);g=16}var s=parseInt(h,g);isNaN(s)||(p=p.substring(0,k)+String.fromCharCode(s)+p.substring(e+1))}}a=p.replace(ea,"<").replace(fa,">").replace(ga,"'").replace(ha,'"').replace(ia," ").replace(ja, +"&")}f.push(a);n+=a.length}}o={source:f.join(""),h:r};var v=o.source;b.source=v;b.c=0;b.g=o.h;Q(i,v)(b);$(b)}catch(w){if("console"in window)console.log(w&&w.stack?w.stack:w)}}var A="str",R="kwd",C="com",S="typ",J="lit",E="pun",z="pln",P="src",V="nocode",Z=function(){for(var b=["!","!=","!==","#","%","%=","&","&&","&&=","&=","(","*","*=","+=",",","-=","->","/","/=",":","::",";","<","<<","<<=","<=","=","==","===",">",">=",">>",">>=",">>>",">>>=","?","@","[","^","^=","^^","^^=","{","|","|=","||","||=", +"~","break","case","continue","delete","do","else","finally","instanceof","return","throw","try","typeof"],f="(?:^^|[+-]",i=0;i<b.length;++i)f+="|"+b[i].replace(/([^=<>:&a-z])/g,"\\$1");f+=")\\s*";return f}(),L=/&/g,M=/</g,N=/>/g,X=/\"/g,ea=/</g,fa=/>/g,ga=/'/g,ha=/"/g,ja=/&/g,ia=/ /g,ka=/[\r\n]/g,K=null,aa=RegExp("[^<]+|<!--[\\s\\S]*?--\>|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>|</?[a-zA-Z](?:[^>\"']|'[^']*'|\"[^\"]*\")*>|<","g"),ba=/^<\!--/,ca=/^<!\[CDATA\[/,da=/^<br\b/i,W=/^<(\/?)([a-zA-Z][a-zA-Z0-9]*)/, +la=x({keywords:"break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try typeof alignof align_union asm axiom bool concept concept_map const_cast constexpr decltype dynamic_cast explicit export friend inline late_check mutable namespace nullptr reinterpret_cast static_assert static_cast template typeid typename using virtual wchar_t where break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try typeof abstract boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient as base by checked decimal delegate descending event fixed foreach from group implicit in interface internal into is lock object out override orderby params partial readonly ref sbyte sealed stackalloc string select uint ulong unchecked unsafe ushort var break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try typeof debugger eval export function get null set undefined var with Infinity NaN caller delete die do dump elsif eval exit foreach for goto if import last local my next no our print package redo require sub undef unless until use wantarray while BEGIN END break continue do else for if return while and as assert class def del elif except exec finally from global import in is lambda nonlocal not or pass print raise try with yield False True None break continue do else for if return while alias and begin case class def defined elsif end ensure false in module next nil not or redo rescue retry self super then true undef unless until when yield BEGIN END break continue do else for if return while case done elif esac eval fi function in local set then until ", +hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true}),G={};u(la,["default-code"]);u(B([],[[z,/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],[C,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[E,/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup", +"htm","html","mxml","xhtml","xml","xsl"]);u(B([[z,/^[\s]+/,null," \t\r\n"],["atv",/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[E,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i], +["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);u(B([],[["atv",/^[\s\S]+/]]),["uq.val"]);u(x({keywords:"break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try typeof alignof align_union asm axiom bool concept concept_map const_cast constexpr decltype dynamic_cast explicit export friend inline late_check mutable namespace nullptr reinterpret_cast static_assert static_cast template typeid typename using virtual wchar_t where ", +hashComments:true,cStyleComments:true}),["c","cc","cpp","cxx","cyc","m"]);u(x({keywords:"null true false"}),["json"]);u(x({keywords:"break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try typeof abstract boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient as base by checked decimal delegate descending event fixed foreach from group implicit in interface internal into is lock object out override orderby params partial readonly ref sbyte sealed stackalloc string select uint ulong unchecked unsafe ushort var ", +hashComments:true,cStyleComments:true,verbatimStrings:true}),["cs"]);u(x({keywords:"break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try typeof abstract boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient ", +cStyleComments:true}),["java"]);u(x({keywords:"break continue do else for if return while case done elif esac eval fi function in local set then until ",hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);u(x({keywords:"break continue do else for if return while and as assert class def del elif except exec finally from global import in is lambda nonlocal not or pass print raise try with yield False True None ",hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]); +u(x({keywords:"caller delete die do dump elsif eval exit foreach for goto if import last local my next no our print package redo require sub undef unless until use wantarray while BEGIN END ",hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);u(x({keywords:"break continue do else for if return while alias and begin case class def defined elsif end ensure false in module next nil not or redo rescue retry self super then true undef unless until when yield BEGIN END ",hashComments:true, +multiLineStrings:true,regexLiterals:true}),["rb"]);u(x({keywords:"break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try typeof debugger eval export function get null set undefined var with Infinity NaN ",cStyleComments:true,regexLiterals:true}),["js"]);u(B([],[[A,/^[\s\S]+/]]), +["regex"]);window.PR_normalizedHtml=H;window.prettyPrintOne=function(b,f){var i={f:b,e:f};U(i);return i.a};window.prettyPrint=function(b){function f(){for(var t=window.PR_SHOULD_USE_CONTINUATION?j.now()+250:Infinity;q<o.length&&j.now()<t;q++){var p=o[q];if(p.className&&p.className.indexOf("prettyprint")>=0){var c=p.className.match(/\blang-(\w+)\b/);if(c)c=c[1];for(var d=false,a=p.parentNode;a;a=a.parentNode)if((a.tagName==="pre"||a.tagName==="code"||a.tagName==="xmp")&&a.className&&a.className.indexOf("prettyprint")>= +0){d=true;break}if(!d){a=p;if(null===K){d=document.createElement("PRE");d.appendChild(document.createTextNode('<!DOCTYPE foo PUBLIC "foo bar">\n<foo />'));K=!/</.test(d.innerHTML)}if(K){d=a.innerHTML;if("XMP"===a.tagName)d=y(d);else{a=a;if("PRE"===a.tagName)a=true;else if(ka.test(d)){var k="";if(a.currentStyle)k=a.currentStyle.whiteSpace;else if(window.getComputedStyle)k=window.getComputedStyle(a,null).whiteSpace;a=!k||k==="pre"}else a=true;a||(d=d.replace(/(<br\s*\/?>)[\r\n]+/g,"$1").replace(/(?:[\r\n]+[ \t]*)+/g, +" "))}d=d}else{d=[];for(a=a.firstChild;a;a=a.nextSibling)H(a,d);d=d.join("")}d=d.replace(/(?:\r\n?|\n)$/,"");m={f:d,e:c,b:p};U(m);if(p=m.a){c=m.b;if("XMP"===c.tagName){d=document.createElement("PRE");for(a=0;a<c.attributes.length;++a){k=c.attributes[a];if(k.specified)if(k.name.toLowerCase()==="class")d.className=k.value;else d.setAttribute(k.name,k.value)}d.innerHTML=p;c.parentNode.replaceChild(d,c)}else c.innerHTML=p}}}}if(q<o.length)setTimeout(f,250);else b&&b()}for(var i=[document.getElementsByTagName("pre"), +document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],o=[],l=0;l<i.length;++l)for(var n=0,r=i[l].length;n<r;++n)o.push(i[l][n]);i=null;var j=Date;j.now||(j={now:function(){return(new Date).getTime()}});var q=0,m;f()};window.PR={combinePrefixPatterns:O,createSimpleLexer:B,registerLangHandler:u,sourceDecorator:x,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:C,PR_DECLARATION:"dec",PR_KEYWORD:R,PR_LITERAL:J,PR_NOCODE:V,PR_PLAIN:z,PR_PUNCTUATION:E,PR_SOURCE:P,PR_STRING:A, +PR_TAG:"tag",PR_TYPE:S}})()
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/ActivityPanel.html b/src/main/java/com/gitblit/wicket/panels/ActivityPanel.html new file mode 100644 index 00000000..b818e94a --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/ActivityPanel.html @@ -0,0 +1,37 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<body>
+<wicket:panel>
+
+ <div wicket:id="activity" style="padding-bottom:10px;">
+ <div class="header"><i class="icon-refresh" style="vertical-align: middle;"></i> <span style="font-weight:bold;" wicket:id="title">[title]</span></div>
+ <table class="activity">
+ <tr wicket:id="commit">
+ <td class="hidden-phone date" style="width:60px; vertical-align: middle;text-align: right;padding-right:10px;" ><span wicket:id="time">[time of day]</span></td>
+ <td style="width:10em;text-align:left;vertical-align: middle;">
+ <span wicket:id="repository" class="repositorySwatch">[repository link]</span>
+ </td>
+ <td class="hidden-phone hidden-tablet" style="width:30px;vertical-align: middle;"><span wicket:id="avatar" style="vertical-align: middle;"></span></td>
+ <td style="vertical-align: middle;padding-left:15px;">
+ <img class="hidden-phone hidden-tablet" wicket:id="commitIcon" style="vertical-align: top;"></img>
+ <span wicket:id="message">[shortlog commit link]</span><br/>
+ <span wicket:id="author">[author link]</span> <span class="hidden-phone"><wicket:message key="gb.authored"></wicket:message> <span wicket:id="commitid">[commit id]</span></span> on <span wicket:id="branch"></span>
+ </td>
+ <td class="hidden-phone" style="text-align:right;vertical-align: middle;">
+ <div wicket:id="commitRefs">[commit refs]</div>
+ </td>
+ <td class="hidden-phone rightAlign" style="width:7em;vertical-align: middle;">
+ <span class="link">
+ <a wicket:id="diff" target="_blank"><wicket:message key="gb.diff"></wicket:message></a> | <a wicket:id="tree" target="_blank"><wicket:message key="gb.tree"></wicket:message></a>
+ </span>
+ </td>
+ </tr>
+ </table>
+ </div>
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/ActivityPanel.java b/src/main/java/com/gitblit/wicket/panels/ActivityPanel.java new file mode 100644 index 00000000..669c36be --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/ActivityPanel.java @@ -0,0 +1,148 @@ +/*
+ * Copyright 2011 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.Collections;
+import java.util.List;
+
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.Constants;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.Activity;
+import com.gitblit.models.RepositoryCommit;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.CommitDiffPage;
+import com.gitblit.wicket.pages.CommitPage;
+import com.gitblit.wicket.pages.GitSearchPage;
+import com.gitblit.wicket.pages.LogPage;
+import com.gitblit.wicket.pages.SummaryPage;
+import com.gitblit.wicket.pages.TreePage;
+
+/**
+ * Renders activity in day-blocks in reverse-chronological order.
+ *
+ * @author James Moger
+ *
+ */
+public class ActivityPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ public ActivityPanel(String wicketId, List<Activity> recentActivity) {
+ super(wicketId);
+
+ Collections.sort(recentActivity);
+
+ final int shortHashLen = GitBlit.getInteger(Keys.web.shortCommitIdLength, 6);
+ DataView<Activity> activityView = new DataView<Activity>("activity",
+ new ListDataProvider<Activity>(recentActivity)) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<Activity> activityItem) {
+ final Activity entry = activityItem.getModelObject();
+ activityItem.add(WicketUtils.createDatestampLabel("title", entry.startDate, getTimeZone(), getTimeUtils()));
+
+ // display the commits in chronological order
+ DataView<RepositoryCommit> commits = new DataView<RepositoryCommit>("commit",
+ new ListDataProvider<RepositoryCommit>(entry.getCommits())) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<RepositoryCommit> commitItem) {
+ final RepositoryCommit commit = commitItem.getModelObject();
+
+ // commit time of day
+ commitItem.add(WicketUtils.createTimeLabel("time", commit.getCommitterIdent()
+ .getWhen(), getTimeZone(), getTimeUtils()));
+
+ // avatar
+ commitItem.add(new GravatarImage("avatar", commit.getAuthorIdent(), 40));
+
+ // merge icon
+ if (commit.getParentCount() > 1) {
+ commitItem.add(WicketUtils.newImage("commitIcon",
+ "commit_merge_16x16.png"));
+ } else {
+ commitItem.add(WicketUtils.newBlankImage("commitIcon").setVisible(false));
+ }
+
+ // author search link
+ String author = commit.getAuthorIdent().getName();
+ LinkPanel authorLink = new LinkPanel("author", "list", author,
+ GitSearchPage.class, WicketUtils.newSearchParameter(commit.repository,
+ commit.getName(), author, Constants.SearchType.AUTHOR), true);
+ setPersonSearchTooltip(authorLink, author, Constants.SearchType.AUTHOR);
+ commitItem.add(authorLink);
+
+ // repository
+ String repoName = StringUtils.stripDotGit(commit.repository);
+ LinkPanel repositoryLink = new LinkPanel("repository", null,
+ repoName, SummaryPage.class,
+ WicketUtils.newRepositoryParameter(commit.repository), true);
+ WicketUtils.setCssBackground(repositoryLink, repoName);
+ commitItem.add(repositoryLink);
+
+ // repository branch
+ LinkPanel branchLink = new LinkPanel("branch", "list", commit.branch,
+ LogPage.class, WicketUtils.newObjectParameter(commit.repository,
+ commit.branch), true);
+ WicketUtils.setCssStyle(branchLink, "color: #008000;");
+ commitItem.add(branchLink);
+
+ LinkPanel commitid = new LinkPanel("commitid", "list subject",
+ commit.getName().substring(0, shortHashLen), CommitPage.class,
+ WicketUtils.newObjectParameter(commit.repository, commit.getName()), true);
+ commitItem.add(commitid);
+
+ // message/commit link
+ String shortMessage = commit.getShortMessage();
+ String trimmedMessage = shortMessage;
+ if (commit.getRefs() != null && commit.getRefs().size() > 0) {
+ trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG_REFS);
+ } else {
+ trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG);
+ }
+ LinkPanel shortlog = new LinkPanel("message", "list subject",
+ trimmedMessage, CommitPage.class, WicketUtils.newObjectParameter(
+ commit.repository, commit.getName()), true);
+ if (!shortMessage.equals(trimmedMessage)) {
+ WicketUtils.setHtmlTooltip(shortlog, shortMessage);
+ }
+ commitItem.add(shortlog);
+
+ // refs
+ commitItem.add(new RefsPanel("commitRefs", commit.repository, commit
+ .getRefs()));
+
+ // diff, tree links
+ commitItem.add(new BookmarkablePageLink<Void>("diff", CommitDiffPage.class,
+ WicketUtils.newObjectParameter(commit.repository, commit.getName()))
+ .setEnabled(commit.getParentCount() > 0));
+ commitItem.add(new BookmarkablePageLink<Void>("tree", TreePage.class,
+ WicketUtils.newObjectParameter(commit.repository, commit.getName())));
+ }
+ };
+ activityItem.add(commits);
+ }
+ };
+ add(activityView);
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/BasePanel.java b/src/main/java/com/gitblit/wicket/panels/BasePanel.java new file mode 100644 index 00000000..ec879178 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/BasePanel.java @@ -0,0 +1,105 @@ +/*
+ * Copyright 2011 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.ResourceBundle;
+import java.util.TimeZone;
+
+import org.apache.wicket.AttributeModifier;
+import org.apache.wicket.Component;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.Model;
+
+import com.gitblit.Constants;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.utils.TimeUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.WicketUtils;
+
+public abstract class BasePanel extends Panel {
+
+ private static final long serialVersionUID = 1L;
+
+ private transient TimeUtils timeUtils;
+
+ public BasePanel(String wicketId) {
+ super(wicketId);
+ }
+
+ protected TimeZone getTimeZone() {
+ return GitBlit.getBoolean(Keys.web.useClientTimezone, false) ? GitBlitWebSession.get()
+ .getTimezone() : GitBlit.getTimezone();
+ }
+
+ protected TimeUtils getTimeUtils() {
+ if (timeUtils == null) {
+ ResourceBundle bundle;
+ try {
+ bundle = ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp", GitBlitWebSession.get().getLocale());
+ } catch (Throwable t) {
+ bundle = ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp");
+ }
+ timeUtils = new TimeUtils(bundle);
+ }
+ return timeUtils;
+ }
+
+ protected void setPersonSearchTooltip(Component component, String value, Constants.SearchType searchType) {
+ if (searchType.equals(Constants.SearchType.AUTHOR)) {
+ WicketUtils.setHtmlTooltip(component, getString("gb.searchForAuthor") + " " + value);
+ } else if (searchType.equals(Constants.SearchType.COMMITTER)) {
+ WicketUtils.setHtmlTooltip(component, getString("gb.searchForCommitter") + " " + value);
+ }
+ }
+
+ public static class JavascriptEventConfirmation extends AttributeModifier {
+
+ private static final long serialVersionUID = 1L;
+
+ public JavascriptEventConfirmation(String event, String msg) {
+ super(event, true, new Model<String>(msg));
+ }
+
+ protected String newValue(final String currentValue, final String replacementValue) {
+ String prefix = "var conf = confirm('" + replacementValue + "'); "
+ + "if (!conf) return false; ";
+ String result = prefix;
+ if (currentValue != null) {
+ result = prefix + currentValue;
+ }
+ return result;
+ }
+ }
+
+ public static class JavascriptTextPrompt extends AttributeModifier {
+
+ private static final long serialVersionUID = 1L;
+
+ private String initialValue = "";
+
+ public JavascriptTextPrompt(String event, String msg, String value) {
+ super(event, true, new Model<String>(msg));
+ initialValue = value;
+ }
+
+ protected String newValue(final String currentValue, final String message) {
+ String result = "var userText = prompt('" + message + "','"
+ + (initialValue == null ? "" : initialValue) + "'); " + "return userText; ";
+ return result;
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/BranchesPanel.html b/src/main/java/com/gitblit/wicket/panels/BranchesPanel.html new file mode 100644 index 00000000..58c86a45 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/BranchesPanel.html @@ -0,0 +1,52 @@ +<!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>
+
+ <!-- header -->
+ <div class="header"><i class="icon-random" style="vertical-align: middle;"></i> <b><span wicket:id="branches">[branches header]</span></b></div>
+
+ <table class="pretty">
+ <tbody>
+ <tr wicket:id="branch">
+ <td class="date"><span wicket:id="branchDate">[branch date]</span></td>
+ <td><span wicket:id="branchName">[branch name]</span></td>
+ <td class="hidden-phone hidden-tablet author"><span wicket:id="branchAuthor">[branch author]</span></td>
+ <td class="hidden-phone"><span wicket:id="branchLog">[branch log]</span></td>
+ <td class="hidden-phone rightAlign">
+ <span wicket:id="branchLinks"></span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <div wicket:id="allBranches">[all branches]</div>
+
+ <!-- branch page links -->
+ <wicket:fragment wicket:id="branchPageLinks">
+ <span class="link">
+ <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | <a wicket:id="metrics"><wicket:message key="gb.metrics"></wicket:message></a> | <a wicket:id="syndication"><wicket:message key="gb.feed"></wicket:message></a>
+ </span>
+ </wicket:fragment>
+
+ <!-- branch page admin links -->
+ <wicket:fragment wicket:id="branchPageAdminLinks">
+ <span class="link">
+ <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | <a wicket:id="metrics"><wicket:message key="gb.metrics"></wicket:message></a> | <a wicket:id="syndication"><wicket:message key="gb.feed"></wicket:message></a> | <a wicket:id="deleteBranch"><wicket:message key="gb.delete"></wicket:message></a>
+ </span>
+ </wicket:fragment>
+
+ <!-- branch panel links -->
+ <wicket:fragment wicket:id="branchPanelLinks">
+ <span class="link">
+ <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a>
+ </span>
+ </wicket:fragment>
+
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/BranchesPanel.java b/src/main/java/com/gitblit/wicket/panels/BranchesPanel.java new file mode 100644 index 00000000..1262077c --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/BranchesPanel.java @@ -0,0 +1,211 @@ +/*
+ * Copyright 2011 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.Collections;
+import java.util.List;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.link.ExternalLink;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.apache.wicket.model.StringResourceModel;
+import org.eclipse.jgit.lib.Repository;
+
+import com.gitblit.Constants;
+import com.gitblit.GitBlit;
+import com.gitblit.SyndicationServlet;
+import com.gitblit.models.RefModel;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.BranchesPage;
+import com.gitblit.wicket.pages.CommitPage;
+import com.gitblit.wicket.pages.GitSearchPage;
+import com.gitblit.wicket.pages.LogPage;
+import com.gitblit.wicket.pages.MetricsPage;
+import com.gitblit.wicket.pages.TreePage;
+
+public class BranchesPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ private final boolean hasBranches;
+
+ public BranchesPanel(String wicketId, final RepositoryModel model, Repository r,
+ final int maxCount, final boolean showAdmin) {
+ super(wicketId);
+
+ // branches
+ List<RefModel> branches = new ArrayList<RefModel>();
+ UserModel user = GitBlitWebSession.get().getUser();
+ if (user == null) {
+ user = UserModel.ANONYMOUS;
+ }
+
+ List<RefModel> localBranches = JGitUtils.getLocalBranches(r, false, -1);
+ for (RefModel refModel : localBranches) {
+ if (user.canView(model, refModel.reference.getName())) {
+ branches.add(refModel);
+ }
+ }
+ if (model.showRemoteBranches) {
+ List<RefModel> remoteBranches = JGitUtils.getRemoteBranches(r, false, -1);
+ for (RefModel refModel : remoteBranches) {
+ if (user.canView(model, refModel.reference.getName())) {
+ branches.add(refModel);
+ }
+ }
+ }
+ Collections.sort(branches);
+ Collections.reverse(branches);
+ if (maxCount > 0 && branches.size() > maxCount) {
+ branches = new ArrayList<RefModel>(branches.subList(0, maxCount));
+ }
+
+ if (maxCount > 0) {
+ // summary page
+ // show branches page link
+ add(new LinkPanel("branches", "title", new StringResourceModel("gb.branches", this,
+ null), BranchesPage.class, WicketUtils.newRepositoryParameter(model.name)));
+ } else {
+ // branches page
+ add(new Label("branches", new StringResourceModel("gb.branches", this, null)));
+ }
+
+ // only allow delete if we have multiple branches
+ final boolean showDelete = showAdmin && branches.size() > 1;
+
+ ListDataProvider<RefModel> branchesDp = new ListDataProvider<RefModel>(branches);
+ DataView<RefModel> branchesView = new DataView<RefModel>("branch", branchesDp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+
+ public void populateItem(final Item<RefModel> item) {
+ final RefModel entry = item.getModelObject();
+
+ item.add(WicketUtils.createDateLabel("branchDate", entry.getDate(), getTimeZone(), getTimeUtils()));
+
+ item.add(new LinkPanel("branchName", "list name", StringUtils.trimString(
+ entry.displayName, 28), LogPage.class, WicketUtils.newObjectParameter(
+ model.name, entry.getName())));
+
+ String author = entry.getAuthorIdent().getName();
+ LinkPanel authorLink = new LinkPanel("branchAuthor", "list", author,
+ GitSearchPage.class, WicketUtils.newSearchParameter(model.name,
+ entry.getName(), author, Constants.SearchType.AUTHOR));
+ setPersonSearchTooltip(authorLink, author, Constants.SearchType.AUTHOR);
+ item.add(authorLink);
+
+ // short message
+ String shortMessage = entry.getShortMessage();
+ String trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG);
+ LinkPanel shortlog = new LinkPanel("branchLog", "list subject", trimmedMessage,
+ CommitPage.class, WicketUtils.newObjectParameter(model.name,
+ entry.getName()));
+ if (!shortMessage.equals(trimmedMessage)) {
+ WicketUtils.setHtmlTooltip(shortlog, shortMessage);
+ }
+ item.add(shortlog);
+
+ if (maxCount <= 0) {
+ Fragment fragment = new Fragment("branchLinks", showDelete? "branchPageAdminLinks" : "branchPageLinks", this);
+ fragment.add(new BookmarkablePageLink<Void>("log", LogPage.class, WicketUtils
+ .newObjectParameter(model.name, entry.getName())));
+ fragment.add(new BookmarkablePageLink<Void>("tree", TreePage.class, WicketUtils
+ .newObjectParameter(model.name, entry.getName())));
+ fragment.add(new BookmarkablePageLink<Void>("metrics", MetricsPage.class,
+ WicketUtils.newObjectParameter(model.name, entry.getName())));
+ fragment.add(new ExternalLink("syndication", SyndicationServlet.asLink(
+ getRequest().getRelativePathPrefixToContextRoot(), model.name,
+ entry.getName(), 0)));
+ if (showDelete) {
+ fragment.add(createDeleteBranchLink(model, entry));
+ }
+ item.add(fragment);
+ } else {
+ Fragment fragment = new Fragment("branchLinks", "branchPanelLinks", this);
+ fragment.add(new BookmarkablePageLink<Void>("log", LogPage.class, WicketUtils
+ .newObjectParameter(model.name, entry.getName())));
+ fragment.add(new BookmarkablePageLink<Void>("tree", TreePage.class, WicketUtils
+ .newObjectParameter(model.name, entry.getName())));
+ item.add(fragment);
+ }
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(branchesView);
+ if (branches.size() < maxCount || maxCount <= 0) {
+ add(new Label("allBranches", "").setVisible(false));
+ } else {
+ add(new LinkPanel("allBranches", "link", new StringResourceModel("gb.allBranches",
+ this, null), BranchesPage.class, WicketUtils.newRepositoryParameter(model.name)));
+ }
+ // We always have 1 branch
+ hasBranches = (branches.size() > 1)
+ || ((branches.size() == 1) && !branches.get(0).displayName
+ .equalsIgnoreCase("master"));
+ }
+
+ public BranchesPanel hideIfEmpty() {
+ setVisible(hasBranches);
+ return this;
+ }
+
+ private Link<Void> createDeleteBranchLink(final RepositoryModel repositoryModel, final RefModel entry)
+ {
+ Link<Void> deleteLink = new Link<Void>("deleteBranch") {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onClick() {
+ Repository r = GitBlit.self().getRepository(repositoryModel.name);
+ if (r == null) {
+ if (GitBlit.self().isCollectingGarbage(repositoryModel.name)) {
+ error(MessageFormat.format(getString("gb.busyCollectingGarbage"), repositoryModel.name));
+ } else {
+ error(MessageFormat.format("Failed to find repository {0}", repositoryModel.name));
+ }
+ return;
+ }
+ boolean success = JGitUtils.deleteBranchRef(r, entry.getName());
+ r.close();
+ if (success) {
+ info(MessageFormat.format("Branch \"{0}\" deleted", entry.displayName));
+ // redirect to the owning page
+ setResponsePage(getPage().getClass(), WicketUtils.newRepositoryParameter(repositoryModel.name));
+ }
+ else {
+ error(MessageFormat.format("Failed to delete branch \"{0}\"", entry.displayName));
+ }
+ }
+ };
+
+ deleteLink.add(new JavascriptEventConfirmation("onclick", MessageFormat.format(
+ "Delete branch \"{0}\"?", entry.displayName )));
+ return deleteLink;
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/BulletListPanel.html b/src/main/java/com/gitblit/wicket/panels/BulletListPanel.html new file mode 100644 index 00000000..4d28f498 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/BulletListPanel.html @@ -0,0 +1,13 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<wicket:panel>
+ <span class="label" wicket:id="header">already specified</span>
+ <ul wicket:id="list">
+ <li wicket:id="listItem">item</li>
+ </ul>
+</wicket:panel>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/BulletListPanel.java b/src/main/java/com/gitblit/wicket/panels/BulletListPanel.java new file mode 100644 index 00000000..e49223e0 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/BulletListPanel.java @@ -0,0 +1,48 @@ +/*
+ * Copyright 2011 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.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+public class BulletListPanel extends Panel {
+
+ private static final long serialVersionUID = 1L;
+
+ public BulletListPanel(String id, String header, List<String> list) {
+ super(id);
+ if (list == null) {
+ list = new ArrayList<String>();
+ }
+ add(new Label("header", header).setVisible(list.size() > 0));
+ ListDataProvider<String> listDp = new ListDataProvider<String>(list);
+ DataView<String> listView = new DataView<String>("list", listDp) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<String> item) {
+ String entry = item.getModelObject();
+ item.add(new Label("listItem", entry));
+ }
+ };
+ add(listView.setVisible(list.size() > 0));
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/CommitHeaderPanel.html b/src/main/java/com/gitblit/wicket/panels/CommitHeaderPanel.html new file mode 100644 index 00000000..95304403 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/CommitHeaderPanel.html @@ -0,0 +1,24 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<wicket:panel>
+ <div class="commitHeader">
+ <div class="row">
+ <div>
+ <span class="pull-right" wicket:id="authorAvatar"></span>
+ </div>
+ <div class="span9">
+ <div wicket:id="shortmessage">[short message]</div>
+ <div wicket:id="author">[author]</div>
+ <div>
+ <span wicket:id="date">[date]</span>
+ <span class="hidden-phone" style="padding-left:20px;color:#888;" wicket:id="commitid">[commit id]</span>
+ </div>
+ </div>
+ </div>
+ </div>
+</wicket:panel>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/CommitHeaderPanel.java b/src/main/java/com/gitblit/wicket/panels/CommitHeaderPanel.java new file mode 100644 index 00000000..bb960cca --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/CommitHeaderPanel.java @@ -0,0 +1,48 @@ +/*
+ * Copyright 2011 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.eclipse.jgit.revwalk.RevCommit;
+
+import com.gitblit.Constants;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.CommitPage;
+
+public class CommitHeaderPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ public CommitHeaderPanel(String id, String title) {
+ super(id);
+ add(new Label("shortmessage", title));
+ add(new Label("commitid"));
+ add(new Label("author"));
+ add(new Label("date"));
+ }
+
+ public CommitHeaderPanel(String id, String repositoryName, RevCommit c) {
+ super(id);
+ add(new LinkPanel("shortmessage", "title", StringUtils.trimString(c.getShortMessage(),
+ Constants.LEN_SHORTLOG), CommitPage.class,
+ WicketUtils.newObjectParameter(repositoryName, c.getName())));
+ add(new Label("commitid", c.getName()));
+ add(new Label("author", c.getAuthorIdent().getName()));
+ add(WicketUtils.createDateLabel("date", c.getAuthorIdent().getWhen(), getTimeZone(), getTimeUtils()));
+ add(new GravatarImage("authorAvatar", c.getAuthorIdent()));
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/CommitLegendPanel.html b/src/main/java/com/gitblit/wicket/panels/CommitLegendPanel.html new file mode 100644 index 00000000..71063626 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/CommitLegendPanel.html @@ -0,0 +1,13 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<wicket:panel>
+ <div class="commitLegend" wicket:id="legend">
+ <span wicket:id="changeType">[change type]</span>
+ <span wicket:id="description">[description]</span>
+ </div>
+</wicket:panel>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/CommitLegendPanel.java b/src/main/java/com/gitblit/wicket/panels/CommitLegendPanel.java new file mode 100644 index 00000000..1e906ef7 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/CommitLegendPanel.java @@ -0,0 +1,88 @@ +/*
+ * Copyright 2011 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.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.eclipse.jgit.diff.DiffEntry.ChangeType;
+
+import com.gitblit.models.PathModel.PathChangeModel;
+import com.gitblit.wicket.WicketUtils;
+
+public class CommitLegendPanel extends Panel {
+
+ private static final long serialVersionUID = 1L;
+
+ public CommitLegendPanel(String id, List<PathChangeModel> paths) {
+ super(id);
+ final Map<ChangeType, AtomicInteger> stats = getChangedPathsStats(paths);
+ ListDataProvider<ChangeType> legendDp = new ListDataProvider<ChangeType>(
+ new ArrayList<ChangeType>(stats.keySet()));
+ DataView<ChangeType> legendsView = new DataView<ChangeType>("legend", legendDp) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<ChangeType> item) {
+ ChangeType entry = item.getModelObject();
+
+ Label changeType = new Label("changeType", "");
+ WicketUtils.setChangeTypeCssClass(changeType, entry);
+ item.add(changeType);
+ int count = stats.get(entry).intValue();
+ String description = "";
+ switch (entry) {
+ case ADD:
+ description = MessageFormat.format(getString("gb.filesAdded"), count);
+ break;
+ case MODIFY:
+ description = MessageFormat.format(getString("gb.filesModified"), count);
+ break;
+ case DELETE:
+ description = MessageFormat.format(getString("gb.filesDeleted"), count);
+ break;
+ case COPY:
+ description = MessageFormat.format(getString("gb.filesCopied"), count);
+ break;
+ case RENAME:
+ description = MessageFormat.format(getString("gb.filesRenamed"), count);
+ break;
+ }
+ item.add(new Label("description", description));
+ }
+ };
+ add(legendsView);
+ }
+
+ protected Map<ChangeType, AtomicInteger> getChangedPathsStats(List<PathChangeModel> paths) {
+ Map<ChangeType, AtomicInteger> stats = new HashMap<ChangeType, AtomicInteger>();
+ for (PathChangeModel path : paths) {
+ if (!stats.containsKey(path.changeType)) {
+ stats.put(path.changeType, new AtomicInteger(0));
+ }
+ stats.get(path.changeType).incrementAndGet();
+ }
+ return stats;
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/CompressedDownloadsPanel.html b/src/main/java/com/gitblit/wicket/panels/CompressedDownloadsPanel.html new file mode 100644 index 00000000..7123d0a7 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/CompressedDownloadsPanel.html @@ -0,0 +1,12 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<wicket:panel>
+ <span wicket:id="compressedLinks">
+ <span wicket:id="linkSep">|</span><span wicket:id="compressedLink">ref</span>
+ </span>
+</wicket:panel>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/CompressedDownloadsPanel.java b/src/main/java/com/gitblit/wicket/panels/CompressedDownloadsPanel.java new file mode 100644 index 00000000..b22c7587 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/CompressedDownloadsPanel.java @@ -0,0 +1,77 @@ +/*
+ * Copyright 2012 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.Component;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.DownloadZipServlet;
+import com.gitblit.DownloadZipServlet.Format;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+
+public class CompressedDownloadsPanel extends Panel {
+
+ private static final long serialVersionUID = 1L;
+
+ public CompressedDownloadsPanel(String id, final String baseUrl, final String repositoryName, final String objectId, final String path) {
+ super(id);
+
+ List<String> types = GitBlit.getStrings(Keys.web.compressedDownloads);
+ if (types.isEmpty()) {
+ types.add(Format.zip.name());
+ types.add(Format.gz.name());
+ }
+
+ ListDataProvider<String> refsDp = new ListDataProvider<String>(types);
+ DataView<String> refsView = new DataView<String>("compressedLinks", refsDp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+
+ @Override
+ protected void onBeforeRender() {
+ super.onBeforeRender();
+ counter = 0;
+ }
+
+ @Override
+ public void populateItem(final Item<String> item) {
+ String compressionType = item.getModelObject();
+ Format format = Format.fromName(compressionType);
+
+ String href = DownloadZipServlet.asLink(baseUrl, repositoryName,
+ objectId, path, format);
+ Component c = new LinkPanel("compressedLink", null, format.name(), href);
+ item.add(c);
+ Label lb = new Label("linkSep", "|");
+ lb.setVisible(counter > 0);
+ lb.setRenderBodyOnly(true);
+ item.add(lb.setEscapeModelStrings(false));
+ item.setRenderBodyOnly(true);
+ counter++;
+ }
+ };
+ add(refsView);
+
+ setVisible(GitBlit.getBoolean(Keys.web.allowZipDownloads, true));
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/DropDownMenu.html b/src/main/java/com/gitblit/wicket/panels/DropDownMenu.html new file mode 100644 index 00000000..0a8319ec --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/DropDownMenu.html @@ -0,0 +1,13 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<wicket:panel>
+ <a class="dropdown-toggle" href="#" data-toggle="dropdown"><span wicket:id="label">label</span><b class="caret"></b></a>
+ <ul class="dropdown-menu">
+ <li wicket:id="menuItems"><span wicket:id="menuItem">[MenuItem]</span></li>
+ </ul>
+</wicket:panel>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/DropDownMenu.java b/src/main/java/com/gitblit/wicket/panels/DropDownMenu.java new file mode 100644 index 00000000..60a8a3d2 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/DropDownMenu.java @@ -0,0 +1,61 @@ +/*
+ * Copyright 2011 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.panel.Panel;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.wicket.PageRegistration.DropDownMenuItem;
+import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
+import com.gitblit.wicket.WicketUtils;
+
+public class DropDownMenu extends Panel {
+
+ private static final long serialVersionUID = 1L;
+
+ public DropDownMenu(String id, String label, final DropDownMenuRegistration menu) {
+ super(id);
+
+ add(new Label("label", label).setRenderBodyOnly(true));
+ ListDataProvider<DropDownMenuItem> items = new ListDataProvider<DropDownMenuItem>(
+ menu.menuItems);
+ DataView<DropDownMenuItem> view = new DataView<DropDownMenuItem>("menuItems", items) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<DropDownMenuItem> item) {
+ DropDownMenuItem entry = item.getModelObject();
+ if (entry.isDivider()) {
+ item.add(new Label("menuItem").setRenderBodyOnly(true));
+ WicketUtils.setCssClass(item, "divider");
+ } else {
+ String icon = null;
+ if (entry.isSelected()) {
+ icon = "icon-ok";
+ } else {
+ icon = "icon-ok-white";
+ }
+ item.add(new LinkPanel("menuItem", icon, null, entry.toString(), menu.pageClass,
+ entry.getPageParameters(), false).setRenderBodyOnly(true));
+ }
+ }
+ };
+ add(view);
+ setRenderBodyOnly(true);
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/FederationProposalsPanel.html b/src/main/java/com/gitblit/wicket/panels/FederationProposalsPanel.html new file mode 100644 index 00000000..89324d56 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/FederationProposalsPanel.html @@ -0,0 +1,34 @@ +<!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="repositories">
+ <tr>
+ <th class="left">
+ <img style="vertical-align: middle; border: 1px solid #888; background-color: white;" src="federated_16x16.png"/>
+ <wicket:message key="gb.proposals">[proposals]</wicket:message>
+ </th>
+ <th><wicket:message key="gb.received">[received]</wicket:message></th>
+ <th><wicket:message key="gb.type">[type]</wicket:message></th>
+ <th><wicket:message key="gb.token">[token]</wicket:message></th>
+ <th class="right"></th>
+ </tr>
+ <tbody>
+ <tr wicket:id="row">
+ <td class="left"><span class="list" wicket:id="url">[field]</span></td>
+ <td><span class="date"" wicket:id="received">[received]</span></td>
+ <td><span wicket:id="tokenType">[token type]</span></td>
+ <td><span class="sha1"" wicket:id="token">[token]</span></td>
+ <td class="rightAlign"><span class="link"><a wicket:id="deleteProposal"><wicket:message key="gb.delete">[delete]</wicket:message></a></span></td>
+ </tr>
+ </tbody>
+ </table>
+
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/FederationProposalsPanel.java b/src/main/java/com/gitblit/wicket/panels/FederationProposalsPanel.java new file mode 100644 index 00000000..3e70ccec --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/FederationProposalsPanel.java @@ -0,0 +1,92 @@ +/*
+ * Copyright 2011 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.List;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.GitBlit;
+import com.gitblit.models.FederationProposal;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.ReviewProposalPage;
+
+public class FederationProposalsPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ private final boolean hasProposals;
+
+ public FederationProposalsPanel(String wicketId) {
+ super(wicketId);
+
+ final List<FederationProposal> list = GitBlit.self().getPendingFederationProposals();
+ hasProposals = list.size() > 0;
+ DataView<FederationProposal> dataView = new DataView<FederationProposal>("row",
+ new ListDataProvider<FederationProposal>(list)) {
+ private static final long serialVersionUID = 1L;
+ private int counter;
+
+ @Override
+ protected void onBeforeRender() {
+ super.onBeforeRender();
+ counter = 0;
+ }
+
+ public void populateItem(final Item<FederationProposal> item) {
+ final FederationProposal entry = item.getModelObject();
+ item.add(new LinkPanel("url", "list", entry.url, ReviewProposalPage.class,
+ WicketUtils.newTokenParameter(entry.token)));
+ item.add(WicketUtils.createDateLabel("received", entry.received, getTimeZone(), getTimeUtils()));
+ item.add(new Label("tokenType", entry.tokenType.name()));
+ item.add(new LinkPanel("token", "list", entry.token, ReviewProposalPage.class,
+ WicketUtils.newTokenParameter(entry.token)));
+
+ Link<Void> deleteLink = new Link<Void>("deleteProposal") {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onClick() {
+ if (GitBlit.self().deletePendingFederationProposal(entry)) {
+ list.remove(entry);
+ info(MessageFormat.format("Proposal ''{0}'' deleted.", entry.name));
+ } else {
+ error(MessageFormat.format("Failed to delete proposal ''{0}''!",
+ entry.name));
+ }
+ }
+ };
+ deleteLink.add(new JavascriptEventConfirmation("onclick", MessageFormat.format(
+ "Delete proposal \"{0}\"?", entry.name)));
+ item.add(deleteLink);
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(dataView);
+ }
+
+ public Component hideIfEmpty() {
+ return super.setVisible(hasProposals);
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/FederationRegistrationsPanel.html b/src/main/java/com/gitblit/wicket/panels/FederationRegistrationsPanel.html new file mode 100644 index 00000000..fbc6f6cb --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/FederationRegistrationsPanel.html @@ -0,0 +1,38 @@ +<!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="repositories">
+ <tr>
+ <th class="left">
+ <img style="vertical-align: middle; border: 1px solid #888; background-color: white;" src="federated_16x16.png"/>
+ <wicket:message key="gb.registrations">[registrations]</wicket:message>
+ </th>
+ <th><wicket:message key="gb.name">[name]</wicket:message></th>
+ <th><wicket:message key="gb.frequency">[frequency]</wicket:message></th>
+ <th></th>
+ <th><wicket:message key="gb.lastPull">[lastPull]</wicket:message></th>
+ <th><wicket:message key="gb.nextPull">[nextPull]</wicket:message></th>
+ <th class="right"></th>
+ </tr>
+ <tbody>
+ <tr wicket:id="row">
+ <td class="left"><img style="border:0px;vertical-align:middle;" wicket:id="statusIcon" /><span class="list" wicket:id="url">[url]</span></td>
+ <td><span class="list" wicket:id="name">[name]</span></td>
+ <td><span wicket:id="frequency">[frequency]</span></td>
+ <td><img style="border:0px;vertical-align:middle;" wicket:id="typeIcon" /></td>
+ <td><span class="date"" wicket:id="lastPull">[lastPull]</span></td>
+ <td><span class="date"" wicket:id="nextPull">[nextPull]</span></td>
+ <td class="rightAlign"><span class="link"></span></td>
+ </tr>
+ </tbody>
+ </table>
+
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/FederationRegistrationsPanel.java b/src/main/java/com/gitblit/wicket/panels/FederationRegistrationsPanel.java new file mode 100644 index 00000000..ff947175 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/FederationRegistrationsPanel.java @@ -0,0 +1,83 @@ +/*
+ * Copyright 2011 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.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.GitBlit;
+import com.gitblit.models.FederationModel;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.FederationRegistrationPage;
+
+public class FederationRegistrationsPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ private final boolean hasRegistrations;
+
+ public FederationRegistrationsPanel(String wicketId) {
+ super(wicketId);
+
+ final List<FederationModel> list = new ArrayList<FederationModel>(GitBlit.self()
+ .getFederationRegistrations());
+ list.addAll(GitBlit.self().getFederationResultRegistrations());
+ Collections.sort(list);
+ hasRegistrations = list.size() > 0;
+ DataView<FederationModel> dataView = new DataView<FederationModel>("row",
+ new ListDataProvider<FederationModel>(list)) {
+ private static final long serialVersionUID = 1L;
+ private int counter;
+
+ @Override
+ protected void onBeforeRender() {
+ super.onBeforeRender();
+ counter = 0;
+ }
+
+ public void populateItem(final Item<FederationModel> item) {
+ final FederationModel entry = item.getModelObject();
+ item.add(new LinkPanel("url", "list", entry.url, FederationRegistrationPage.class,
+ WicketUtils.newRegistrationParameter(entry.url, entry.name)));
+ item.add(WicketUtils.getPullStatusImage("statusIcon", entry.getLowestStatus()));
+ item.add(new LinkPanel("name", "list", entry.name,
+ FederationRegistrationPage.class, WicketUtils.newRegistrationParameter(
+ entry.url, entry.name)));
+
+ item.add(WicketUtils.getRegistrationImage("typeIcon", entry, this));
+
+ item.add(WicketUtils.createDateLabel("lastPull", entry.lastPull, getTimeZone(), getTimeUtils()));
+ item.add(WicketUtils
+ .createTimestampLabel("nextPull", entry.nextPull, getTimeZone(), getTimeUtils()));
+ item.add(new Label("frequency", entry.frequency));
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(dataView);
+ }
+
+ public Component hideIfEmpty() {
+ return super.setVisible(hasRegistrations);
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/FederationTokensPanel.html b/src/main/java/com/gitblit/wicket/panels/FederationTokensPanel.html new file mode 100644 index 00000000..dc5307bb --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/FederationTokensPanel.html @@ -0,0 +1,35 @@ +<!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 class="admin_nav">
+ <a wicket:id="federatedUsers"><wicket:message key="gb.federatedUserDefinitions">[users]</wicket:message></a>
+ | <a wicket:id="federatedSettings"><wicket:message key="gb.federatedSettingDefinitions">[settings]</wicket:message></a>
+ </div>
+
+ <table class="repositories">
+ <tr>
+ <th class="left">
+ <img style="vertical-align: middle; border: 1px solid #888; background-color: white;" src="federated_16x16.png"/>
+ <wicket:message key="gb.tokens">[tokens]</wicket:message>
+ </th>
+ <th></th>
+ <th class="right"></th>
+ </tr>
+ <tbody>
+ <tr wicket:id="row">
+ <td class="left"><span wicket:id="description"></span></td>
+ <td><span class="sha1"" wicket:id="value">[value]</span></td>
+ <td class="rightAlign"><span class="link"><a wicket:id="repositoryDefinitions"><wicket:message key="gb.federatedRepositoryDefinitions">[repository definitions]</wicket:message></a> | <a wicket:id="send"><wicket:message key="gb.sendProposal">[send proposal]</wicket:message></a></span></td>
+ </tr>
+ </tbody>
+ </table>
+
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/FederationTokensPanel.java b/src/main/java/com/gitblit/wicket/panels/FederationTokensPanel.java new file mode 100644 index 00000000..3454492f --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/FederationTokensPanel.java @@ -0,0 +1,110 @@ +/*
+ * Copyright 2011 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.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.link.ExternalLink;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.Constants.FederationRequest;
+import com.gitblit.Constants.FederationToken;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.utils.FederationUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.SendProposalPage;
+
+public class FederationTokensPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ public FederationTokensPanel(String wicketId, final boolean showFederation) {
+ super(wicketId);
+
+ final String baseUrl = WicketUtils.getGitblitURL(getRequest());
+ add(new ExternalLink("federatedUsers", FederationUtils.asLink(baseUrl, GitBlit.self()
+ .getFederationToken(FederationToken.USERS_AND_REPOSITORIES),
+ FederationRequest.PULL_USERS)));
+
+ add(new ExternalLink("federatedSettings", FederationUtils.asLink(baseUrl, GitBlit
+ .self().getFederationToken(FederationToken.ALL), FederationRequest.PULL_SETTINGS)));
+
+ final List<String[]> data = new ArrayList<String[]>();
+ for (FederationToken token : FederationToken.values()) {
+ data.add(new String[] { token.name(), GitBlit.self().getFederationToken(token), null });
+ }
+ List<String> sets = GitBlit.getStrings(Keys.federation.sets);
+ Collections.sort(sets);
+ for (String set : sets) {
+ data.add(new String[] { FederationToken.REPOSITORIES.name(),
+ GitBlit.self().getFederationToken(set), set });
+ }
+
+ DataView<String[]> dataView = new DataView<String[]>("row", new ListDataProvider<String[]>(
+ data)) {
+ private static final long serialVersionUID = 1L;
+ private int counter;
+
+ @Override
+ protected void onBeforeRender() {
+ super.onBeforeRender();
+ counter = 0;
+ }
+
+ public void populateItem(final Item<String[]> item) {
+ final String[] entry = item.getModelObject();
+ final FederationToken token = FederationToken.fromName(entry[0]);
+ if (entry[2] == null) {
+ // standard federation token
+ item.add(new Label("description", describeToken(token)));
+ } else {
+ // federation set token
+ item.add(new Label("description", entry[2]));
+ }
+ item.add(new Label("value", entry[1]));
+
+ item.add(new ExternalLink("repositoryDefinitions", FederationUtils.asLink(
+ baseUrl, entry[1], FederationRequest.PULL_REPOSITORIES)));
+
+ item.add(new BookmarkablePageLink<Void>("send",
+ SendProposalPage.class, WicketUtils.newTokenParameter(entry[1])));
+
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(dataView.setVisible(showFederation));
+ }
+
+ private String describeToken(FederationToken token) {
+ switch (token) {
+ case ALL:
+ return getString("gb.tokenAllDescription");
+ case USERS_AND_REPOSITORIES:
+ return getString("gb.tokenUnrDescription");
+ case REPOSITORIES:
+ default:
+ return getString("gb.tokenJurDescription");
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/GravatarImage.html b/src/main/java/com/gitblit/wicket/panels/GravatarImage.html new file mode 100644 index 00000000..9dda7958 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/GravatarImage.html @@ -0,0 +1,9 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+<wicket:panel>
+<a href="#" wicket:id="link"><img wicket:id="image"></img></a>
+</wicket:panel>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/GravatarImage.java b/src/main/java/com/gitblit/wicket/panels/GravatarImage.java new file mode 100644 index 00000000..7f1874f2 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/GravatarImage.java @@ -0,0 +1,73 @@ +/*
+ * Copyright 2011 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.wicket.panels;
+
+import java.text.MessageFormat;
+
+import org.apache.wicket.behavior.SimpleAttributeModifier;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.eclipse.jgit.lib.PersonIdent;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.utils.ActivityUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.ExternalImage;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.GravatarProfilePage;
+
+/**
+ * Represents a Gravatar image and links to the Gravatar profile page.
+ *
+ * @author James Moger
+ *
+ */
+public class GravatarImage extends Panel {
+
+ private static final long serialVersionUID = 1L;
+
+ public GravatarImage(String id, PersonIdent person) {
+ this(id, person, 0);
+ }
+
+ public GravatarImage(String id, PersonIdent person, int width) {
+ this(id, person, width, true);
+ }
+
+ public GravatarImage(String id, PersonIdent person, int width, boolean linked) {
+ super(id);
+
+ String email = person.getEmailAddress() == null ? person.getName().toLowerCase() : person.getEmailAddress().toLowerCase();
+ String hash = StringUtils.getMD5(email);
+ Link<Void> link = new BookmarkablePageLink<Void>("link", GravatarProfilePage.class,
+ WicketUtils.newObjectParameter(hash));
+ link.add(new SimpleAttributeModifier("target", "_blank"));
+ String url = ActivityUtils.getGravatarThumbnailUrl(email, width);
+ ExternalImage image = new ExternalImage("image", url);
+ WicketUtils.setCssClass(image, "gravatar");
+ link.add(image);
+ if (linked) {
+ WicketUtils.setHtmlTooltip(link,
+ MessageFormat.format("View Gravatar profile for {0}", person.getName()));
+ } else {
+ WicketUtils.setHtmlTooltip(link, person.getName());
+ }
+ add(link.setEnabled(linked));
+ setVisible(GitBlit.getBoolean(Keys.web.allowGravatar, true));
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/HistoryPanel.html b/src/main/java/com/gitblit/wicket/panels/HistoryPanel.html new file mode 100644 index 00000000..811eeed1 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/HistoryPanel.html @@ -0,0 +1,48 @@ +<!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>
+
+ <!-- commit header -->
+ <div wicket:id="commitHeader">[commit header]</div>
+
+ <!-- breadcrumbs -->
+ <div wicket:id="breadcrumbs">[breadcrumbs]</div>
+
+ <table class="pretty">
+ <tbody>
+ <tr wicket:id="commit">
+ <td class="date"><span wicket:id="commitDate">[commit date]</span></td>
+ <td class="icon"><img wicket:id="commitIcon" /></td>
+ <td class="hidden-phone author"><span wicket:id="commitAuthor">[commit author]</span></td>
+ <td class="message"><table class="nestedTable"><tr><td><span style="vertical-align:middle;" wicket:id="commitShortMessage">[commit short message]</span></td><td><div style="text-align:right;" wicket:id="commitRefs">[commit refs]</div></td></tr></table></td>
+ <td class="hidden-phone hidden-tablet rightAlign"><span class="link" wicket:id="hashLabel">[hash label]</span><span wicket:id="hashLink">[hash link]</span></td>
+ <td class="hidden-phone rightAlign">
+ <span wicket:id="historyLinks">[history links]</span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <div wicket:id="moreHistory">[more...]</div>
+
+ <!-- tree links -->
+ <wicket:fragment wicket:id="treeLinks">
+ <span class="link">
+ <a wicket:id="commitdiff"><wicket:message key="gb.commitdiff"></wicket:message></a>
+ </span>
+ </wicket:fragment>
+
+ <!-- blob links -->
+ <wicket:fragment wicket:id="blobLinks">
+ <span class="link">
+ <a wicket:id="commitdiff"><wicket:message key="gb.commitdiff"></wicket:message></a> | <a wicket:id="difftocurrent"><wicket:message key="gb.difftocurrent"></wicket:message></a>
+ </span>
+ </wicket:fragment>
+
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java b/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java new file mode 100644 index 00000000..e5878635 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java @@ -0,0 +1,335 @@ +/*
+ * Copyright 2011 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.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.apache.wicket.model.StringResourceModel;
+import org.eclipse.jgit.diff.DiffEntry.ChangeType;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+
+import com.gitblit.Constants;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.PathModel;
+import com.gitblit.models.SubmoduleModel;
+import com.gitblit.models.PathModel.PathChangeModel;
+import com.gitblit.models.RefModel;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.BlobDiffPage;
+import com.gitblit.wicket.pages.BlobPage;
+import com.gitblit.wicket.pages.CommitDiffPage;
+import com.gitblit.wicket.pages.CommitPage;
+import com.gitblit.wicket.pages.GitSearchPage;
+import com.gitblit.wicket.pages.HistoryPage;
+import com.gitblit.wicket.pages.TreePage;
+
+public class HistoryPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ private boolean hasMore;
+
+ public HistoryPanel(String wicketId, final String repositoryName, final String objectId,
+ final String path, Repository r, int limit, int pageOffset, boolean showRemoteRefs) {
+ super(wicketId);
+ boolean pageResults = limit <= 0;
+ int itemsPerPage = GitBlit.getInteger(Keys.web.itemsPerPage, 50);
+ if (itemsPerPage <= 1) {
+ itemsPerPage = 50;
+ }
+
+ RevCommit commit = JGitUtils.getCommit(r, objectId);
+ List<PathChangeModel> paths = JGitUtils.getFilesInCommit(r, commit);
+
+ Map<String, SubmoduleModel> submodules = new HashMap<String, SubmoduleModel>();
+ for (SubmoduleModel model : JGitUtils.getSubmodules(r, commit.getTree())) {
+ submodules.put(model.path, model);
+ }
+
+ PathModel matchingPath = null;
+ for (PathModel p : paths) {
+ if (p.path.equals(path)) {
+ matchingPath = p;
+ break;
+ }
+ }
+ if (matchingPath == null) {
+ // path not in commit
+ // manually locate path in tree
+ TreeWalk tw = new TreeWalk(r);
+ tw.reset();
+ tw.setRecursive(true);
+ try {
+ tw.addTree(commit.getTree());
+ tw.setFilter(PathFilterGroup.createFromStrings(Collections.singleton(path)));
+ while (tw.next()) {
+ if (tw.getPathString().equals(path)) {
+ matchingPath = new PathChangeModel(tw.getPathString(), tw.getPathString(), 0, tw
+ .getRawMode(0), tw.getObjectId(0).getName(), commit.getId().getName(),
+ ChangeType.MODIFY);
+ }
+ }
+ } catch (Exception e) {
+ } finally {
+ tw.release();
+ }
+ }
+
+ final boolean isTree = matchingPath == null ? true : matchingPath.isTree();
+ final boolean isSubmodule = matchingPath == null ? true : matchingPath.isSubmodule();
+
+ // submodule
+ SubmoduleModel submodule = getSubmodule(submodules, repositoryName, matchingPath.path);
+ final String submodulePath;
+ final boolean hasSubmodule;
+ if (submodule != null) {
+ submodulePath = submodule.gitblitPath;
+ hasSubmodule = submodule.hasSubmodule;
+ } else {
+ submodulePath = "";
+ hasSubmodule = false;
+ }
+
+ final Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(r, showRemoteRefs);
+ List<RevCommit> commits;
+ if (pageResults) {
+ // Paging result set
+ commits = JGitUtils.getRevLog(r, objectId, path, pageOffset * itemsPerPage,
+ itemsPerPage);
+ } else {
+ // Fixed size result set
+ commits = JGitUtils.getRevLog(r, objectId, path, 0, limit);
+ }
+
+ // inaccurate way to determine if there are more commits.
+ // works unless commits.size() represents the exact end.
+ hasMore = commits.size() >= itemsPerPage;
+
+ add(new CommitHeaderPanel("commitHeader", repositoryName, commit));
+
+ // breadcrumbs
+ add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, path, objectId));
+
+ final int hashLen = GitBlit.getInteger(Keys.web.shortCommitIdLength, 6);
+ ListDataProvider<RevCommit> dp = new ListDataProvider<RevCommit>(commits);
+ DataView<RevCommit> logView = new DataView<RevCommit>("commit", dp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+
+ public void populateItem(final Item<RevCommit> item) {
+ final RevCommit entry = item.getModelObject();
+ final Date date = JGitUtils.getCommitDate(entry);
+
+ item.add(WicketUtils.createDateLabel("commitDate", date, getTimeZone(), getTimeUtils()));
+
+ // author search link
+ String author = entry.getAuthorIdent().getName();
+ LinkPanel authorLink = new LinkPanel("commitAuthor", "list", author,
+ GitSearchPage.class,
+ WicketUtils.newSearchParameter(repositoryName, objectId,
+ author, Constants.SearchType.AUTHOR));
+ setPersonSearchTooltip(authorLink, author, Constants.SearchType.AUTHOR);
+ item.add(authorLink);
+
+ // merge icon
+ if (entry.getParentCount() > 1) {
+ item.add(WicketUtils.newImage("commitIcon", "commit_merge_16x16.png"));
+ } else {
+ item.add(WicketUtils.newBlankImage("commitIcon"));
+ }
+
+ String shortMessage = entry.getShortMessage();
+ String trimmedMessage = shortMessage;
+ if (allRefs.containsKey(entry.getId())) {
+ trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG_REFS);
+ } else {
+ trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG);
+ }
+ LinkPanel shortlog = new LinkPanel("commitShortMessage", "list subject",
+ trimmedMessage, CommitPage.class, WicketUtils.newObjectParameter(
+ repositoryName, entry.getName()));
+ if (!shortMessage.equals(trimmedMessage)) {
+ WicketUtils.setHtmlTooltip(shortlog, shortMessage);
+ }
+ item.add(shortlog);
+
+ item.add(new RefsPanel("commitRefs", repositoryName, entry, allRefs));
+
+ if (isTree) {
+ // tree
+ item.add(new Label("hashLabel", getString("gb.tree") + "@"));
+ LinkPanel commitHash = new LinkPanel("hashLink", null, entry.getName().substring(0, hashLen),
+ TreePage.class, WicketUtils.newObjectParameter(
+ repositoryName, entry.getName()));
+ WicketUtils.setCssClass(commitHash, "shortsha1");
+ WicketUtils.setHtmlTooltip(commitHash, entry.getName());
+ item.add(commitHash);
+
+ Fragment links = new Fragment("historyLinks", "treeLinks", this);
+ links.add(new BookmarkablePageLink<Void>("commitdiff", CommitDiffPage.class,
+ WicketUtils.newObjectParameter(repositoryName, entry.getName())));
+ item.add(links);
+ } else if (isSubmodule) {
+ // submodule
+ item.add(new Label("hashLabel", submodulePath + "@"));
+ Repository repository = GitBlit.self().getRepository(repositoryName);
+ String submoduleId = JGitUtils.getSubmoduleCommitId(repository, path, entry);
+ repository.close();
+ LinkPanel commitHash = new LinkPanel("hashLink", null, submoduleId.substring(0, hashLen),
+ TreePage.class, WicketUtils.newObjectParameter(
+ submodulePath, submoduleId));
+ WicketUtils.setCssClass(commitHash, "shortsha1");
+ WicketUtils.setHtmlTooltip(commitHash, submoduleId);
+ item.add(commitHash.setEnabled(hasSubmodule));
+
+ Fragment links = new Fragment("historyLinks", "treeLinks", this);
+ links.add(new BookmarkablePageLink<Void>("commitdiff", CommitDiffPage.class,
+ WicketUtils.newObjectParameter(repositoryName, entry.getName())));
+ item.add(links);
+ } else {
+ // commit
+ item.add(new Label("hashLabel", getString("gb.blob") + "@"));
+ LinkPanel commitHash = new LinkPanel("hashLink", null, entry.getName().substring(0, hashLen),
+ BlobPage.class, WicketUtils.newPathParameter(
+ repositoryName, entry.getName(), path));
+ WicketUtils.setCssClass(commitHash, "sha1");
+ WicketUtils.setHtmlTooltip(commitHash, entry.getName());
+ item.add(commitHash);
+
+ Fragment links = new Fragment("historyLinks", "blobLinks", this);
+ links.add(new BookmarkablePageLink<Void>("commitdiff", CommitDiffPage.class,
+ WicketUtils.newObjectParameter(repositoryName, entry.getName())));
+ links.add(new BookmarkablePageLink<Void>("difftocurrent", BlobDiffPage.class,
+ WicketUtils.newBlobDiffParameter(repositoryName, entry.getName(),
+ objectId, path)).setEnabled(counter > 0));
+ item.add(links);
+ }
+
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(logView);
+
+ // determine to show pager, more, or neither
+ if (limit <= 0) {
+ // no display limit
+ add(new Label("moreHistory", "").setVisible(false));
+ } else {
+ if (pageResults) {
+ // paging
+ add(new Label("moreHistory", "").setVisible(false));
+ } else {
+ // more
+ if (commits.size() == limit) {
+ // show more
+ add(new LinkPanel("moreHistory", "link", new StringResourceModel(
+ "gb.moreHistory", this, null), HistoryPage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, path)));
+ } else {
+ // no more
+ add(new Label("moreHistory", "").setVisible(false));
+ }
+ }
+ }
+ }
+
+ public boolean hasMore() {
+ return hasMore;
+ }
+
+ protected SubmoduleModel getSubmodule(Map<String, SubmoduleModel> submodules, String repositoryName, String path) {
+ SubmoduleModel model = submodules.get(path);
+ if (model == null) {
+ // undefined submodule?!
+ model = new SubmoduleModel(path.substring(path.lastIndexOf('/') + 1), path, path);
+ model.hasSubmodule = false;
+ model.gitblitPath = model.name;
+ return model;
+ } else {
+ // extract the repository name from the clone url
+ List<String> patterns = GitBlit.getStrings(Keys.git.submoduleUrlPatterns);
+ String submoduleName = StringUtils.extractRepositoryPath(model.url, patterns.toArray(new String[0]));
+
+ // determine the current path for constructing paths relative
+ // to the current repository
+ String currentPath = "";
+ if (repositoryName.indexOf('/') > -1) {
+ currentPath = repositoryName.substring(0, repositoryName.lastIndexOf('/') + 1);
+ }
+
+ // try to locate the submodule repository
+ // prefer bare to non-bare names
+ List<String> candidates = new ArrayList<String>();
+
+ // relative
+ candidates.add(currentPath + StringUtils.stripDotGit(submoduleName));
+ candidates.add(candidates.get(candidates.size() - 1) + ".git");
+
+ // relative, no subfolder
+ if (submoduleName.lastIndexOf('/') > -1) {
+ String name = submoduleName.substring(submoduleName.lastIndexOf('/') + 1);
+ candidates.add(currentPath + StringUtils.stripDotGit(name));
+ candidates.add(currentPath + candidates.get(candidates.size() - 1) + ".git");
+ }
+
+ // absolute
+ candidates.add(StringUtils.stripDotGit(submoduleName));
+ candidates.add(candidates.get(candidates.size() - 1) + ".git");
+
+ // absolute, no subfolder
+ if (submoduleName.lastIndexOf('/') > -1) {
+ String name = submoduleName.substring(submoduleName.lastIndexOf('/') + 1);
+ candidates.add(StringUtils.stripDotGit(name));
+ candidates.add(candidates.get(candidates.size() - 1) + ".git");
+ }
+
+ // create a unique, ordered set of candidate paths
+ Set<String> paths = new LinkedHashSet<String>(candidates);
+ for (String candidate : paths) {
+ if (GitBlit.self().hasRepository(candidate)) {
+ model.hasSubmodule = true;
+ model.gitblitPath = candidate;
+ return model;
+ }
+ }
+
+ // we do not have a copy of the submodule, but we need a path
+ model.gitblitPath = candidates.get(0);
+ return model;
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/LinkPanel.html b/src/main/java/com/gitblit/wicket/panels/LinkPanel.html new file mode 100644 index 00000000..714d53ab --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/LinkPanel.html @@ -0,0 +1,9 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+<wicket:panel>
+<a href="#" wicket:id="link"><i wicket:id="icon" style="padding-right:5px;"></i><span wicket:id="label">[link]</span></a>
+</wicket:panel>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/LinkPanel.java b/src/main/java/com/gitblit/wicket/panels/LinkPanel.java new file mode 100644 index 00000000..688a9576 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/LinkPanel.java @@ -0,0 +1,110 @@ +/*
+ * Copyright 2011 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.PageParameters;
+import org.apache.wicket.behavior.SimpleAttributeModifier;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.link.ExternalLink;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+
+public class LinkPanel extends Panel {
+
+ private static final long serialVersionUID = 1L;
+
+ private final IModel<String> labelModel;
+
+ public LinkPanel(String wicketId, String linkCssClass, String label,
+ Class<? extends WebPage> clazz) {
+ this(wicketId, null, linkCssClass, new Model<String>(label), clazz, null, false);
+ }
+
+ public LinkPanel(String wicketId, String linkCssClass, String label,
+ Class<? extends WebPage> clazz, PageParameters parameters) {
+ this(wicketId, null, linkCssClass, new Model<String>(label), clazz, parameters, false);
+ }
+
+ public LinkPanel(String wicketId, String linkCssClass, String label,
+ Class<? extends WebPage> clazz, PageParameters parameters, boolean newWindow) {
+ this(wicketId, null, linkCssClass, new Model<String>(label), clazz, parameters, newWindow);
+ }
+
+ public LinkPanel(String wicketId, String bootstrapIcon, String linkCssClass, String label,
+ Class<? extends WebPage> clazz, PageParameters parameters, boolean newWindow) {
+ this(wicketId, bootstrapIcon, linkCssClass, new Model<String>(label), clazz, parameters, newWindow);
+ }
+
+ public LinkPanel(String wicketId, String linkCssClass, IModel<String> model,
+ Class<? extends WebPage> clazz, PageParameters parameters) {
+ this(wicketId, null, linkCssClass, model, clazz, parameters, false);
+ }
+
+ public LinkPanel(String wicketId, String bootstrapIcon, String linkCssClass, IModel<String> model,
+ Class<? extends WebPage> clazz, PageParameters parameters, boolean newWindow) {
+ super(wicketId);
+ this.labelModel = model;
+ Link<Void> link = null;
+ if (parameters == null) {
+ link = new BookmarkablePageLink<Void>("link", clazz);
+ } else {
+ link = new BookmarkablePageLink<Void>("link", clazz, parameters);
+ }
+ if (newWindow) {
+ link.add(new SimpleAttributeModifier("target", "_blank"));
+ }
+ if (linkCssClass != null) {
+ link.add(new SimpleAttributeModifier("class", linkCssClass));
+ }
+ Label icon = new Label("icon");
+ if (StringUtils.isEmpty(bootstrapIcon)) {
+ link.add(icon.setVisible(false));
+ } else {
+ WicketUtils.setCssClass(icon, bootstrapIcon);
+ link.add(icon);
+ }
+ link.add(new Label("label", labelModel).setRenderBodyOnly(true));
+ add(link);
+ }
+
+ public LinkPanel(String wicketId, String linkCssClass, String label, String href) {
+ this(wicketId, linkCssClass, label, href, false);
+ }
+
+ public LinkPanel(String wicketId, String linkCssClass, String label, String href,
+ boolean newWindow) {
+ super(wicketId);
+ this.labelModel = new Model<String>(label);
+ ExternalLink link = new ExternalLink("link", href);
+ if (newWindow) {
+ link.add(new SimpleAttributeModifier("target", "_blank"));
+ }
+ if (linkCssClass != null) {
+ link.add(new SimpleAttributeModifier("class", linkCssClass));
+ }
+ link.add(new Label("icon").setVisible(false));
+ link.add(new Label("label", labelModel));
+ add(link);
+ }
+
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/LogPanel.html b/src/main/java/com/gitblit/wicket/panels/LogPanel.html new file mode 100644 index 00000000..2b2605ac --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/LogPanel.html @@ -0,0 +1,32 @@ +<!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>
+
+ <!-- header -->
+ <div class="header"><i class="icon-refresh" style="vertical-align: middle;"></i> <b><span wicket:id="header">[log header]</span></b></div>
+ <table class="pretty">
+ <tbody>
+ <tr wicket:id="commit">
+ <td class="date" style="width:6em;"><span wicket:id="commitDate">[commit date]</span></td>
+ <td class="hidden-phone author"><span wicket:id="commitAuthor">[commit author]</span></td>
+ <td class="hidden-phone icon"><img wicket:id="commitIcon" /></td>
+ <td class="message"><table class="nestedTable"><tr><td><span style="vertical-align:middle;" wicket:id="commitShortMessage">[commit short message]</span></td><td><div style="text-align:right;" wicket:id="commitRefs">[commit refs]</div></td></tr></table></td>
+ <td class="hidden-phone hidden-tablet rightAlign"><span wicket:id="hashLink">[hash link]</span></td>
+ <td class="hidden-phone hidden-tablet rightAlign">
+ <span class="link">
+ <a wicket:id="diff"><wicket:message key="gb.diff"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a>
+ </span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <div wicket:id="moreLogs">[more...]</div>
+
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/LogPanel.java b/src/main/java/com/gitblit/wicket/panels/LogPanel.java new file mode 100644 index 00000000..05397642 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/LogPanel.java @@ -0,0 +1,176 @@ +/*
+ * Copyright 2011 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.Date;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.apache.wicket.model.StringResourceModel;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import com.gitblit.Constants;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.RefModel;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.CommitDiffPage;
+import com.gitblit.wicket.pages.CommitPage;
+import com.gitblit.wicket.pages.LogPage;
+import com.gitblit.wicket.pages.GitSearchPage;
+import com.gitblit.wicket.pages.TreePage;
+
+public class LogPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ private boolean hasMore;
+
+ public LogPanel(String wicketId, final String repositoryName, final String objectId,
+ Repository r, int limit, int pageOffset, boolean showRemoteRefs) {
+ super(wicketId);
+ boolean pageResults = limit <= 0;
+ int itemsPerPage = GitBlit.getInteger(Keys.web.itemsPerPage, 50);
+ if (itemsPerPage <= 1) {
+ itemsPerPage = 50;
+ }
+
+ final Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(r, showRemoteRefs);
+ List<RevCommit> commits;
+ if (pageResults) {
+ // Paging result set
+ commits = JGitUtils.getRevLog(r, objectId, pageOffset * itemsPerPage, itemsPerPage);
+ } else {
+ // Fixed size result set
+ commits = JGitUtils.getRevLog(r, objectId, 0, limit);
+ }
+
+ // inaccurate way to determine if there are more commits.
+ // works unless commits.size() represents the exact end.
+ hasMore = commits.size() >= itemsPerPage;
+
+ // header
+ if (pageResults) {
+ // shortlog page
+ add(new Label("header", objectId));
+ } else {
+ // summary page
+ // show shortlog page link
+ add(new LinkPanel("header", "title", objectId, LogPage.class,
+ WicketUtils.newRepositoryParameter(repositoryName)));
+ }
+
+ final int hashLen = GitBlit.getInteger(Keys.web.shortCommitIdLength, 6);
+ ListDataProvider<RevCommit> dp = new ListDataProvider<RevCommit>(commits);
+ DataView<RevCommit> logView = new DataView<RevCommit>("commit", dp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+
+ public void populateItem(final Item<RevCommit> item) {
+ final RevCommit entry = item.getModelObject();
+ final Date date = JGitUtils.getCommitDate(entry);
+
+ item.add(WicketUtils.createDateLabel("commitDate", date, getTimeZone(), getTimeUtils()));
+
+ // author search link
+ String author = entry.getAuthorIdent().getName();
+ LinkPanel authorLink = new LinkPanel("commitAuthor", "list", author,
+ GitSearchPage.class, WicketUtils.newSearchParameter(repositoryName,
+ objectId, author, Constants.SearchType.AUTHOR));
+ setPersonSearchTooltip(authorLink, author, Constants.SearchType.AUTHOR);
+ item.add(authorLink);
+
+ // merge icon
+ if (entry.getParentCount() > 1) {
+ item.add(WicketUtils.newImage("commitIcon", "commit_merge_16x16.png"));
+ } else {
+ item.add(WicketUtils.newBlankImage("commitIcon"));
+ }
+
+ // short message
+ String shortMessage = entry.getShortMessage();
+ String trimmedMessage = shortMessage;
+ if (allRefs.containsKey(entry.getId())) {
+ trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG_REFS);
+ } else {
+ trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG);
+ }
+ LinkPanel shortlog = new LinkPanel("commitShortMessage", "list subject",
+ trimmedMessage, CommitPage.class, WicketUtils.newObjectParameter(
+ repositoryName, entry.getName()));
+ if (!shortMessage.equals(trimmedMessage)) {
+ WicketUtils.setHtmlTooltip(shortlog, shortMessage);
+ }
+ item.add(shortlog);
+
+ item.add(new RefsPanel("commitRefs", repositoryName, entry, allRefs));
+
+ // commit hash link
+ LinkPanel commitHash = new LinkPanel("hashLink", null, entry.getName().substring(0, hashLen),
+ CommitPage.class, WicketUtils.newObjectParameter(
+ repositoryName, entry.getName()));
+ WicketUtils.setCssClass(commitHash, "shortsha1");
+ WicketUtils.setHtmlTooltip(commitHash, entry.getName());
+ item.add(commitHash);
+
+ item.add(new BookmarkablePageLink<Void>("diff", CommitDiffPage.class, WicketUtils
+ .newObjectParameter(repositoryName, entry.getName())).setEnabled(entry
+ .getParentCount() > 0));
+ item.add(new BookmarkablePageLink<Void>("tree", TreePage.class, WicketUtils
+ .newObjectParameter(repositoryName, entry.getName())));
+
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(logView);
+
+ // determine to show pager, more, or neither
+ if (limit <= 0) {
+ // no display limit
+ add(new Label("moreLogs", "").setVisible(false));
+ } else {
+ if (pageResults) {
+ // paging
+ add(new Label("moreLogs", "").setVisible(false));
+ } else {
+ // more
+ if (commits.size() == limit) {
+ // show more
+ add(new LinkPanel("moreLogs", "link", new StringResourceModel("gb.moreLogs",
+ this, null), LogPage.class,
+ WicketUtils.newRepositoryParameter(repositoryName)));
+ } else {
+ // no more
+ add(new Label("moreLogs", "").setVisible(false));
+ }
+ }
+ }
+ }
+
+ public boolean hasMore() {
+ return hasMore;
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/NavigationPanel.html b/src/main/java/com/gitblit/wicket/panels/NavigationPanel.html new file mode 100644 index 00000000..f883e49d --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/NavigationPanel.html @@ -0,0 +1,12 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<wicket:panel>
+ <ul class="nav">
+ <li wicket:id="navLink"><span wicket:id="link">[link]</span></li>
+ </ul>
+</wicket:panel>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/NavigationPanel.java b/src/main/java/com/gitblit/wicket/panels/NavigationPanel.java new file mode 100644 index 00000000..558cc716 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/NavigationPanel.java @@ -0,0 +1,74 @@ +/*
+ * Copyright 2011 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.Component;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.wicket.PageRegistration;
+import com.gitblit.wicket.PageRegistration.DropDownMenuRegistration;
+import com.gitblit.wicket.PageRegistration.OtherPageLink;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.BasePage;
+
+public class NavigationPanel extends Panel {
+
+ private static final long serialVersionUID = 1L;
+
+ public NavigationPanel(String id, final Class<? extends BasePage> pageClass,
+ List<PageRegistration> registeredPages) {
+ super(id);
+
+ ListDataProvider<PageRegistration> refsDp = new ListDataProvider<PageRegistration>(
+ registeredPages);
+ DataView<PageRegistration> refsView = new DataView<PageRegistration>("navLink", refsDp) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<PageRegistration> item) {
+ PageRegistration entry = item.getModelObject();
+ if (entry instanceof OtherPageLink) {
+ // other link
+ OtherPageLink link = (OtherPageLink) entry;
+ Component c = new LinkPanel("link", null, getString(entry.translationKey), link.url);
+ c.setRenderBodyOnly(true);
+ item.add(c);
+ } else if (entry instanceof DropDownMenuRegistration) {
+ // drop down menu
+ DropDownMenuRegistration reg = (DropDownMenuRegistration) entry;
+ Component c = new DropDownMenu("link", getString(entry.translationKey), reg);
+ c.setRenderBodyOnly(true);
+ item.add(c);
+ WicketUtils.setCssClass(item, "dropdown");
+ } else {
+ // standard page link
+ Component c = new LinkPanel("link", null, getString(entry.translationKey),
+ entry.pageClass, entry.params);
+ c.setRenderBodyOnly(true);
+ if (entry.pageClass.equals(pageClass)) {
+ WicketUtils.setCssClass(item, "active");
+ }
+ item.add(c);
+ }
+ }
+ };
+ add(refsView);
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/ObjectContainer.java b/src/main/java/com/gitblit/wicket/panels/ObjectContainer.java new file mode 100644 index 00000000..d7f1f789 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/ObjectContainer.java @@ -0,0 +1,158 @@ +/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.Component;
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.Response;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.MarkupStream;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.protocol.http.ClientProperties;
+import org.apache.wicket.protocol.http.WebRequestCycle;
+import org.apache.wicket.protocol.http.WebSession;
+import org.apache.wicket.protocol.http.request.WebClientInfo;
+import org.apache.wicket.request.ClientInfo;
+import org.apache.wicket.util.value.IValueMap;
+
+/**
+ * https://cwiki.apache.org/WICKET/object-container-adding-flash-to-a-wicket-application.html
+ */
+public abstract class ObjectContainer extends WebMarkupContainer {
+
+ private static final long serialVersionUID = 1L;
+
+ // Some general attributes for the object tag:
+ private static final String ATTRIBUTE_CONTENTTYPE = "type";
+ private static final String ATTRIBUTE_CLASSID = "classid";
+ private static final String ATTRIBUTE_CODEBASE = "codebase";
+
+ // This is used for browser specific adjustments
+ private ClientProperties clientProperties = null;
+
+ public ObjectContainer(String id) {
+ super(id);
+ }
+
+ // Set an attribute/property
+ public abstract void setValue(String name, String value);
+
+ // Get an attribute/property
+ public abstract String getValue(String name);
+
+ // Set the object's content type
+ protected abstract String getContentType();
+
+ // Set the object's clsid (for IE)
+ protected abstract String getClsid();
+
+ // Where to get the browser plugin (for IE)
+ protected abstract String getCodebase();
+
+ // Object's valid attribute names
+ protected abstract List<String> getAttributeNames();
+
+ // Object's valid parameter names
+ protected abstract List<String> getParameterNames();
+
+ // Utility function to get the URL for the object's data
+ protected String resolveResource(String src) {
+ // if it's an absolute path, return it:
+ if (src.startsWith("/") || src.startsWith("http://") || src.startsWith("https://"))
+ return (src);
+
+ // use the parent container class to resolve the resource reference
+ Component parent = getParent();
+ if (parent instanceof Fragment) {
+ // must check for fragment, otherwise we end up in Wicket namespace
+ parent = parent.getParent();
+ }
+ if (parent != null) {
+ ResourceReference resRef = new ResourceReference(parent.getClass(), src, false);
+ return (urlFor(resRef).toString());
+ }
+
+ return (src);
+ }
+
+ public void onComponentTag(ComponentTag tag) {
+ super.onComponentTag(tag);
+
+ // get the attributes from the html-source
+ IValueMap attributeMap = tag.getAttributes();
+
+ // set the content type
+ String contentType = getContentType();
+ if (contentType != null && !"".equals(contentType))
+ attributeMap.put(ATTRIBUTE_CONTENTTYPE, contentType);
+
+ // set clsid and codebase for IE
+ if (getClientProperties().isBrowserInternetExplorer()) {
+ String clsid = getClsid();
+ String codeBase = getCodebase();
+
+ if (clsid != null && !"".equals(clsid))
+ attributeMap.put(ATTRIBUTE_CLASSID, clsid);
+ if (codeBase != null && !"".equals(codeBase))
+ attributeMap.put(ATTRIBUTE_CODEBASE, codeBase);
+ }
+
+ // add all attributes
+ for (String name : getAttributeNames()) {
+ String value = getValue(name);
+ if (value != null)
+ attributeMap.put(name, value);
+ }
+ }
+
+ public void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) {
+ Response response = getResponse();
+ response.write("\n");
+
+ // add all object's parameters:
+ for (String name : getParameterNames()) {
+ String value = getValue(name);
+ if (value != null) {
+ response.write("<param name=\"");
+ response.write(name);
+ response.write("\" value=\"");
+ response.write(value);
+ response.write("\"/>\n");
+ }
+ }
+
+ super.onComponentTagBody(markupStream, openTag);
+ }
+
+ // shortcut to the client properties:
+ protected ClientProperties getClientProperties() {
+ if (clientProperties == null) {
+ ClientInfo clientInfo = WebSession.get().getClientInfo();
+
+ if (clientInfo == null || !(clientInfo instanceof WebClientInfo)) {
+ clientInfo = new WebClientInfo((WebRequestCycle) getRequestCycle());
+ WebSession.get().setClientInfo(clientInfo);
+ }
+
+ clientProperties = ((WebClientInfo) clientInfo).getProperties();
+ }
+ return (clientProperties);
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/PagerPanel.html b/src/main/java/com/gitblit/wicket/panels/PagerPanel.html new file mode 100644 index 00000000..099001db --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/PagerPanel.html @@ -0,0 +1,13 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+<wicket:panel>
+ <div class="pagination pagination-right" style="margin: 0px;">
+ <ul>
+ <li wicket:id="page"><span wicket:id="pageLink"></span></li>
+ </ul>
+ </div>
+</wicket:panel>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/PagerPanel.java b/src/main/java/com/gitblit/wicket/panels/PagerPanel.java new file mode 100644 index 00000000..a5dbb9ef --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/PagerPanel.java @@ -0,0 +1,95 @@ +/*
+ * Copyright 2012 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.PageParameters;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.BasePage;
+
+public class PagerPanel extends Panel {
+
+ private static final long serialVersionUID = 1L;
+
+ public PagerPanel(String wicketId, final int currentPage, final int totalPages,
+ final Class<? extends BasePage> pageClass, final PageParameters baseParams) {
+ super(wicketId);
+ List<PageObject> pages = new ArrayList<PageObject>();
+ int[] deltas;
+ if (currentPage == 1) {
+ // [1], 2, 3, 4, 5
+ deltas = new int[] { 0, 1, 2, 3, 4 };
+ } else if (currentPage == 2) {
+ // 1, [2], 3, 4, 5
+ deltas = new int[] { -1, 0, 1, 2, 3 };
+ } else {
+ // 1, 2, [3], 4, 5
+ deltas = new int[] { -2, -1, 0, 1, 2 };
+ }
+
+ if (totalPages > 0) {
+ pages.add(new PageObject("\u2190", currentPage - 1));
+ }
+ for (int delta : deltas) {
+ int page = currentPage + delta;
+ if (page > 0 && page <= totalPages) {
+ pages.add(new PageObject("" + page, page));
+ }
+ }
+ if (totalPages > 0) {
+ pages.add(new PageObject("\u2192", currentPage + 1));
+ }
+
+ ListDataProvider<PageObject> pagesProvider = new ListDataProvider<PageObject>(pages);
+ final DataView<PageObject> pagesView = new DataView<PageObject>("page", pagesProvider) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<PageObject> item) {
+ PageObject pageItem = item.getModelObject();
+ PageParameters pageParams = new PageParameters(baseParams);
+ pageParams.put("pg", pageItem.page);
+ LinkPanel link = new LinkPanel("pageLink", null, pageItem.text, pageClass, pageParams);
+ link.setRenderBodyOnly(true);
+ item.add(link);
+ if (pageItem.page == currentPage || pageItem.page < 1 || pageItem.page > totalPages) {
+ WicketUtils.setCssClass(item, "disabled");
+ }
+ }
+ };
+ add(pagesView);
+ }
+
+ private class PageObject implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ String text;
+ int page;
+
+ PageObject(String text, int page) {
+ this.text = text;
+ this.page = page;
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/PathBreadcrumbsPanel.html b/src/main/java/com/gitblit/wicket/panels/PathBreadcrumbsPanel.html new file mode 100644 index 00000000..c51ceac8 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/PathBreadcrumbsPanel.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">
+
+<wicket:panel>
+ <!-- page path links -->
+ <div class="page_path">
+ <ul class="breadcrumb">
+ <li wicket:id="path">
+ <span wicket:id="pathLink"></span> <span class="divider" wicket:id="pathSeparator"></span>
+ </li>
+ </ul>
+ </div>
+</wicket:panel>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/PathBreadcrumbsPanel.java b/src/main/java/com/gitblit/wicket/panels/PathBreadcrumbsPanel.java new file mode 100644 index 00000000..f6c0e4f8 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/PathBreadcrumbsPanel.java @@ -0,0 +1,92 @@ +/*
+ * Copyright 2011 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.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.TreePage;
+
+public class PathBreadcrumbsPanel extends Panel {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String ROOT = "--ROOT--";
+
+ public PathBreadcrumbsPanel(String id, final String repositoryName, String pathName,
+ final String objectId) {
+ super(id);
+ List<BreadCrumb> crumbs = new ArrayList<BreadCrumb>();
+ crumbs.add(new BreadCrumb("[" + repositoryName + "]", ROOT, false));
+
+ if (pathName != null && pathName.length() > 0) {
+ String[] paths = pathName.split("/");
+ StringBuilder sb = new StringBuilder();
+
+ for (int i = 0; i < paths.length; i++) {
+ String path = paths[i];
+ sb.append(path);
+ crumbs.add(new BreadCrumb(path, sb.toString(), i == (paths.length - 1)));
+ sb.append('/');
+ }
+ }
+
+ ListDataProvider<BreadCrumb> crumbsDp = new ListDataProvider<BreadCrumb>(crumbs);
+ DataView<BreadCrumb> pathsView = new DataView<BreadCrumb>("path", crumbsDp) {
+ private static final long serialVersionUID = 1L;
+
+ public void populateItem(final Item<BreadCrumb> item) {
+ final BreadCrumb entry = item.getModelObject();
+ String path = entry.path;
+ if (path.equals(ROOT)) {
+ path = null;
+ }
+ if (entry.isLeaf) {
+ item.add(new Label("pathLink", entry.name));
+ item.add(new Label("pathSeparator", "").setVisible(false));
+ } else {
+ item.add(new LinkPanel("pathLink", null, entry.name, TreePage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, path)));
+ item.add(new Label("pathSeparator", "/"));
+ }
+ }
+ };
+ add(pathsView);
+ }
+
+ private static class BreadCrumb implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ final String name;
+ final String path;
+ final boolean isLeaf;
+
+ BreadCrumb(String name, String path, boolean isLeaf) {
+ this.name = name;
+ this.path = path;
+ this.isLeaf = isLeaf;
+ }
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html new file mode 100644 index 00000000..9b621d5a --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.html @@ -0,0 +1,80 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<wicket:panel>
+ <wicket:fragment wicket:id="repositoryAdminLinks">
+ <span class="link">
+ <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a>
+ | <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a>
+ | <a wicket:id="editRepository"><wicket:message key="gb.edit">[edit]</wicket:message></a>
+ | <a wicket:id="deleteRepository"><wicket:message key="gb.delete">[delete]</wicket:message></a>
+ </span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="repositoryOwnerLinks">
+ <span class="link">
+ <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a>
+ | <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a>
+ | <a wicket:id="editRepository"><wicket:message key="gb.edit">[edit]</wicket:message></a>
+ </span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="repositoryUserLinks">
+ <span class="link">
+ <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a>
+ | <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a>
+ </span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="originFragment">
+ <p class="originRepository" style="margin-left:20px;" ><wicket:message key="gb.forkedFrom">[forked from]</wicket:message> <span wicket:id="originRepository">[origin repository]</span></p>
+ </wicket:fragment>
+
+ <div>
+ <div style="padding-top:15px;padding-bottom:15px;margin-right:15px;">
+ <div class="pull-right" style="text-align:right;padding-right:15px;">
+ <span wicket:id="repositoryLinks"></span>
+ <div>
+ <img class="inlineIcon" wicket:id="sparkleshareIcon" />
+ <img class="inlineIcon" wicket:id="frozenIcon" />
+ <img class="inlineIcon" wicket:id="federatedIcon" />
+
+ <a style="text-decoration: none;" wicket:id="tickets" wicket:message="title:gb.tickets">
+ <img style="border:0px;vertical-align:middle;" src="bug_16x16.png"></img>
+ </a>
+ <a style="text-decoration: none;" wicket:id="docs" wicket:message="title:gb.docs">
+ <img style="border:0px;vertical-align:middle;" src="book_16x16.png"></img>
+ </a>
+ <a style="text-decoration: none;" wicket:id="syndication" wicket:message="title:gb.feed">
+ <img style="border:0px;vertical-align:middle;" src="feed_16x16.png"></img>
+ </a>
+ </div>
+ <span style="color: #999;font-style:italic;font-size:0.8em;" wicket:id="repositoryOwner">[owner]</span>
+ </div>
+
+ <div class="pageTitle" style="border:0px;">
+ <div>
+ <span class="repositorySwatch" wicket:id="repositorySwatch"></span>
+ <span class="repository" style="padding-left:3px;color:black;" wicket:id="repositoryName">[repository name]</span>
+ <img class="inlineIcon" style="vertical-align:baseline" wicket:id="accessRestrictionIcon" />
+ </div>
+ <span wicket:id="originRepository">[origin repository]</span>
+ </div>
+
+ <div style="padding-left:20px;">
+ <div style="padding-bottom:10px" wicket:id="repositoryDescription">[repository description]</div>
+
+ <div style="color: #999;">
+ <wicket:message key="gb.lastChange">[last change]</wicket:message> <span wicket:id="repositoryLastChange">[last change]</span>,
+ <span style="font-size:0.8em;" wicket:id="repositorySize">[repository size]</span>
+ </div>
+
+ <div class="hidden-phone hidden-tablet" wicket:id="repositoryCloneUrl">[repository clone url]</div>
+ </div>
+ </div>
+ </div>
+</wicket:panel>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java new file mode 100644 index 00000000..7b4ee9f0 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/ProjectRepositoryPanel.java @@ -0,0 +1,229 @@ +/*
+ * Copyright 2012 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.List;
+import java.util.Map;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.Localizer;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.link.ExternalLink;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Fragment;
+
+import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.SyndicationServlet;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.GitBlitWebSession;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.BasePage;
+import com.gitblit.wicket.pages.DocsPage;
+import com.gitblit.wicket.pages.EditRepositoryPage;
+import com.gitblit.wicket.pages.LogPage;
+import com.gitblit.wicket.pages.SummaryPage;
+import com.gitblit.wicket.pages.TicketsPage;
+import com.gitblit.wicket.pages.TreePage;
+
+public class ProjectRepositoryPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ public ProjectRepositoryPanel(String wicketId, Localizer localizer, Component parent,
+ final boolean isAdmin, final RepositoryModel entry,
+ final Map<AccessRestrictionType, String> accessRestrictions) {
+ super(wicketId);
+
+ final boolean showSwatch = GitBlit.getBoolean(Keys.web.repositoryListSwatches, true);
+ final boolean gitServlet = GitBlit.getBoolean(Keys.git.enableGitServlet, true);
+ final boolean showSize = GitBlit.getBoolean(Keys.web.showRepositorySizes, true);
+
+ // repository swatch
+ Component swatch;
+ if (entry.isBare) {
+ swatch = new Label("repositorySwatch", " ").setEscapeModelStrings(false);
+ } else {
+ swatch = new Label("repositorySwatch", "!");
+ WicketUtils.setHtmlTooltip(swatch, localizer.getString("gb.workingCopyWarning", parent));
+ }
+ WicketUtils.setCssBackground(swatch, entry.toString());
+ add(swatch);
+ swatch.setVisible(showSwatch);
+
+ PageParameters pp = WicketUtils.newRepositoryParameter(entry.name);
+ add(new LinkPanel("repositoryName", "list", StringUtils.getRelativePath(entry.projectPath,
+ StringUtils.stripDotGit(entry.name)), SummaryPage.class, pp));
+ add(new Label("repositoryDescription", entry.description).setVisible(!StringUtils
+ .isEmpty(entry.description)));
+
+ if (StringUtils.isEmpty(entry.originRepository)) {
+ add(new Label("originRepository").setVisible(false));
+ } else {
+ Fragment forkFrag = new Fragment("originRepository", "originFragment", this);
+ forkFrag.add(new LinkPanel("originRepository", null, StringUtils.stripDotGit(entry.originRepository),
+ SummaryPage.class, WicketUtils.newRepositoryParameter(entry.originRepository)));
+ add(forkFrag);
+ }
+
+ if (entry.isSparkleshared()) {
+ add(WicketUtils.newImage("sparkleshareIcon", "star_16x16.png", localizer.getString("gb.isSparkleshared", parent)));
+ } else {
+ add(WicketUtils.newClearPixel("sparkleshareIcon").setVisible(false));
+ }
+
+ add(new BookmarkablePageLink<Void>("tickets", TicketsPage.class, pp).setVisible(entry.useTickets));
+ add(new BookmarkablePageLink<Void>("docs", DocsPage.class, pp).setVisible(entry.useDocs));
+
+ if (entry.isFrozen) {
+ add(WicketUtils.newImage("frozenIcon", "cold_16x16.png", localizer.getString("gb.isFrozen", parent)));
+ } else {
+ add(WicketUtils.newClearPixel("frozenIcon").setVisible(false));
+ }
+
+ if (entry.isFederated) {
+ add(WicketUtils.newImage("federatedIcon", "federated_16x16.png", localizer.getString("gb.isFederated", parent)));
+ } else {
+ add(WicketUtils.newClearPixel("federatedIcon").setVisible(false));
+ }
+ switch (entry.accessRestriction) {
+ case NONE:
+ add(WicketUtils.newBlankImage("accessRestrictionIcon").setVisible(false));
+ break;
+ case PUSH:
+ add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png",
+ accessRestrictions.get(entry.accessRestriction)));
+ break;
+ case CLONE:
+ add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png",
+ accessRestrictions.get(entry.accessRestriction)));
+ break;
+ case VIEW:
+ add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png",
+ accessRestrictions.get(entry.accessRestriction)));
+ break;
+ default:
+ add(WicketUtils.newBlankImage("accessRestrictionIcon"));
+ }
+
+ if (ArrayUtils.isEmpty(entry.owners)) {
+ add(new Label("repositoryOwner").setVisible(false));
+ } else {
+ String owner = "";
+ for (String username : entry.owners) {
+ UserModel ownerModel = GitBlit.self().getUserModel(username);
+
+ if (ownerModel != null) {
+ owner = ownerModel.getDisplayName();
+ }
+ }
+ if (entry.owners.size() > 1) {
+ owner += ", ...";
+ }
+ Label ownerLabel = (new Label("repositoryOwner", owner + " (" +
+ localizer.getString("gb.owner", parent) + ")"));
+ WicketUtils.setHtmlTooltip(ownerLabel, ArrayUtils.toString(entry.owners));
+ add(ownerLabel);
+ }
+
+ UserModel user = GitBlitWebSession.get().getUser();
+ if (user == null) {
+ user = UserModel.ANONYMOUS;
+ }
+ Fragment repositoryLinks;
+ boolean showOwner = entry.isOwner(user.username);
+ // owner of personal repository gets admin powers
+ boolean showAdmin = isAdmin || entry.isUsersPersonalRepository(user.username);
+
+ if (showAdmin || showOwner) {
+ repositoryLinks = new Fragment("repositoryLinks", showAdmin ? "repositoryAdminLinks"
+ : "repositoryOwnerLinks", this);
+ repositoryLinks.add(new BookmarkablePageLink<Void>("editRepository", EditRepositoryPage.class,
+ WicketUtils.newRepositoryParameter(entry.name)));
+ if (showAdmin) {
+ Link<Void> deleteLink = new Link<Void>("deleteRepository") {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onClick() {
+ if (GitBlit.self().deleteRepositoryModel(entry)) {
+ // redirect to the owning page
+ if (entry.isPersonalRepository()) {
+ setResponsePage(getPage().getClass(), WicketUtils.newUsernameParameter(entry.projectPath.substring(1)));
+ } else {
+ setResponsePage(getPage().getClass(), WicketUtils.newProjectParameter(entry.projectPath));
+ }
+ } else {
+ error(MessageFormat.format(getString("gb.repositoryDeleteFailed"), entry));
+ }
+ }
+ };
+ deleteLink.add(new JavascriptEventConfirmation("onclick", MessageFormat.format(
+ localizer.getString("gb.deleteRepository", parent), entry)));
+ repositoryLinks.add(deleteLink);
+ }
+ } else {
+ repositoryLinks = new Fragment("repositoryLinks", "repositoryUserLinks", this);
+ }
+
+ repositoryLinks.add(new BookmarkablePageLink<Void>("tree", TreePage.class, WicketUtils
+ .newRepositoryParameter(entry.name)).setEnabled(entry.hasCommits));
+
+ repositoryLinks.add(new BookmarkablePageLink<Void>("log", LogPage.class, WicketUtils
+ .newRepositoryParameter(entry.name)).setEnabled(entry.hasCommits));
+
+ add(repositoryLinks);
+
+ String lastChange;
+ if (entry.lastChange.getTime() == 0) {
+ lastChange = "--";
+ } else {
+ lastChange = getTimeUtils().timeAgo(entry.lastChange);
+ }
+ Label lastChangeLabel = new Label("repositoryLastChange", lastChange);
+ add(lastChangeLabel);
+ WicketUtils.setCssClass(lastChangeLabel, getTimeUtils().timeAgoCss(entry.lastChange));
+
+ if (entry.hasCommits) {
+ // Existing repository
+ add(new Label("repositorySize", entry.size).setVisible(showSize));
+ } else {
+ // New repository
+ add(new Label("repositorySize", localizer.getString("gb.empty", parent)).setEscapeModelStrings(false));
+ }
+
+ add(new ExternalLink("syndication", SyndicationServlet.asLink("", entry.name, null, 0)));
+
+ List<String> repositoryUrls = new ArrayList<String>();
+ if (gitServlet) {
+ // add the Gitblit repository url
+ repositoryUrls.add(BasePage.getRepositoryUrl(entry));
+ }
+ repositoryUrls.addAll(GitBlit.self().getOtherCloneUrls(entry.name));
+
+ String primaryUrl = ArrayUtils.isEmpty(repositoryUrls) ? "" : repositoryUrls.remove(0);
+ add(new RepositoryUrlPanel("repositoryCloneUrl", primaryUrl));
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/RefsPanel.html b/src/main/java/com/gitblit/wicket/panels/RefsPanel.html new file mode 100644 index 00000000..a3c0ec49 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/RefsPanel.html @@ -0,0 +1,12 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<wicket:panel>
+ <span wicket:id="ref">
+ <span wicket:id="lineBreak">[LB]</span><span wicket:id="refName">ref</span>
+ </span>
+</wicket:panel>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/RefsPanel.java b/src/main/java/com/gitblit/wicket/panels/RefsPanel.java new file mode 100644 index 00000000..3ba22c0b --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/RefsPanel.java @@ -0,0 +1,156 @@ +/*
+ * Copyright 2011 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.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import com.gitblit.models.RefModel;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.CommitPage;
+import com.gitblit.wicket.pages.LogPage;
+import com.gitblit.wicket.pages.RepositoryPage;
+import com.gitblit.wicket.pages.TagPage;
+
+public class RefsPanel extends Panel {
+
+ private static final long serialVersionUID = 1L;
+
+ public RefsPanel(String id, final String repositoryName, RevCommit c,
+ Map<ObjectId, List<RefModel>> refs) {
+ this(id, repositoryName, refs.get(c.getId()));
+ }
+
+ public RefsPanel(String id, final String repositoryName, List<RefModel> refs) {
+ super(id);
+ if (refs == null) {
+ refs = new ArrayList<RefModel>();
+ }
+ Collections.sort(refs, new Comparator<RefModel>() {
+ @Override
+ public int compare(RefModel o1, RefModel o2) {
+ // sort remote heads last, otherwise sort by name
+ // this is so we can insert a break on the refs panel
+ // [head][branch][branch][tag][tag]
+ // [remote][remote][remote]
+ boolean remote1 = o1.displayName.startsWith(Constants.R_REMOTES);
+ boolean remote2 = o2.displayName.startsWith(Constants.R_REMOTES);
+ if (remote1 && remote2) {
+ // both are remote heads, sort by name
+ return o1.displayName.compareTo(o2.displayName);
+ }
+ if (remote1) {
+ // o1 is remote, o2 comes first
+ return 1;
+ }
+ if (remote2) {
+ // remote is o2, o1 comes first
+ return -1;
+ }
+ // standard sort
+ return o1.displayName.compareTo(o2.displayName);
+ }
+ });
+
+ // count remote and determine if we should insert a break
+ int remoteCount = 0;
+ for (RefModel ref : refs) {
+ if (ref.displayName.startsWith(Constants.R_REMOTES)) {
+ remoteCount++;
+ }
+ }
+ final boolean shouldBreak = remoteCount < refs.size();
+
+ ListDataProvider<RefModel> refsDp = new ListDataProvider<RefModel>(refs);
+ DataView<RefModel> refsView = new DataView<RefModel>("ref", refsDp) {
+ private static final long serialVersionUID = 1L;
+ private boolean alreadyInsertedBreak = !shouldBreak;
+
+ public void populateItem(final Item<RefModel> item) {
+ RefModel entry = item.getModelObject();
+ String name = entry.displayName;
+ String objectid = entry.getReferencedObjectId().getName();
+ boolean breakLine = false;
+ Class<? extends RepositoryPage> linkClass = CommitPage.class;
+ String cssClass = "";
+ if (name.startsWith(Constants.R_HEADS)) {
+ // local branch
+ linkClass = LogPage.class;
+ name = name.substring(Constants.R_HEADS.length());
+ cssClass = "localBranch";
+ } else if (name.equals(Constants.HEAD)) {
+ // local head
+ linkClass = LogPage.class;
+ cssClass = "headRef";
+ } else if (name.startsWith(Constants.R_REMOTES)) {
+ // remote branch
+ linkClass = LogPage.class;
+ name = name.substring(Constants.R_REMOTES.length());
+ cssClass = "remoteBranch";
+ if (!alreadyInsertedBreak) {
+ breakLine = true;
+ alreadyInsertedBreak = true;
+ }
+ } else if (name.startsWith(Constants.R_TAGS)) {
+ // tag
+ if (entry.isAnnotatedTag()) {
+ linkClass = TagPage.class;
+ objectid = entry.getObjectId().getName();
+ } else {
+ linkClass = CommitPage.class;
+ objectid = entry.getReferencedObjectId().getName();
+ }
+ name = name.substring(Constants.R_TAGS.length());
+ cssClass = "tagRef";
+ } else if (name.startsWith(Constants.R_NOTES)) {
+ // codereview refs
+ linkClass = CommitPage.class;
+ cssClass = "otherRef";
+ } else if (name.startsWith(com.gitblit.Constants.R_GITBLIT)) {
+ // gitblit refs
+ linkClass = LogPage.class;
+ cssClass = "otherRef";
+ name = name.substring(com.gitblit.Constants.R_GITBLIT.length());
+ }
+
+ Component c = new LinkPanel("refName", null, name, linkClass,
+ WicketUtils.newObjectParameter(repositoryName, objectid));
+ WicketUtils.setCssClass(c, cssClass);
+ WicketUtils.setHtmlTooltip(c, name);
+ item.add(c);
+ Label lb = new Label("lineBreak", "<br/>");
+ lb.setVisible(breakLine);
+ lb.setRenderBodyOnly(true);
+ item.add(lb.setEscapeModelStrings(false));
+ item.setRenderBodyOnly(true);
+ }
+ };
+ add(refsView);
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html b/src/main/java/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html new file mode 100644 index 00000000..eb82245c --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/RegistrantPermissionsPanel.html @@ -0,0 +1,44 @@ +<!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>
+
+ <form class="form-inline" wicket:id="permissionToggleForm">
+ <div style="padding-bottom:10px" class="btn-group pull-right" data-toggle="buttons-radio">
+ <a class="btn btn-info" wicket:id="showMutable"><wicket:message key="gb.mutable"></wicket:message></a>
+ <a class="btn btn-info" wicket:id="showSpecified"><wicket:message key="gb.specified"></wicket:message></a>
+ <a class="btn btn-info" wicket:id="showEffective"><wicket:message key="gb.effective"></wicket:message></a>
+ </div>
+ </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: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>
+
+ <div style="clear:both; padding-top:15px;" class="row-fluid">
+ <form style="padding: 20px 40px;" class="well form-inline" wicket:id="addPermissionForm">
+ <select class="input-xlarge" wicket:id="registrant"></select> <select class="input-large" wicket:id="permission"></select> <input class="btn btn-success" type="submit" value="Add" wicket:message="value:gb.add" wicket:id="addPermissionButton"/>
+ </form>
+ </div>
+
+ <wicket:fragment wicket:id="repositoryRegistrant">
+ <b><span class="repositorySwatch" wicket:id="repositorySwatch"></span></b> <span wicket:id="repositoryName"></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="userRegistrant">
+ <span wicket:id="userAvatar"></span> <span wicket:id="userName"></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="teamRegistrant">
+ <span style="font-weight: bold;" wicket:id="teamName"></span>
+ </wicket:fragment>
+
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java b/src/main/java/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java new file mode 100644 index 00000000..4156cd19 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/RegistrantPermissionsPanel.java @@ -0,0 +1,340 @@ +/* + * Copyright 2012 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.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.wicket.Component; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; +import org.apache.wicket.ajax.markup.html.form.AjaxButton; +import org.apache.wicket.markup.html.basic.Label; +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.panel.Fragment; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.markup.repeater.OddEvenItem; +import org.apache.wicket.markup.repeater.RefreshingView; +import org.apache.wicket.markup.repeater.util.ModelIteratorAdapter; +import org.apache.wicket.model.CompoundPropertyModel; +import org.apache.wicket.model.IModel; +import org.eclipse.jgit.lib.PersonIdent; + +import com.gitblit.Constants.AccessPermission; +import com.gitblit.Constants.PermissionType; +import com.gitblit.Constants.RegistrantType; +import com.gitblit.GitBlit; +import com.gitblit.models.RegistrantAccessPermission; +import com.gitblit.models.UserModel; +import com.gitblit.utils.DeepCopier; +import com.gitblit.utils.StringUtils; +import com.gitblit.wicket.WicketUtils; + +/** + * Allows user to manipulate registrant access permissions. + * + * @author James Moger + * + */ +public class RegistrantPermissionsPanel extends BasePanel { + + private static final long serialVersionUID = 1L; + + public enum Show { + specified, mutable, effective; + + public boolean show(RegistrantAccessPermission ap) { + switch (this) { + case specified: + return ap.mutable || ap.isOwner(); + case mutable: + return ap.mutable; + case effective: + return true; + default: + return true; + } + } + } + + private Show activeState = Show.mutable; + + public RegistrantPermissionsPanel(String wicketId, RegistrantType registrantType, List<String> allRegistrants, final List<RegistrantAccessPermission> permissions, final Map<AccessPermission, String> translations) { + super(wicketId); + setOutputMarkupId(true); + + /* + * Permission view toggle buttons + */ + Form<Void> permissionToggleForm = new Form<Void>("permissionToggleForm"); + permissionToggleForm.add(new ShowStateButton("showSpecified", Show.specified)); + permissionToggleForm.add(new ShowStateButton("showMutable", Show.mutable)); + permissionToggleForm.add(new ShowStateButton("showEffective", Show.effective)); + add(permissionToggleForm); + + /* + * Permission repeating display + */ + RefreshingView<RegistrantAccessPermission> dataView = new RefreshingView<RegistrantAccessPermission>("permissionRow") { + private static final long serialVersionUID = 1L; + + @Override + protected Iterator<IModel<RegistrantAccessPermission>> getItemModels() { + // the iterator returns RepositoryPermission objects, but we need it to + // return models + return new ModelIteratorAdapter<RegistrantAccessPermission>(permissions.iterator()) { + @Override + protected IModel<RegistrantAccessPermission> model(RegistrantAccessPermission permission) { + return new CompoundPropertyModel<RegistrantAccessPermission>(permission); + } + }; + } + + @Override + protected Item<RegistrantAccessPermission> newItem(String id, int index, IModel<RegistrantAccessPermission> model) { + // this item sets markup class attribute to either 'odd' or + // 'even' for decoration + return new OddEvenItem<RegistrantAccessPermission>(id, index, model); + } + + public void populateItem(final Item<RegistrantAccessPermission> item) { + final RegistrantAccessPermission entry = item.getModelObject(); + if (RegistrantType.REPOSITORY.equals(entry.registrantType)) { + String repoName = StringUtils.stripDotGit(entry.registrant); + if (!entry.isMissing() && StringUtils.findInvalidCharacter(repoName) == null) { + // repository, strip .git and show swatch + Fragment repositoryFragment = new Fragment("registrant", "repositoryRegistrant", RegistrantPermissionsPanel.this); + Component swatch = new Label("repositorySwatch", " ").setEscapeModelStrings(false); + WicketUtils.setCssBackground(swatch, entry.toString()); + repositoryFragment.add(swatch); + Label registrant = new Label("repositoryName", repoName); + repositoryFragment.add(registrant); + item.add(repositoryFragment); + } else { + // regex or missing + Label label = new Label("registrant", entry.registrant); + WicketUtils.setCssStyle(label, "font-weight: bold;"); + item.add(label); + } + } else if (RegistrantType.USER.equals(entry.registrantType)) { + // user + PersonIdent ident = new PersonIdent(entry.registrant, ""); + UserModel user = GitBlit.self().getUserModel(entry.registrant); + if (user != null) { + ident = new PersonIdent(user.getDisplayName(), user.emailAddress == null ? user.getDisplayName() : user.emailAddress); + } + + Fragment userFragment = new Fragment("registrant", "userRegistrant", RegistrantPermissionsPanel.this); + userFragment.add(new GravatarImage("userAvatar", ident, 20, false)); + userFragment.add(new Label("userName", entry.registrant)); + item.add(userFragment); + } else { + // team + Fragment teamFragment = new Fragment("registrant", "teamRegistrant", RegistrantPermissionsPanel.this); + teamFragment.add(new Label("teamName", entry.registrant)); + item.add(teamFragment); + } + switch (entry.permissionType) { + case ADMINISTRATOR: + Label administrator = new Label("pType", entry.source == null ? getString("gb.administrator") : entry.source); + WicketUtils.setHtmlTooltip(administrator, getString("gb.administratorPermission")); + WicketUtils.setCssClass(administrator, "label label-inverse"); + item.add(administrator); + break; + case OWNER: + Label owner = new Label("pType", getString("gb.owner")); + WicketUtils.setHtmlTooltip(owner, getString("gb.ownerPermission")); + WicketUtils.setCssClass(owner, "label label-info"); + item.add(owner); + break; + case TEAM: + Label team = new Label("pType", entry.source == null ? getString("gb.team") : entry.source); + WicketUtils.setHtmlTooltip(team, MessageFormat.format(getString("gb.teamPermission"), entry.source)); + WicketUtils.setCssClass(team, "label label-success"); + item.add(team); + break; + case REGEX: + Label regex = new Label("pType", "regex"); + if (!StringUtils.isEmpty(entry.source)) { + WicketUtils.setHtmlTooltip(regex, MessageFormat.format(getString("gb.regexPermission"), entry.source)); + } + WicketUtils.setCssClass(regex, "label"); + item.add(regex); + break; + default: + if (entry.isMissing()) { + // repository is missing, this permission will be removed on save + Label missing = new Label("pType", getString("gb.missing")); + WicketUtils.setCssClass(missing, "label label-important"); + WicketUtils.setHtmlTooltip(missing, getString("gb.missingPermission")); + item.add(missing); + } else { + // standard permission + item.add(new Label("pType", "").setVisible(false)); + } + break; + } + + item.setVisible(activeState.show(entry)); + + // use ajax to get immediate update of permission level change + // otherwise we can lose it if they change levels and then add + // a new repository permission + final DropDownChoice<AccessPermission> permissionChoice = new DropDownChoice<AccessPermission>( + "permission", Arrays.asList(AccessPermission.values()), new AccessPermissionRenderer(translations)); + // only allow changing an explicitly defined permission + // this is designed to prevent changing a regex permission in + // a repository + permissionChoice.setEnabled(entry.mutable); + permissionChoice.setOutputMarkupId(true); + if (entry.mutable) { + permissionChoice.add(new AjaxFormComponentUpdatingBehavior("onchange") { + + private static final long serialVersionUID = 1L; + + protected void onUpdate(AjaxRequestTarget target) { + target.addComponent(permissionChoice); + } + }); + } + + item.add(permissionChoice); + } + }; + add(dataView); + setOutputMarkupId(true); + + // filter out registrants we already have permissions for + final List<String> registrants = new ArrayList<String>(allRegistrants); + for (RegistrantAccessPermission rp : permissions) { + if (rp.mutable) { + // remove editable duplicates + // this allows for specifying an explicit permission + registrants.remove(rp.registrant); + } else if (rp.isAdmin()) { + // administrators can not have their permission changed + registrants.remove(rp.registrant); + } else if (rp.isOwner()) { + // owners can not have their permission changed + registrants.remove(rp.registrant); + } + } + + /* + * Add permission form + */ + IModel<RegistrantAccessPermission> addPermissionModel = new CompoundPropertyModel<RegistrantAccessPermission>(new RegistrantAccessPermission(registrantType)); + Form<RegistrantAccessPermission> addPermissionForm = new Form<RegistrantAccessPermission>("addPermissionForm", addPermissionModel); + addPermissionForm.add(new DropDownChoice<String>("registrant", registrants)); + addPermissionForm.add(new DropDownChoice<AccessPermission>("permission", Arrays + .asList(AccessPermission.NEWPERMISSIONS), new AccessPermissionRenderer(translations))); + AjaxButton button = new AjaxButton("addPermissionButton", addPermissionForm) { + + private static final long serialVersionUID = 1L; + + @Override + protected void onSubmit(AjaxRequestTarget target, Form<?> form) { + // add permission to our list + RegistrantAccessPermission rp = (RegistrantAccessPermission) form.getModel().getObject(); + if (rp.permission == null) { + return; + } + RegistrantAccessPermission copy = DeepCopier.copy(rp); + if (StringUtils.findInvalidCharacter(copy.registrant) != null) { + copy.permissionType = PermissionType.REGEX; + copy.source = copy.registrant; + } + permissions.add(copy); + + // resort permissions after insert to convey idea of eval order + Collections.sort(permissions); + + // remove registrant from available choices + registrants.remove(rp.registrant); + + // force the panel to refresh + target.addComponent(RegistrantPermissionsPanel.this); + } + }; + addPermissionForm.add(button); + + // only show add permission form if we have a registrant choice + add(addPermissionForm.setVisible(registrants.size() > 0)); + } + + protected boolean getStatelessHint() + { + return false; + } + + + private class AccessPermissionRenderer implements IChoiceRenderer<AccessPermission> { + + private static final long serialVersionUID = 1L; + + private final Map<AccessPermission, String> map; + + public AccessPermissionRenderer(Map<AccessPermission, String> map) { + this.map = map; + } + + @Override + public String getDisplayValue(AccessPermission type) { + return map.get(type); + } + + @Override + public String getIdValue(AccessPermission type, int index) { + return Integer.toString(index); + } + } + + private class ShowStateButton extends AjaxButton { + private static final long serialVersionUID = 1L; + + Show buttonState; + + public ShowStateButton(String wicketId, Show state) { + super(wicketId); + this.buttonState = state; + setOutputMarkupId(true); + } + + @Override + protected void onBeforeRender() + { + String cssClass = "btn"; + if (buttonState.equals(RegistrantPermissionsPanel.this.activeState)) { + cssClass = "btn btn-info active"; + } + WicketUtils.setCssClass(this, cssClass); + super.onBeforeRender(); + } + + @Override + protected void onSubmit(AjaxRequestTarget target, Form<?> form) { + RegistrantPermissionsPanel.this.activeState = buttonState; + target.addComponent(RegistrantPermissionsPanel.this); + } + }; +} diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.html b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.html new file mode 100644 index 00000000..81a4c6eb --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.html @@ -0,0 +1,107 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<body>
+<wicket:panel>
+
+ <div wicket:id="managementPanel">[management links]</div>
+
+ <table class="repositories">
+ <span wicket:id="headerContent"></span>
+ <tbody>
+ <tr wicket:id="row">
+ <span wicket:id="rowContent"></span>
+ </tr>
+ </tbody>
+ </table>
+
+ <wicket:fragment wicket:id="adminLinks">
+ <!-- page nav links -->
+ <div class="admin_nav">
+ <a class="btn-small" wicket:id="clearCache">
+ <i class="icon icon-remove"></i>
+ <wicket:message key="gb.clearCache"></wicket:message>
+ </a>
+ <a class="btn-small" wicket:id="newRepository" style="padding-right:0px;">
+ <i class="icon icon-plus-sign"></i>
+ <wicket:message key="gb.newRepository"></wicket:message>
+ </a>
+ </div>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="personalLinks">
+ <!-- page nav links -->
+ <div class="admin_nav">
+ <a class="btn-small" wicket:id="newRepository" style="padding-right:0px;">
+ <i class="icon icon-plus-sign"></i>
+ <wicket:message key="gb.newRepository"></wicket:message>
+ </a>
+ </div>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="repositoryAdminLinks">
+ <span class="link"><a wicket:id="editRepository"><wicket:message key="gb.edit">[edit]</wicket:message></a> | <a wicket:id="deleteRepository"><wicket:message key="gb.delete">[delete]</wicket:message></a></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="repositoryOwnerLinks">
+ <span class="link"><a wicket:id="editRepository"><wicket:message key="gb.edit">[edit]</wicket:message></a></span>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="flatRepositoryHeader">
+ <tr>
+ <th class="left" wicket:id="orderByRepository">
+ <img style="vertical-align: middle;" src="git-black-16x16.png"/>
+ <wicket:message key="gb.repository">Repository</wicket:message>
+ </th>
+ <th class="hidden-phone" wicket:id="orderByDescription"><wicket:message key="gb.description">Description</wicket:message></th>
+ <th class="hidden-tablet hidden-phone" wicket:id="orderByOwner"><wicket:message key="gb.owner">Owner</wicket:message></th>
+ <th class="hidden-phone"></th>
+ <th wicket:id="orderByDate"><wicket:message key="gb.lastChange">Last Change</wicket:message></th>
+ <th class="hidden-phone"></th>
+ <th class="right"></th>
+ </tr>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="groupRepositoryHeader">
+ <tr>
+ <th class="left">
+ <img style="vertical-align: middle;" src="git-black-16x16.png"/>
+ <wicket:message key="gb.repository">Repository</wicket:message>
+ </th>
+ <th class="hidden-phone" ><span><wicket:message key="gb.description">Description</wicket:message></span></th>
+ <th class="hidden-tablet hidden-phone"><span><wicket:message key="gb.owner">Owner</wicket:message></span></th>
+ <th class="hidden-phone"></th>
+ <th><wicket:message key="gb.lastChange">Last Change</wicket:message></th>
+ <th class="hidden-phone"></th>
+ <th class="right"></th>
+ </tr>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="groupRepositoryRow">
+ <td colspan="1"><span wicket:id="groupName">[group name]</span></td>
+ <td colspan="6" style="padding: 2px;"><span class="hidden-phone" style="font-weight:normal;color:#666;" wicket:id="groupDescription">[description]</span></td>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="repositoryRow">
+ <td class="left" style="padding-left:3px;" ><b><span class="repositorySwatch" wicket:id="repositorySwatch"></span></b> <span style="padding-left:3px;" wicket:id="repositoryName">[repository name]</span></td>
+ <td class="hidden-phone"><span class="list" wicket:id="repositoryDescription">[repository description]</span></td>
+ <td class="hidden-tablet hidden-phone author"><span wicket:id="repositoryOwner">[repository owner]</span></td>
+ <td class="hidden-phone" style="text-align: right;padding-right:10px;"><img class="inlineIcon" wicket:id="sparkleshareIcon" /><img class="inlineIcon" wicket:id="forkIcon" /><img class="inlineIcon" wicket:id="ticketsIcon" /><img class="inlineIcon" wicket:id="docsIcon" /><img class="inlineIcon" wicket:id="frozenIcon" /><img class="inlineIcon" wicket:id="federatedIcon" /><img class="inlineIcon" wicket:id="accessRestrictionIcon" /></td>
+ <td><span wicket:id="repositoryLastChange">[last change]</span></td>
+ <td class="hidden-phone" style="text-align: right;padding-right:15px;"><span style="font-size:0.8em;" wicket:id="repositorySize">[repository size]</span></td>
+ <td class="rightAlign">
+ <span class="hidden-phone">
+ <span wicket:id="repositoryLinks"></span>
+ <a style="text-decoration: none;" wicket:id="syndication" wicket:message="title:gb.feed">
+ <img style="border:0px;vertical-align:middle;" src="feed_16x16.png"></img>
+ </a>
+ </span>
+ </td>
+ </wicket:fragment>
+
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java new file mode 100644 index 00000000..726af61d --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java @@ -0,0 +1,557 @@ +/*
+ * Copyright 2011 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.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.PageParameters;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.OrderByBorder;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.link.ExternalLink;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.IDataProvider;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+
+import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.SyndicationServlet;
+import com.gitblit.models.ProjectModel;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.StringUtils;
+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.EmptyRepositoryPage;
+import com.gitblit.wicket.pages.ProjectPage;
+import com.gitblit.wicket.pages.RepositoriesPage;
+import com.gitblit.wicket.pages.SummaryPage;
+import com.gitblit.wicket.pages.UserPage;
+
+public class RepositoriesPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ public RepositoriesPanel(String wicketId, final boolean showAdmin, final boolean showManagement,
+ List<RepositoryModel> models, boolean enableLinks,
+ final Map<AccessRestrictionType, String> accessRestrictionTranslations) {
+ super(wicketId);
+
+ final boolean linksActive = enableLinks;
+ final boolean showSize = GitBlit.getBoolean(Keys.web.showRepositorySizes, true);
+
+ final UserModel user = GitBlitWebSession.get().getUser();
+
+ final IDataProvider<RepositoryModel> dp;
+
+ Fragment managementLinks;
+ if (showAdmin) {
+ // user is admin
+ managementLinks = new Fragment("managementPanel", "adminLinks", this);
+ managementLinks.add(new Link<Void>("clearCache") {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onClick() {
+ GitBlit.self().resetRepositoryListCache();
+ setResponsePage(RepositoriesPage.class);
+ }
+ }.setVisible(GitBlit.getBoolean(Keys.git.cacheRepositoryList, true)));
+ managementLinks.add(new BookmarkablePageLink<Void>("newRepository", EditRepositoryPage.class));
+ 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));
+ add(managementLinks);
+ } else {
+ // user has no management permissions
+ add (new Label("managementPanel").setVisible(false));
+ }
+
+ if (GitBlit.getString(Keys.web.repositoryListType, "flat").equalsIgnoreCase("grouped")) {
+ List<RepositoryModel> rootRepositories = new ArrayList<RepositoryModel>();
+ Map<String, List<RepositoryModel>> groups = new HashMap<String, List<RepositoryModel>>();
+ for (RepositoryModel model : models) {
+ String rootPath = StringUtils.getRootPath(model.name);
+ if (StringUtils.isEmpty(rootPath)) {
+ // root repository
+ rootRepositories.add(model);
+ } else {
+ // non-root, grouped repository
+ if (!groups.containsKey(rootPath)) {
+ groups.put(rootPath, new ArrayList<RepositoryModel>());
+ }
+ groups.get(rootPath).add(model);
+ }
+ }
+ List<String> roots = new ArrayList<String>(groups.keySet());
+ Collections.sort(roots);
+
+ if (rootRepositories.size() > 0) {
+ // inject the root repositories at the top of the page
+ roots.add(0, "");
+ groups.put("", rootRepositories);
+ }
+
+ List<RepositoryModel> groupedModels = new ArrayList<RepositoryModel>();
+ for (String root : roots) {
+ List<RepositoryModel> subModels = groups.get(root);
+ ProjectModel project = GitBlit.self().getProjectModel(root);
+ GroupRepositoryModel group = new GroupRepositoryModel(project.name, subModels.size());
+ if (project != null) {
+ group.title = project.title;
+ group.description = project.description;
+ }
+ groupedModels.add(group);
+ Collections.sort(subModels);
+ groupedModels.addAll(subModels);
+ }
+ dp = new RepositoriesProvider(groupedModels);
+ } else {
+ dp = new SortableRepositoriesProvider(models);
+ }
+
+ final String baseUrl = WicketUtils.getGitblitURL(getRequest());
+ final boolean showSwatch = GitBlit.getBoolean(Keys.web.repositoryListSwatches, true);
+
+ DataView<RepositoryModel> dataView = new DataView<RepositoryModel>("row", dp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+ String currGroupName;
+
+ @Override
+ protected void onBeforeRender() {
+ super.onBeforeRender();
+ counter = 0;
+ }
+
+ public void populateItem(final Item<RepositoryModel> item) {
+ final RepositoryModel entry = item.getModelObject();
+ if (entry instanceof GroupRepositoryModel) {
+ GroupRepositoryModel groupRow = (GroupRepositoryModel) entry;
+ currGroupName = entry.name;
+ Fragment row = new Fragment("rowContent", "groupRepositoryRow", this);
+ item.add(row);
+
+ String name = groupRow.name;
+ if (name.charAt(0) == '~') {
+ // user page
+ String username = name.substring(1);
+ UserModel user = GitBlit.self().getUserModel(username);
+ row.add(new LinkPanel("groupName", null, (user == null ? username : user.getDisplayName()) + " (" + groupRow.count + ")", UserPage.class, WicketUtils.newUsernameParameter(username)));
+ row.add(new Label("groupDescription", getString("gb.personalRepositories")));
+ } else {
+ // project page
+ row.add(new LinkPanel("groupName", null, groupRow.toString(), ProjectPage.class, WicketUtils.newProjectParameter(entry.name)));
+ row.add(new Label("groupDescription", entry.description == null ? "":entry.description));
+ }
+ WicketUtils.setCssClass(item, "group");
+ // reset counter so that first row is light background
+ counter = 0;
+ return;
+ }
+ Fragment row = new Fragment("rowContent", "repositoryRow", this);
+ item.add(row);
+
+ // try to strip group name for less cluttered list
+ String repoName = entry.toString();
+ if (!StringUtils.isEmpty(currGroupName) && (repoName.indexOf('/') > -1)) {
+ repoName = repoName.substring(currGroupName.length() + 1);
+ }
+
+ // repository swatch
+ Component swatch;
+ if (entry.isBare){
+ swatch = new Label("repositorySwatch", " ").setEscapeModelStrings(false);
+ } else {
+ swatch = new Label("repositorySwatch", "!");
+ WicketUtils.setHtmlTooltip(swatch, getString("gb.workingCopyWarning"));
+ }
+ WicketUtils.setCssBackground(swatch, entry.toString());
+ row.add(swatch);
+ swatch.setVisible(showSwatch);
+
+ if (linksActive) {
+ Class<? extends BasePage> linkPage;
+ if (entry.hasCommits) {
+ // repository has content
+ linkPage = SummaryPage.class;
+ } else {
+ // new/empty repository OR proposed repository
+ linkPage = EmptyRepositoryPage.class;
+ }
+
+ PageParameters pp = WicketUtils.newRepositoryParameter(entry.name);
+ row.add(new LinkPanel("repositoryName", "list", repoName, linkPage, pp));
+ row.add(new LinkPanel("repositoryDescription", "list", entry.description,
+ linkPage, pp));
+ } else {
+ // no links like on a federation page
+ row.add(new Label("repositoryName", repoName));
+ row.add(new Label("repositoryDescription", entry.description));
+ }
+ if (entry.hasCommits) {
+ // Existing repository
+ row.add(new Label("repositorySize", entry.size).setVisible(showSize));
+ } else {
+ // New repository
+ row.add(new Label("repositorySize", "<span class='empty'>(" + getString("gb.empty") + ")</span>")
+ .setEscapeModelStrings(false));
+ }
+
+ if (entry.isSparkleshared()) {
+ row.add(WicketUtils.newImage("sparkleshareIcon", "star_16x16.png",
+ getString("gb.isSparkleshared")));
+ } else {
+ row.add(WicketUtils.newClearPixel("sparkleshareIcon").setVisible(false));
+ }
+
+ if (entry.isFork()) {
+ row.add(WicketUtils.newImage("forkIcon", "commit_divide_16x16.png",
+ getString("gb.isFork")));
+ } else {
+ row.add(WicketUtils.newClearPixel("forkIcon").setVisible(false));
+ }
+
+ if (entry.useTickets) {
+ row.add(WicketUtils.newImage("ticketsIcon", "bug_16x16.png",
+ getString("gb.tickets")));
+ } else {
+ row.add(WicketUtils.newBlankImage("ticketsIcon"));
+ }
+
+ if (entry.useDocs) {
+ row.add(WicketUtils
+ .newImage("docsIcon", "book_16x16.png", getString("gb.docs")));
+ } else {
+ row.add(WicketUtils.newBlankImage("docsIcon"));
+ }
+
+ if (entry.isFrozen) {
+ row.add(WicketUtils.newImage("frozenIcon", "cold_16x16.png",
+ getString("gb.isFrozen")));
+ } else {
+ row.add(WicketUtils.newClearPixel("frozenIcon").setVisible(false));
+ }
+
+ if (entry.isFederated) {
+ row.add(WicketUtils.newImage("federatedIcon", "federated_16x16.png",
+ getString("gb.isFederated")));
+ } else {
+ row.add(WicketUtils.newClearPixel("federatedIcon").setVisible(false));
+ }
+ switch (entry.accessRestriction) {
+ case NONE:
+ row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));
+ break;
+ case PUSH:
+ row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png",
+ accessRestrictionTranslations.get(entry.accessRestriction)));
+ break;
+ case CLONE:
+ row.add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png",
+ accessRestrictionTranslations.get(entry.accessRestriction)));
+ break;
+ case VIEW:
+ row.add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png",
+ accessRestrictionTranslations.get(entry.accessRestriction)));
+ break;
+ default:
+ row.add(WicketUtils.newBlankImage("accessRestrictionIcon"));
+ }
+
+ String owner = "";
+ if (!ArrayUtils.isEmpty(entry.owners)) {
+ // display first owner
+ for (String username : entry.owners) {
+ UserModel ownerModel = GitBlit.self().getUserModel(username);
+ if (ownerModel != null) {
+ owner = ownerModel.getDisplayName();
+ break;
+ }
+ }
+ if (entry.owners.size() > 1) {
+ owner += ", ...";
+ }
+ }
+ Label ownerLabel = new Label("repositoryOwner", owner);
+ WicketUtils.setHtmlTooltip(ownerLabel, ArrayUtils.toString(entry.owners));
+ row.add(ownerLabel);
+
+ String lastChange;
+ if (entry.lastChange.getTime() == 0) {
+ lastChange = "--";
+ } else {
+ lastChange = getTimeUtils().timeAgo(entry.lastChange);
+ }
+ Label lastChangeLabel = new Label("repositoryLastChange", lastChange);
+ row.add(lastChangeLabel);
+ WicketUtils.setCssClass(lastChangeLabel, getTimeUtils().timeAgoCss(entry.lastChange));
+
+ boolean showOwner = user != null && entry.isOwner(user.username);
+ boolean myPersonalRepository = showOwner && entry.isUsersPersonalRepository(user.username);
+ if (showAdmin || myPersonalRepository) {
+ Fragment repositoryLinks = new Fragment("repositoryLinks",
+ "repositoryAdminLinks", this);
+ repositoryLinks.add(new BookmarkablePageLink<Void>("editRepository",
+ EditRepositoryPage.class, WicketUtils
+ .newRepositoryParameter(entry.name)));
+ Link<Void> deleteLink = new Link<Void>("deleteRepository") {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onClick() {
+ if (GitBlit.self().deleteRepositoryModel(entry)) {
+ if (dp instanceof SortableRepositoriesProvider) {
+ info(MessageFormat.format(getString("gb.repositoryDeleted"), entry));
+ ((SortableRepositoriesProvider) dp).remove(entry);
+ } else {
+ setResponsePage(getPage().getClass(), getPage().getPageParameters());
+ }
+ } else {
+ error(MessageFormat.format(getString("gb.repositoryDeleteFailed"), entry));
+ }
+ }
+ };
+ deleteLink.add(new JavascriptEventConfirmation("onclick", MessageFormat.format(
+ getString("gb.deleteRepository"), entry)));
+ repositoryLinks.add(deleteLink);
+ row.add(repositoryLinks);
+ } else if (showOwner) {
+ Fragment repositoryLinks = new Fragment("repositoryLinks",
+ "repositoryOwnerLinks", this);
+ repositoryLinks.add(new BookmarkablePageLink<Void>("editRepository",
+ EditRepositoryPage.class, WicketUtils
+ .newRepositoryParameter(entry.name)));
+ row.add(repositoryLinks);
+ } else {
+ row.add(new Label("repositoryLinks"));
+ }
+ row.add(new ExternalLink("syndication", SyndicationServlet.asLink(baseUrl,
+ entry.name, null, 0)).setVisible(linksActive));
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(dataView);
+
+ if (dp instanceof SortableDataProvider<?>) {
+ // add sortable header
+ SortableDataProvider<?> sdp = (SortableDataProvider<?>) dp;
+ Fragment fragment = new Fragment("headerContent", "flatRepositoryHeader", this);
+ fragment.add(newSort("orderByRepository", SortBy.repository, sdp, dataView));
+ fragment.add(newSort("orderByDescription", SortBy.description, sdp, dataView));
+ fragment.add(newSort("orderByOwner", SortBy.owner, sdp, dataView));
+ fragment.add(newSort("orderByDate", SortBy.date, sdp, dataView));
+ add(fragment);
+ } else {
+ // not sortable
+ Fragment fragment = new Fragment("headerContent", "groupRepositoryHeader", this);
+ add(fragment);
+ }
+ }
+
+ private static class GroupRepositoryModel extends RepositoryModel {
+
+ private static final long serialVersionUID = 1L;
+
+ int count;
+ String title;
+
+ GroupRepositoryModel(String name, int count) {
+ super(name, "", "", new Date(0));
+ this.count = count;
+ }
+
+ @Override
+ public String toString() {
+ return (StringUtils.isEmpty(title) ? name : title) + " (" + count + ")";
+ }
+ }
+
+ protected enum SortBy {
+ repository, description, owner, date;
+ }
+
+ protected OrderByBorder newSort(String wicketId, SortBy field, SortableDataProvider<?> dp,
+ final DataView<?> dataView) {
+ return new OrderByBorder(wicketId, field.name(), dp) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void onSortChanged() {
+ dataView.setCurrentPage(0);
+ }
+ };
+ }
+
+ private static class RepositoriesProvider extends ListDataProvider<RepositoryModel> {
+
+ private static final long serialVersionUID = 1L;
+
+ public RepositoriesProvider(List<RepositoryModel> list) {
+ super(list);
+ }
+
+ @Override
+ public List<RepositoryModel> getData() {
+ return super.getData();
+ }
+
+ public void remove(RepositoryModel model) {
+ int index = getData().indexOf(model);
+ RepositoryModel groupModel = null;
+ if (index == (getData().size() - 1)) {
+ // last element
+ if (index > 0) {
+ // previous element is group header, then this is last
+ // repository in group. remove group too.
+ if (getData().get(index - 1) instanceof GroupRepositoryModel) {
+ groupModel = getData().get(index - 1);
+ }
+ }
+ } else if (index < (getData().size() - 1)) {
+ // not last element. check next element for group match.
+ if (getData().get(index - 1) instanceof GroupRepositoryModel
+ && getData().get(index + 1) instanceof GroupRepositoryModel) {
+ // repository is sandwiched by group headers so this
+ // repository is the only element in the group. remove
+ // group.
+ groupModel = getData().get(index - 1);
+ }
+ }
+
+ if (groupModel == null) {
+ // Find the group and decrement the count
+ for (int i = index; i >= 0; i--) {
+ if (getData().get(i) instanceof GroupRepositoryModel) {
+ ((GroupRepositoryModel) getData().get(i)).count--;
+ break;
+ }
+ }
+ } else {
+ // Remove the group header
+ getData().remove(groupModel);
+ }
+
+ getData().remove(model);
+ }
+ }
+
+ private static class SortableRepositoriesProvider extends SortableDataProvider<RepositoryModel> {
+
+ private static final long serialVersionUID = 1L;
+
+ private List<RepositoryModel> list;
+
+ protected SortableRepositoriesProvider(List<RepositoryModel> list) {
+ this.list = list;
+ setSort(SortBy.date.name(), false);
+ }
+
+ public void remove(RepositoryModel model) {
+ list.remove(model);
+ }
+
+ @Override
+ public int size() {
+ if (list == null) {
+ return 0;
+ }
+ return list.size();
+ }
+
+ @Override
+ public IModel<RepositoryModel> model(RepositoryModel header) {
+ return new Model<RepositoryModel>(header);
+ }
+
+ @Override
+ public Iterator<RepositoryModel> iterator(int first, int count) {
+ SortParam sp = getSort();
+ String prop = sp.getProperty();
+ final boolean asc = sp.isAscending();
+
+ if (prop == null || prop.equals(SortBy.date.name())) {
+ Collections.sort(list, new Comparator<RepositoryModel>() {
+ @Override
+ public int compare(RepositoryModel o1, RepositoryModel o2) {
+ if (asc) {
+ return o1.lastChange.compareTo(o2.lastChange);
+ }
+ return o2.lastChange.compareTo(o1.lastChange);
+ }
+ });
+ } else if (prop.equals(SortBy.repository.name())) {
+ Collections.sort(list, new Comparator<RepositoryModel>() {
+ @Override
+ public int compare(RepositoryModel o1, RepositoryModel o2) {
+ if (asc) {
+ return o1.name.compareTo(o2.name);
+ }
+ return o2.name.compareTo(o1.name);
+ }
+ });
+ } else if (prop.equals(SortBy.owner.name())) {
+ Collections.sort(list, new Comparator<RepositoryModel>() {
+ @Override
+ public int compare(RepositoryModel o1, RepositoryModel o2) {
+ String own1 = ArrayUtils.toString(o1.owners);
+ String own2 = ArrayUtils.toString(o2.owners);
+ if (asc) {
+ return own1.compareTo(own2);
+ }
+ return own2.compareTo(own1);
+ }
+ });
+ } else if (prop.equals(SortBy.description.name())) {
+ Collections.sort(list, new Comparator<RepositoryModel>() {
+ @Override
+ public int compare(RepositoryModel o1, RepositoryModel o2) {
+ if (asc) {
+ return o1.description.compareTo(o2.description);
+ }
+ return o2.description.compareTo(o1.description);
+ }
+ });
+ }
+ return list.subList(first, first + count).iterator();
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.html b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.html new file mode 100644 index 00000000..d7c76f13 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.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">
+
+<wicket:panel>
+ <span wicket:id="repositoryUrl" style="color: blue;">[repository url]</span><span class="hidden-phone hidden-tablet" wicket:id="copyFunction"></span>
+
+ <!-- Plain JavaScript manual copy & paste -->
+ <wicket:fragment wicket:id="jsPanel">
+ <span style="vertical-align:baseline;">
+ <img wicket:id="copyIcon" wicket:message="title:gb.copyToClipboard"></img>
+ </span>
+ </wicket:fragment>
+
+ <!-- flash-based button-press copy & paste -->
+ <wicket:fragment wicket:id="clippyPanel">
+ <object wicket:message="title:gb.copyToClipboard" style="vertical-align:middle;"
+ wicket:id="clippy"
+ width="14"
+ height="14"
+ bgcolor="#ffffff"
+ quality="high"
+ wmode="transparent"
+ scale="noscale"
+ allowScriptAccess="always"></object>
+ </wicket:fragment>
+</wicket:panel>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java new file mode 100644 index 00000000..58df028b --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java @@ -0,0 +1,51 @@ +/*
+ * Copyright 2011 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.image.ContextImage;
+import org.apache.wicket.markup.html.panel.Fragment;
+
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+
+public class RepositoryUrlPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ public RepositoryUrlPanel(String wicketId, String url) {
+ super(wicketId);
+ add(new Label("repositoryUrl", url));
+ if (GitBlit.getBoolean(Keys.web.allowFlashCopyToClipboard, true)) {
+ // clippy: flash-based copy & paste
+ Fragment fragment = new Fragment("copyFunction", "clippyPanel", this);
+ String baseUrl = WicketUtils.getGitblitURL(getRequest());
+ ShockWaveComponent clippy = new ShockWaveComponent("clippy", baseUrl + "/clippy.swf");
+ clippy.setValue("flashVars", "text=" + StringUtils.encodeURL(url));
+ fragment.add(clippy);
+ add(fragment);
+ } else {
+ // javascript: manual copy & paste with modal browser prompt dialog
+ Fragment fragment = new Fragment("copyFunction", "jsPanel", this);
+ ContextImage img = WicketUtils.newImage("copyIcon", "clippy.png");
+ img.add(new JavascriptTextPrompt("onclick", "Copy to Clipboard (Ctrl+C, Enter)", url));
+ fragment.add(img);
+ add(fragment);
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/SearchPanel.html b/src/main/java/com/gitblit/wicket/panels/SearchPanel.html new file mode 100644 index 00000000..74af71c5 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/SearchPanel.html @@ -0,0 +1,33 @@ +<!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>
+
+ <!-- header -->
+ <div wicket:id="commitHeader">[search header]</div>
+
+ <!-- header -->
+ <div style="margin-top:10px;font-weight:bold;" class="header"><wicket:message key="gb.search"></wicket:message>: <span wicket:id="searchString">[search string]</span> (<span wicket:id="searchType">[search type]</span>)</div>
+ <table class="pretty">
+ <tbody>
+ <tr wicket:id="commit">
+ <td class="date"><span wicket:id="commitDate">[commit date]</span></td>
+ <td class="author"><span wicket:id="commitAuthor">[commit author]</span></td>
+ <td class="icon"><img wicket:id="commitIcon" /></td>
+ <td class="message"><table class="nestedTable"><tr><td><span style="vertical-align:middle;" wicket:id="commitShortMessage">[commit short message]</span></td><td><div style="text-align:right;" wicket:id="commitRefs">[commit refs]</div></td></tr></table></td>
+ <td class="rightAlign">
+ <span class="hidden-phone link">
+ <a wicket:id="commit"><wicket:message key="gb.commit"></wicket:message></a> | <a wicket:id="commitdiff"><wicket:message key="gb.commitdiff"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a>
+ </span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/SearchPanel.java b/src/main/java/com/gitblit/wicket/panels/SearchPanel.java new file mode 100644 index 00000000..9d38ab09 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/SearchPanel.java @@ -0,0 +1,142 @@ +/*
+ * Copyright 2011 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.Date;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+
+import com.gitblit.Constants;
+import com.gitblit.GitBlit;
+import com.gitblit.Keys;
+import com.gitblit.models.RefModel;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.CommitDiffPage;
+import com.gitblit.wicket.pages.CommitPage;
+import com.gitblit.wicket.pages.GitSearchPage;
+import com.gitblit.wicket.pages.TreePage;
+
+public class SearchPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ private boolean hasMore;
+
+ public SearchPanel(String wicketId, final String repositoryName, final String objectId,
+ final String value, Constants.SearchType searchType, Repository r, int limit, int pageOffset,
+ boolean showRemoteRefs) {
+ super(wicketId);
+ boolean pageResults = limit <= 0;
+ int itemsPerPage = GitBlit.getInteger(Keys.web.itemsPerPage, 50);
+ if (itemsPerPage <= 1) {
+ itemsPerPage = 50;
+ }
+
+ RevCommit commit = JGitUtils.getCommit(r, objectId);
+
+ final Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(r, showRemoteRefs);
+ List<RevCommit> commits;
+ if (pageResults) {
+ // Paging result set
+ commits = JGitUtils.searchRevlogs(r, objectId, value, searchType, pageOffset
+ * itemsPerPage, itemsPerPage);
+ } else {
+ // Fixed size result set
+ commits = JGitUtils.searchRevlogs(r, objectId, value, searchType, 0, limit);
+ }
+
+ // inaccurate way to determine if there are more commits.
+ // works unless commits.size() represents the exact end.
+ hasMore = commits.size() >= itemsPerPage;
+
+ // header
+ add(new CommitHeaderPanel("commitHeader", repositoryName, commit));
+
+ add(new Label("searchString", value));
+ add(new Label("searchType", searchType.toString()));
+
+ ListDataProvider<RevCommit> dp = new ListDataProvider<RevCommit>(commits);
+ DataView<RevCommit> searchView = new DataView<RevCommit>("commit", dp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+
+ public void populateItem(final Item<RevCommit> item) {
+ final RevCommit entry = item.getModelObject();
+ final Date date = JGitUtils.getCommitDate(entry);
+
+ item.add(WicketUtils.createDateLabel("commitDate", date, getTimeZone(), getTimeUtils()));
+
+ // author search link
+ String author = entry.getAuthorIdent().getName();
+ LinkPanel authorLink = new LinkPanel("commitAuthor", "list", author,
+ GitSearchPage.class, WicketUtils.newSearchParameter(repositoryName, objectId,
+ author, Constants.SearchType.AUTHOR));
+ setPersonSearchTooltip(authorLink, author, Constants.SearchType.AUTHOR);
+ item.add(authorLink);
+
+ // merge icon
+ if (entry.getParentCount() > 1) {
+ item.add(WicketUtils.newImage("commitIcon", "commit_merge_16x16.png"));
+ } else {
+ item.add(WicketUtils.newBlankImage("commitIcon"));
+ }
+
+ String shortMessage = entry.getShortMessage();
+ String trimmedMessage = shortMessage;
+ if (allRefs.containsKey(entry.getId())) {
+ trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG_REFS);
+ } else {
+ trimmedMessage = StringUtils.trimString(shortMessage, Constants.LEN_SHORTLOG);
+ }
+ LinkPanel shortlog = new LinkPanel("commitShortMessage", "list subject",
+ trimmedMessage, CommitPage.class, WicketUtils.newObjectParameter(
+ repositoryName, entry.getName()));
+ if (!shortMessage.equals(trimmedMessage)) {
+ WicketUtils.setHtmlTooltip(shortlog, shortMessage);
+ }
+ item.add(shortlog);
+
+ item.add(new RefsPanel("commitRefs", repositoryName, entry, allRefs));
+
+ item.add(new BookmarkablePageLink<Void>("commit", CommitPage.class, WicketUtils
+ .newObjectParameter(repositoryName, entry.getName())));
+ item.add(new BookmarkablePageLink<Void>("commitdiff", CommitDiffPage.class,
+ WicketUtils.newObjectParameter(repositoryName, entry.getName())));
+ item.add(new BookmarkablePageLink<Void>("tree", TreePage.class, WicketUtils
+ .newObjectParameter(repositoryName, entry.getName())));
+
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(searchView);
+ }
+
+ public boolean hasMore() {
+ return hasMore;
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/ShockWaveComponent.java b/src/main/java/com/gitblit/wicket/panels/ShockWaveComponent.java new file mode 100644 index 00000000..fa989453 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/ShockWaveComponent.java @@ -0,0 +1,205 @@ +/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.wicket.Response;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.MarkupStream;
+import org.apache.wicket.util.value.IValueMap;
+
+/**
+ * https://cwiki.apache.org/WICKET/object-container-adding-flash-to-a-wicket-application.html
+ *
+ * @author Jan Kriesten
+ * @author manuelbarzi
+ * @author James Moger
+ *
+ */
+public class ShockWaveComponent extends ObjectContainer {
+ private static final long serialVersionUID = 1L;
+
+ private static final String CONTENTTYPE = "application/x-shockwave-flash";
+ private static final String CLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
+ private static final String CODEBASE = "http://fpdownload.adobe.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0";
+
+ // valid attributes
+ private static final List<String> attributeNames = Arrays.asList(new String[] { "classid",
+ "width", "height", "codebase", "align", "base", "data", "flashvars" });
+ // valid parameters
+ private static final List<String> parameterNames = Arrays.asList(new String[] { "devicefont",
+ "movie", "play", "loop", "quality", "bgcolor", "scale", "salign", "menu", "wmode",
+ "allowscriptaccess", "seamlesstabbing", "flashvars" });
+
+ // combined options (to iterate over them)
+ private static final List<String> optionNames = new ArrayList<String>(attributeNames.size()
+ + parameterNames.size());
+ static {
+ optionNames.addAll(attributeNames);
+ optionNames.addAll(parameterNames);
+ }
+
+ private Map<String, String> attributes;
+ private Map<String, String> parameters;
+
+ public ShockWaveComponent(String id) {
+ super(id);
+
+ attributes = new HashMap<String, String>();
+ parameters = new HashMap<String, String>();
+ }
+
+ public ShockWaveComponent(String id, String movie) {
+ this(id);
+ setValue("movie", movie);
+ }
+
+ public ShockWaveComponent(String id, String movie, String width, String height) {
+ this(id);
+
+ setValue("movie", movie);
+ setValue("width", width);
+ setValue("height", height);
+ }
+
+ public void setValue(String name, String value) {
+ // IE and other browsers handle movie/data differently. So movie is used
+ // for IE, whereas
+ // data is used for all other browsers. The class uses movie parameter
+ // to handle url and
+ // puts the values to the maps depending on the browser information
+ String parameter = name.toLowerCase();
+ if ("data".equals(parameter))
+ parameter = "movie";
+
+ if ("movie".equals(parameter) && !getClientProperties().isBrowserInternetExplorer())
+ attributes.put("data", value);
+
+ if (attributeNames.contains(parameter))
+ attributes.put(parameter, value);
+ else if (parameterNames.contains(parameter))
+ parameters.put(parameter, value);
+ }
+
+ public String getValue(String name) {
+ String parameter = name.toLowerCase();
+ String value = null;
+
+ if ("data".equals(parameter)) {
+ if (getClientProperties().isBrowserInternetExplorer())
+ return null;
+ parameter = "movie";
+ }
+
+ if (attributeNames.contains(parameter))
+ value = attributes.get(parameter);
+ else if (parameterNames.contains(parameter))
+ value = parameters.get(parameter);
+
+ // special treatment of movie to resolve to the url
+ if (value != null && parameter.equals("movie"))
+ value = resolveResource(value);
+
+ return value;
+ }
+
+ public void onComponentTag(ComponentTag tag) {
+ // get options from the markup
+ IValueMap valueMap = tag.getAttributes();
+
+ // Iterate over valid options
+ for (String s : optionNames) {
+ if (valueMap.containsKey(s)) {
+ // if option isn't set programmatically, set value from markup
+ if (!attributes.containsKey(s) && !parameters.containsKey(s))
+ setValue(s, valueMap.getString(s));
+ // remove attribute - they are added in super.onComponentTag()
+ // to
+ // the right place as attribute or param
+ valueMap.remove(s);
+ }
+ }
+
+ super.onComponentTag(tag);
+ }
+
+ public void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) {
+
+ super.onComponentTagBody(markupStream, openTag);
+
+ Response response = getResponse();
+
+ // add all object's parameters in embed tag too:
+ response.write("<embed");
+ addParameter(response, "type", CONTENTTYPE);
+ for (String name : getParameterNames()) {
+ String value = getValue(name);
+ if (value != null) {
+ name = "movie".equals(name) ? "src" : name;
+ addParameter(response, name, value);
+ }
+ }
+ for (String name : getAttributeNames()) {
+ if ("width".equals(name) || "height".equals(name)) {
+ String value = getValue(name);
+ if (value != null) {
+ addParameter(response, name, value);
+ }
+ }
+ }
+ response.write(" />\n");
+
+ }
+
+ private void addParameter(Response response, String name, String value) {
+ response.write(" ");
+ response.write(name);
+ response.write("=\"");
+ response.write(value);
+ response.write("\"");
+ }
+
+ @Override
+ protected String getClsid() {
+ return CLSID;
+ }
+
+ @Override
+ protected String getCodebase() {
+ return CODEBASE;
+ }
+
+ @Override
+ protected String getContentType() {
+ return CONTENTTYPE;
+ }
+
+ @Override
+ protected List<String> getAttributeNames() {
+ return attributeNames;
+ }
+
+ @Override
+ protected List<String> getParameterNames() {
+ return parameterNames;
+ }
+}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/TagsPanel.html b/src/main/java/com/gitblit/wicket/panels/TagsPanel.html new file mode 100644 index 00000000..ba9f15dd --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/TagsPanel.html @@ -0,0 +1,51 @@ +<!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>
+
+ <!-- tags -->
+ <div class="header"><i class="icon-tags" style="vertical-align: middle;"></i> <b><span wicket:id="header">[tags header]</span></b></div>
+ <table class="pretty">
+ <tbody>
+ <tr wicket:id="tag">
+ <td class="date"><span wicket:id="tagDate">[tag date]</span></td>
+ <td><b><span wicket:id="tagName">[tag name]</span></b></td>
+ <td class="hidden-phone icon"><img wicket:id="tagIcon" /></td>
+ <td class="hidden-phone"><span wicket:id="tagDescription">[tag description]</span></td>
+ <td class="hidden-phone rightAlign">
+ <span wicket:id="tagLinks"></span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <div wicket:id="allTags">[all tags]</div>
+
+ <!-- annotated tag links -->
+ <wicket:fragment wicket:id="annotatedLinks">
+ <span class="link">
+ <a wicket:id="tag"><wicket:message key="gb.tag"></wicket:message></a> | <a wicket:id="commit"><wicket:message key="gb.commit"></wicket:message></a> | <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a>
+ </span>
+ </wicket:fragment>
+
+ <!-- lightweight tag links -->
+ <wicket:fragment wicket:id="lightweightLinks">
+ <span class="link">
+ <a wicket:id="commit"><wicket:message key="gb.commit"></wicket:message></a> | <a wicket:id="log"><wicket:message key="gb.log"></wicket:message></a>
+ </span>
+ </wicket:fragment>
+
+ <!-- blob tag links -->
+ <wicket:fragment wicket:id="blobLinks">
+ <span class="link">
+ <a wicket:id="tag"><wicket:message key="gb.tag"></wicket:message></a> | <a wicket:id="blob"><wicket:message key="gb.blob"></wicket:message></a> | <a wicket:id="raw"><wicket:message key="gb.raw"></wicket:message></a>
+ </span>
+ </wicket:fragment>
+
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/TagsPanel.java b/src/main/java/com/gitblit/wicket/panels/TagsPanel.java new file mode 100644 index 00000000..2bee6a60 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/TagsPanel.java @@ -0,0 +1,170 @@ +/*
+ * Copyright 2011 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.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+import org.apache.wicket.model.StringResourceModel;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+
+import com.gitblit.models.RefModel;
+import com.gitblit.utils.JGitUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.BlobPage;
+import com.gitblit.wicket.pages.CommitPage;
+import com.gitblit.wicket.pages.LogPage;
+import com.gitblit.wicket.pages.RawPage;
+import com.gitblit.wicket.pages.RepositoryPage;
+import com.gitblit.wicket.pages.TagPage;
+import com.gitblit.wicket.pages.TagsPage;
+import com.gitblit.wicket.pages.TreePage;
+
+public class TagsPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ private final boolean hasTags;
+
+ public TagsPanel(String wicketId, final String repositoryName, Repository r, final int maxCount) {
+ super(wicketId);
+
+ // header
+ List<RefModel> tags = JGitUtils.getTags(r, false, maxCount);
+ if (maxCount > 0) {
+ // summary page
+ // show tags page link
+ add(new LinkPanel("header", "title", new StringResourceModel("gb.tags", this, null),
+ TagsPage.class, WicketUtils.newRepositoryParameter(repositoryName)));
+ } else {
+ // tags page
+ add(new Label("header", new StringResourceModel("gb.tags", this, null)));
+ }
+
+ ListDataProvider<RefModel> tagsDp = new ListDataProvider<RefModel>(tags);
+ DataView<RefModel> tagView = new DataView<RefModel>("tag", tagsDp) {
+ private static final long serialVersionUID = 1L;
+ int counter;
+
+ public void populateItem(final Item<RefModel> item) {
+ RefModel entry = item.getModelObject();
+
+ item.add(WicketUtils.createDateLabel("tagDate", entry.getDate(), getTimeZone(), getTimeUtils()));
+
+ Class<? extends RepositoryPage> linkClass;
+ switch (entry.getReferencedObjectType()) {
+ case Constants.OBJ_BLOB:
+ linkClass = BlobPage.class;
+ break;
+ case Constants.OBJ_TREE:
+ linkClass = TreePage.class;
+ break;
+ case Constants.OBJ_COMMIT:
+ default:
+ linkClass = CommitPage.class;
+ break;
+ }
+ item.add(new LinkPanel("tagName", "list name", entry.displayName, linkClass,
+ WicketUtils.newObjectParameter(repositoryName, entry
+ .getReferencedObjectId().getName())));
+
+ // workaround for RevTag returning a lengthy shortlog. :(
+ String message = StringUtils.trimString(entry.getShortMessage(),
+ com.gitblit.Constants.LEN_SHORTLOG);
+
+ if (linkClass.equals(BlobPage.class)) {
+ // Blob Tag Object
+ item.add(WicketUtils.newImage("tagIcon", "file_16x16.png"));
+ item.add(new LinkPanel("tagDescription", "list", message, TagPage.class,
+ WicketUtils.newObjectParameter(repositoryName, entry.getObjectId()
+ .getName())));
+
+ Fragment fragment = new Fragment("tagLinks", "blobLinks", this);
+ fragment.add(new BookmarkablePageLink<Void>("tag", TagPage.class, WicketUtils
+ .newObjectParameter(repositoryName, entry.getObjectId().getName()))
+ .setEnabled(entry.isAnnotatedTag()));
+
+ fragment.add(new BookmarkablePageLink<Void>("blob", linkClass, WicketUtils
+ .newObjectParameter(repositoryName, entry.getReferencedObjectId()
+ .getName())));
+
+ fragment.add(new BookmarkablePageLink<Void>("raw", RawPage.class, WicketUtils
+ .newObjectParameter(repositoryName, entry.getReferencedObjectId()
+ .getName())));
+ item.add(fragment);
+ } else {
+ // TODO Tree Tag Object
+ // Standard Tag Object
+ if (entry.isAnnotatedTag()) {
+ item.add(WicketUtils.newImage("tagIcon", "tag_16x16.png"));
+ item.add(new LinkPanel("tagDescription", "list", message, TagPage.class,
+ WicketUtils.newObjectParameter(repositoryName, entry.getObjectId()
+ .getName())));
+
+ Fragment fragment = new Fragment("tagLinks", "annotatedLinks", this);
+ fragment.add(new BookmarkablePageLink<Void>("tag", TagPage.class,
+ WicketUtils.newObjectParameter(repositoryName, entry.getObjectId()
+ .getName())).setEnabled(entry.isAnnotatedTag()));
+
+ fragment.add(new BookmarkablePageLink<Void>("commit", linkClass,
+ WicketUtils.newObjectParameter(repositoryName, entry
+ .getReferencedObjectId().getName())));
+
+ fragment.add(new BookmarkablePageLink<Void>("log", LogPage.class,
+ WicketUtils.newObjectParameter(repositoryName, entry.getName())));
+ item.add(fragment);
+ } else {
+ item.add(WicketUtils.newBlankImage("tagIcon"));
+ item.add(new LinkPanel("tagDescription", "list", message, CommitPage.class,
+ WicketUtils.newObjectParameter(repositoryName, entry.getObjectId()
+ .getName())));
+ Fragment fragment = new Fragment("tagLinks", "lightweightLinks", this);
+ fragment.add(new BookmarkablePageLink<Void>("commit", CommitPage.class,
+ WicketUtils.newObjectParameter(repositoryName, entry
+ .getReferencedObjectId().getName())));
+ fragment.add(new BookmarkablePageLink<Void>("log", LogPage.class,
+ WicketUtils.newObjectParameter(repositoryName, entry.getName())));
+ item.add(fragment);
+ }
+ }
+
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(tagView);
+ if (tags.size() < maxCount || maxCount <= 0) {
+ add(new Label("allTags", "").setVisible(false));
+ } else {
+ add(new LinkPanel("allTags", "link", new StringResourceModel("gb.allTags", this, null),
+ TagsPage.class, WicketUtils.newRepositoryParameter(repositoryName)));
+ }
+
+ hasTags = tags.size() > 0;
+ }
+
+ public TagsPanel hideIfEmpty() {
+ setVisible(hasTags);
+ return this;
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/TeamsPanel.html b/src/main/java/com/gitblit/wicket/panels/TeamsPanel.html new file mode 100644 index 00000000..ff689292 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/TeamsPanel.html @@ -0,0 +1,48 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<body>
+<wicket:panel>
+
+ <div wicket:id="adminPanel">[admin links]</div>
+
+ <table class="repositories">
+ <tr>
+ <th class="left">
+ <img style="vertical-align: middle; border: 1px solid #888; background-color: white;" src="users_16x16.png"/>
+ <wicket:message key="gb.teams">[teams]</wicket:message>
+ </th>
+ <th class="hidden-phone" style="width:140px;"><wicket:message key="gb.teamMembers">[team members]</wicket:message></th>
+ <th class="hidden-phone" style="width:100px;"><wicket:message key="gb.repositories">[repositories]</wicket:message></th>
+ <th style="width:80px;" class="right"></th>
+ </tr>
+ <tbody>
+ <tr wicket:id="teamRow">
+ <td class="left" ><div class="list" wicket:id="teamname">[teamname]</div></td>
+ <td class="hidden-phone left" ><div class="list" wicket:id="members">[members]</div></td>
+ <td class="hidden-phone left" ><div class="list" wicket:id="repositories">[repositories]</div></td>
+ <td class="rightAlign"><span wicket:id="teamLinks"></span></td>
+ </tr>
+ </tbody>
+ </table>
+
+ <wicket:fragment wicket:id="adminLinks">
+ <!-- page nav links -->
+ <div class="admin_nav">
+ <a class="btn-small" wicket:id="newTeam" style="padding-right:0px;">
+ <i class="icon icon-plus-sign"></i>
+ <wicket:message key="gb.newTeam"></wicket:message>
+ </a>
+ </div>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="teamAdminLinks">
+ <span class="link"><a wicket:id="editTeam"><wicket:message key="gb.edit">[edit]</wicket:message></a> | <a wicket:id="deleteTeam"><wicket:message key="gb.delete">[delete]</wicket:message></a></span>
+ </wicket:fragment>
+
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/TeamsPanel.java b/src/main/java/com/gitblit/wicket/panels/TeamsPanel.java new file mode 100644 index 00000000..b76388b3 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/TeamsPanel.java @@ -0,0 +1,96 @@ +/*
+ * Copyright 2011 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.List;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.GitBlit;
+import com.gitblit.models.TeamModel;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.EditTeamPage;
+
+public class TeamsPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ public TeamsPanel(String wicketId, final boolean showAdmin) {
+ super(wicketId);
+
+ Fragment adminLinks = new Fragment("adminPanel", "adminLinks", this);
+ adminLinks.add(new BookmarkablePageLink<Void>("newTeam", EditTeamPage.class));
+ add(adminLinks.setVisible(showAdmin && GitBlit.self().supportsTeamMembershipChanges(null)));
+
+ final List<TeamModel> teams = GitBlit.self().getAllTeams();
+ DataView<TeamModel> teamsView = new DataView<TeamModel>("teamRow",
+ new ListDataProvider<TeamModel>(teams)) {
+ private static final long serialVersionUID = 1L;
+ private int counter;
+
+ @Override
+ protected void onBeforeRender() {
+ super.onBeforeRender();
+ counter = 0;
+ }
+
+ public void populateItem(final Item<TeamModel> item) {
+ final TeamModel entry = item.getModelObject();
+ LinkPanel editLink = new LinkPanel("teamname", "list", entry.name,
+ EditTeamPage.class, WicketUtils.newTeamnameParameter(entry.name));
+ WicketUtils.setHtmlTooltip(editLink, getString("gb.edit") + " " + entry.name);
+ item.add(editLink);
+ item.add(new Label("members", entry.users.size() > 0 ? ("" + entry.users.size())
+ : ""));
+ item.add(new Label("repositories",
+ entry.repositories.size() > 0 ? ("" + entry.repositories.size()) : ""));
+ Fragment teamLinks = new Fragment("teamLinks", "teamAdminLinks", this);
+ teamLinks.add(new BookmarkablePageLink<Void>("editTeam", EditTeamPage.class,
+ WicketUtils.newTeamnameParameter(entry.name)));
+ Link<Void> deleteLink = new Link<Void>("deleteTeam") {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onClick() {
+ if (GitBlit.self().deleteTeam(entry.name)) {
+ teams.remove(entry);
+ info(MessageFormat.format("Team ''{0}'' deleted.", entry.name));
+ } else {
+ error(MessageFormat
+ .format("Failed to delete team ''{0}''!", entry.name));
+ }
+ }
+ };
+ deleteLink.add(new JavascriptEventConfirmation("onclick", MessageFormat.format(
+ "Delete team \"{0}\"?", entry.name)));
+ teamLinks.add(deleteLink);
+ item.add(teamLinks);
+
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(teamsView.setVisible(showAdmin));
+ }
+}
diff --git a/src/main/java/com/gitblit/wicket/panels/UsersPanel.html b/src/main/java/com/gitblit/wicket/panels/UsersPanel.html new file mode 100644 index 00000000..80159610 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/UsersPanel.html @@ -0,0 +1,54 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
+ xml:lang="en"
+ lang="en">
+
+<body>
+<wicket:panel>
+
+ <div wicket:id="adminPanel">[admin links]</div>
+
+ <table class="repositories">
+ <tr>
+ <th class="left">
+ <img style="vertical-align: middle; border: 1px solid #888; background-color: white;" src="user_16x16.png"/>
+ <wicket:message key="gb.users">[users]</wicket:message>
+ </th>
+ <th class="hidden-phone hidden-tablet left"><wicket:message key="gb.displayName">[display name]</wicket:message></th>
+ <th class="hidden-phone hidden-tablet left"><wicket:message key="gb.emailAddress">[email address]</wicket:message></th>
+ <th class="hidden-phone" style="width:140px;"><wicket:message key="gb.type">[type]</wicket:message></th>
+ <th class="hidden-phone" style="width:140px;"><wicket:message key="gb.teamMemberships">[team memberships]</wicket:message></th>
+ <th class="hidden-phone" style="width:100px;"><wicket:message key="gb.repositories">[repositories]</wicket:message></th>
+ <th style="width:80px;" class="right"></th>
+ </tr>
+ <tbody>
+ <tr wicket:id="userRow">
+ <td class="left" ><span class="list" wicket:id="username">[username]</span></td>
+ <td class="hidden-phone hidden-tablet left" ><span class="list" wicket:id="displayName">[display name]</span></td>
+ <td class="hidden-phone hidden-tablet left" ><span class="list" wicket:id="emailAddress">[email address]</span></td>
+ <td class="hidden-phone left" ><span style="font-size: 0.8em;" wicket:id="accountType">[account type]</span></td>
+ <td class="hidden-phone left" ><span class="list" wicket:id="teams">[team memberships]</span></td>
+ <td class="hidden-phone left" ><span class="list" wicket:id="repositories">[repositories]</span></td>
+ <td class="rightAlign"><span wicket:id="userLinks"></span></td>
+ </tr>
+ </tbody>
+ </table>
+
+ <wicket:fragment wicket:id="adminLinks">
+ <!-- page nav links -->
+ <div class="admin_nav">
+ <a class="btn-small" wicket:id="newUser" style="padding-right:0px;">
+ <i class="icon icon-plus-sign"></i>
+ <wicket:message key="gb.newUser"></wicket:message>
+ </a>
+ </div>
+ </wicket:fragment>
+
+ <wicket:fragment wicket:id="userAdminLinks">
+ <span class="link"><a wicket:id="editUser"><wicket:message key="gb.edit">[edit]</wicket:message></a> | <a wicket:id="deleteUser"><wicket:message key="gb.delete">[delete]</wicket:message></a></span>
+ </wicket:fragment>
+
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/UsersPanel.java b/src/main/java/com/gitblit/wicket/panels/UsersPanel.java new file mode 100644 index 00000000..f5b95e20 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/UsersPanel.java @@ -0,0 +1,117 @@ +/*
+ * Copyright 2011 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.List;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.markup.repeater.data.DataView;
+import org.apache.wicket.markup.repeater.data.ListDataProvider;
+
+import com.gitblit.GitBlit;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.pages.EditUserPage;
+
+public class UsersPanel extends BasePanel {
+
+ private static final long serialVersionUID = 1L;
+
+ public UsersPanel(String wicketId, final boolean showAdmin) {
+ super(wicketId);
+
+ Fragment adminLinks = new Fragment("adminPanel", "adminLinks", this);
+ adminLinks.add(new BookmarkablePageLink<Void>("newUser", EditUserPage.class)
+ .setVisible(GitBlit.self().supportsAddUser()));
+ add(adminLinks.setVisible(showAdmin));
+
+ final List<UserModel> users = GitBlit.self().getAllUsers();
+ DataView<UserModel> usersView = new DataView<UserModel>("userRow",
+ new ListDataProvider<UserModel>(users)) {
+ private static final long serialVersionUID = 1L;
+ private int counter;
+
+ @Override
+ protected void onBeforeRender() {
+ super.onBeforeRender();
+ counter = 0;
+ }
+
+ public void populateItem(final Item<UserModel> item) {
+ final UserModel entry = item.getModelObject();
+ LinkPanel editLink = new LinkPanel("username", "list", entry.username,
+ EditUserPage.class, WicketUtils.newUsernameParameter(entry.username));
+ WicketUtils.setHtmlTooltip(editLink, getString("gb.edit") + " " + entry.getDisplayName());
+ item.add(editLink);
+
+ if (StringUtils.isEmpty(entry.displayName)) {
+ item.add(new Label("displayName").setVisible(false));
+ } else {
+ editLink = new LinkPanel("displayName", "list", entry.getDisplayName(),
+ EditUserPage.class, WicketUtils.newUsernameParameter(entry.username));
+ WicketUtils.setHtmlTooltip(editLink, getString("gb.edit") + " " + entry.getDisplayName());
+ item.add(editLink);
+ }
+
+ if (StringUtils.isEmpty(entry.emailAddress)) {
+ item.add(new Label("emailAddress").setVisible(false));
+ } else {
+ editLink = new LinkPanel("emailAddress", "list", entry.emailAddress,
+ EditUserPage.class, WicketUtils.newUsernameParameter(entry.username));
+ WicketUtils.setHtmlTooltip(editLink, getString("gb.edit") + " " + entry.getDisplayName());
+ item.add(editLink);
+ }
+
+ item.add(new Label("accountType", entry.accountType.name() + (entry.canAdmin() ? ", admin":"")));
+ item.add(new Label("teams", entry.teams.size() > 0 ? ("" + entry.teams.size()) : ""));
+ item.add(new Label("repositories",
+ entry.permissions.size() > 0 ? ("" + entry.permissions.size()) : ""));
+ Fragment userLinks = new Fragment("userLinks", "userAdminLinks", this);
+ userLinks.add(new BookmarkablePageLink<Void>("editUser", EditUserPage.class,
+ WicketUtils.newUsernameParameter(entry.username)));
+ Link<Void> deleteLink = new Link<Void>("deleteUser") {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void onClick() {
+ if (GitBlit.self().deleteUser(entry.username)) {
+ users.remove(entry);
+ info(MessageFormat.format(getString("gb.userDeleted"), entry.username));
+ } else {
+ error(MessageFormat.format(getString("gb.deleteUserFailed"),
+ entry.username));
+ }
+ }
+ };
+ deleteLink.add(new JavascriptEventConfirmation("onclick", MessageFormat.format(
+ getString("gb.deleteUser"), entry.username)));
+ userLinks.add(deleteLink);
+ item.add(userLinks);
+
+ WicketUtils.setAlternatingBackground(item, counter);
+ counter++;
+ }
+ };
+ add(usersView.setVisible(showAdmin));
+ }
+}
|