Compare commits

...

62 Commits
3.5 ... 3.6

Author SHA1 Message Date
Naoki Takezoe
4088b2c1e8 Exclude group name from issue / pull request assignees 2015-08-30 03:33:29 +09:00
Naoki Takezoe
919d55c002 Fix NullPointerException for non-existent branches 2015-08-27 11:16:33 +09:00
Naoki Takezoe
068bbd0c3b Merge branch 'officer-retry_fix_#838' 2015-08-26 22:48:03 +09:00
Naoki Takezoe
9f50528192 Merge branch 'retry_fix_#838' of https://github.com/officer/gitbucket into officer-retry_fix_#838
# Conflicts:
#	src/main/scala/gitbucket/core/view/LinkConverter.scala
2015-08-26 22:47:41 +09:00
Naoki Takezoe
4c149cf01c (refs #831)url encode filename in the redirect path 2015-08-26 22:17:21 +09:00
Naoki Takezoe
c86c706406 (refs #864)Fix blame 2015-08-24 02:40:29 +09:00
Naoki Takezoe
3b0a0f55b5 Fix broken blame 2015-08-24 02:09:50 +09:00
Naoki Takezoe
4232b8184e Change a limit of initial amount of the repositories list 2015-08-23 15:47:07 +09:00
Naoki Takezoe
e5f3dfe293 Update version to 3.6.0 2015-08-23 15:42:52 +09:00
Naoki Takezoe
22af94d36a BugFix and improvement for pull request 2015-08-23 13:44:12 +09:00
Naoki Takezoe
d6b6781861 Add show more link for repositories and wiki pages 2015-08-23 03:19:52 +09:00
Naoki Takezoe
2222299793 Fix merge checking 2015-08-23 02:17:46 +09:00
Naoki Takezoe
fdd9a184b5 Fix presentation of commit list in the pull request detail view 2015-08-22 17:20:59 +09:00
Naoki Takezoe
99492e3f8e Merge pull request #886 from noc06140728/fix-octicon
Replace some icon to octicon
2015-08-21 02:12:15 +09:00
Naoki Takezoe
a42c40bbc1 Fix merge guide to display ssh url 2015-08-21 02:11:42 +09:00
Masahiro Namba
2794f9fcfc Replace some icon to octicon
- replace some of the non-octicon to octicon.
- adjust the color of octicon on the button.

modified icon is as follows.

- .icon-home          -> .octicon-home
- .icon-time          -> .octicon-clock
- .icon-ok            -> .octicon-check
- .icon-lock          -> .octicon-lock
- .icon-envelope      -> .octicon-mail
- .icon-pencil        -> .octicon-pencil
- .icon-remove-circle -> .octicon-x
- .icon-check         -> .octicon-clippy
- .icon-calendar      -> .octicon-calendar
- .icon-cog           -> .octicon-gear
- .icon-th-list       -> .octicon-list-unordered
- .icon-trash         -> .octicon-trashcan
- .icon-arrow-right   -> .octicon-arrow-right
- .icon-retweet       -> .octicon-git-compare
- .icon-comment       -> .octicon-comment
2015-08-20 20:23:47 +09:00
Naoki Takezoe
28c0262e74 Improve issue and pull request creation form 2015-08-19 10:20:52 +09:00
Naoki Takezoe
8634191bd2 Merge pull request #884 from skx/master
Updated to fix truncated name in JSON: watchers_coun
2015-08-18 17:27:29 +09:00
Steve Kemp
f73c86d533 Updated to fix truncated name in JSON: watchers_coun
The correct field in the JSON should be `watchers_count` rather
than the truncated version `watchers_coun`.
2015-08-18 09:14:44 +03:00
Naoki Takezoe
f042d709ac Improve issue creation form 2015-08-18 10:42:16 +09:00
Naoki Takezoe
e2a6149a93 Update auto_update.md 2015-08-17 13:29:41 +09:00
Naoki Takezoe
b2a7e2c7e2 Merge pull request #882 from garygreen/shorten-commit-message
File listing and sidebar display improvements
2015-08-17 06:19:00 +09:00
Naoki Takezoe
89fc143075 Update merge guide 2015-08-16 23:43:57 +09:00
Gary Green
a754a92799 File listing and sidebar display improvements 2015-08-16 14:55:18 +01:00
Naoki Takezoe
dc26fcf609 Merge branch 'garygreen-link-width' 2015-08-16 11:07:08 +09:00
Naoki Takezoe
b9db57eeef Merge branch 'link-width' of https://github.com/garygreen/gitbucket into garygreen-link-width 2015-08-16 11:03:48 +09:00
Naoki Takezoe
9b377c727d Improve the pull request creation form 2015-08-16 02:30:13 +09:00
Naoki Takezoe
e5b8d81bb4 Remove unused code 2015-08-16 01:13:25 +09:00
Naoki Takezoe
c85b31a7d5 Improve comparing view 2015-08-16 01:12:44 +09:00
Naoki Takezoe
6580e5458a Merge branch 'master' of https://github.com/takezoe/gitbucket 2015-08-16 00:55:18 +09:00
Naoki Takezoe
4e4e65eaa6 Improve th background color 2015-08-15 14:31:00 +09:00
Naoki Takezoe
9d19aad384 Merge pull request #880 from garygreen/issues-gui
Improved design of issue
2015-08-15 11:29:56 +09:00
Naoki Takezoe
c16a9f234b (refs #878)Hide the Delete button for other than the head of branch 2015-08-15 11:21:26 +09:00
Naoki Takezoe
ace551c33d (refs #871)Make link for @mention which contains dot 2015-08-15 10:15:44 +09:00
Naoki Takezoe
1e6e686692 Merge pull request #873 from superhj1987/master
Update main.scala.html
2015-08-15 09:59:16 +09:00
Gary Green
afdcc3f7c0 Improved design of issue 2015-08-15 00:12:56 +01:00
Naoki Takezoe
00e64bc46c Remove IntelliJ specific file 2015-08-13 09:24:18 +09:00
Bryant Hang
a959e1820f Update main.scala.html
fix header plus dropdown menu display bug in safari and add 'Your profile' in user dropdown menu
2015-08-12 15:39:54 +08:00
Naoki Takezoe
3dfbdbfe51 (refs #865)Fix styles for repository viewer 2015-08-09 01:41:10 +09:00
Naoki Takezoe
5c46dc0bd3 (refs #865)Fix paginator of the commit list 2015-08-09 01:31:29 +09:00
Naoki Takezoe
db60db674f (refs #865)Update commit list presentation 2015-08-09 01:14:21 +09:00
Naoki Takezoe
687a4f14e1 (refs #865)Fix presentation of file finder and blow view 2015-08-08 21:11:34 +09:00
Naoki Takezoe
bb10365b8b (refs #865)Apply the flat style to box headers 2015-08-08 13:32:42 +09:00
Naoki Takezoe
74ed3bf6a0 Update README.md 2015-08-06 07:17:05 +09:00
Naoki Takezoe
d1d7fdc488 Merge pull request #862 from McFoggy/plugins-info
list installed plugins in the system administration menu
2015-08-06 02:20:07 +09:00
Matthieu Brouillard
67775a4c62 add a comprehensive message when no plugin is detected on the installation 2015-08-05 17:38:14 +02:00
Naoki Takezoe
317b5cb096 Merge pull request #861 from McFoggy/system-admin-extensibility
give an id to system admin menu container to allow plugin extension
2015-08-06 00:16:42 +09:00
Matthieu Brouillard
2929517d7e list installed plugins in the system administration menu 2015-08-05 16:45:00 +02:00
Matthieu Brouillard
51e788396d give an id to system admin menu container to allow plugin extension 2015-08-05 11:38:04 +02:00
Naoki Takezoe
1321653bf6 (refs #848)Additional fix for header width 2015-08-05 02:26:38 +09:00
Naoki Takezoe
3899854854 Merge pull request #848 from garygreen/css-container
Increase container width
2015-08-05 02:21:25 +09:00
Naoki Takezoe
c0ca842ba7 Merge pull request #857 from ssogabe/fixed_build_error
small fixed: env.sh has been already removed.
2015-08-04 00:40:44 +09:00
Seiji Sogabe
24b05d28db env.sh has been already removed. 2015-08-03 19:38:46 +09:00
chocolatle
f0268b105c Fix making bad link from certain references. 2015-08-03 02:14:38 +09:00
Naoki Takezoe
0a46e180a9 Merge pull request #855 from mslinn/master
Updated installation script to GitBucket 3.5
2015-08-03 01:11:42 +09:00
Mike Slinn
e6a215a9c3 Updated to GitBucket 3.5 2015-08-02 08:47:47 -07:00
Naoki Takezoe
8ca7117065 (refs #854)Backup document is moved to Wiki 2015-08-02 12:52:40 +09:00
Naoki Takezoe
ba0a07b835 Merge pull request #854 from McFoggy/backup-gitbucket
add an example of a backup script and some usage instructions
2015-08-02 12:44:22 +09:00
Naoki Takezoe
4a35b65c2c Update release scripts 2015-08-01 03:02:38 +09:00
Matthieu Brouillard
5b658ef6ff add backup script and instructions 2015-07-31 16:39:16 +02:00
Gary Green
e9ff24d9a7 Make header and sidemenu links clickable across full width. 2015-07-29 23:02:29 +01:00
Gary Green
a92051a4c3 Increase container width 2015-07-29 22:52:46 +01:00
62 changed files with 1207 additions and 942 deletions

View File

@@ -1,5 +1,4 @@
language: scala
sudo: false
script:
- . env.sh
- sbt test

View File

@@ -14,12 +14,13 @@ The current version of GitBucket provides a basic features below:
- Wiki
- Issues
- Fork / Pull request
- Mail notification
- Email notification
- Activity timeline
- User management (for Administrators)
- Group (like Organization in Github)
- Group (like Organization in GitHub)
- LDAP integration
- Gravatar support
- Plug-in system
Following features are not implemented, but we will make them in the future release!
@@ -79,6 +80,13 @@ Run the following commands in `Terminal` to
- start gitbucket: `launchctl load ~/Library/LaunchAgents/gitbucket.plist`
- stop gitbucket: `launchctl unload ~/Library/LaunchAgents/gitbucket.plist`
Plug-ins
--------
GitBucket has the plug-in system to extend GitBucket from outside of GitBucket. Some plug-ins are available now:
- [gitbucket-gist-plugin](https://github.com/takezoe/gitbucket-gist-plugin)
- [gitbucket-announce-plugin](https://github.com/McFoggy/gitbucket-announce-plugin)
Release Notes
--------
### 3.5 - 1 Aug 2015

View File

@@ -44,7 +44,7 @@ GITBUCKET_WAR_DIR=$GITBUCKET_DIR/lib
GITBUCKET_WAR_FILE=$GITBUCKET_WAR_DIR/gitbucket.war
# GitBucket version to fetch when installing
GITBUCKET_VERSION=2.1
GITBUCKET_VERSION=3.5
#
# End of configuration section. Ignore this part

View File

@@ -2,7 +2,7 @@ Automatic Schema Updating
========
GitBucket uses H2 database to manage project and account data. GitBucket updates database schema automatically in the first run after the upgrading.
To release a new version of GitBucket, add the version definition to the [servlet.AutoUpdate](https://github.com/takezoe/gitbucket/blob/master/src/main/scala/servlet/AutoUpdateListener.scala) at first.
To release a new version of GitBucket, add the version definition to the [gitbucket.core.servlet.AutoUpdate](https://github.com/takezoe/gitbucket/blob/master/src/main/scala/gitbucket/core/servlet/AutoUpdate.scala) at first.
```scala
object AutoUpdate {

3
env.sh
View File

@@ -1,3 +0,0 @@
#!/bin/sh
export GITBUCKET_VERSION=`cat project/build.scala | grep 'val Version' | cut -d \" -f 2`
echo "GITBUCKET_VERSION: $GITBUCKET_VERSION"

View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -10,7 +10,7 @@ import sbtassembly.AssemblyKeys._
object MyBuild extends Build {
val Organization = "gitbucket"
val Name = "gitbucket"
val Version = "3.5.0"
val Version = "3.6.0"
val ScalaVersion = "2.11.6"
val ScalatraVersion = "2.3.1"

View File

@@ -1,5 +1,5 @@
#!/bin/sh
. ../env.sh
. ./env.sh
cd ../
./sbt.sh clean assembly

3
release/env.sh Normal file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
export GITBUCKET_VERSION=`cat ../project/build.scala | grep 'val Version' | cut -d \" -f 2`
echo "GITBUCKET_VERSION: $GITBUCKET_VERSION"

View File

@@ -3,13 +3,13 @@ D="$(dirname "$0")"
D="$(cd "${D}"; pwd)"
DD="$(dirname "${D}")"
(
for f in "${DD}/env.sh" "${D}/build.xml"; do
for f in "${D}/env.sh" "${D}/build.xml"; do
if [ ! -s "${f}" ]; then
echo >&2 "$0: Unable to access file '${f}'"
exit 1
fi
done
. "${D}/env.sh"
cd "${DD}"
. "${DD}/env.sh"
ant -f "${D}/build.xml" all
)

View File

@@ -32,6 +32,7 @@ class ScalatraBootstrap extends LifeCycle {
context.mount(new DashboardController, "/*")
context.mount(new UserManagementController, "/*")
context.mount(new SystemSettingsController, "/*")
context.mount(new PluginsController, "/*")
context.mount(new AccountController, "/*")
context.mount(new RepositoryViewerController, "/*")
context.mount(new WikiController, "/*")

View File

@@ -15,7 +15,7 @@ case class ApiRepository(
default_branch: String,
owner: ApiUser) {
val forks_count = forks
val watchers_coun = watchers
val watchers_count = watchers
val url = ApiPath(s"/api/v3/repos/${full_name}")
val http_url = ApiPath(s"/git/${full_name}.git")
val clone_url = ApiPath(s"/git/${full_name}.git")

View File

@@ -257,6 +257,12 @@ trait IssuesControllerBase extends ControllerBase {
} getOrElse NotFound
})
ajaxPost("/:owner/:repository/issues/new/label")(collaboratorsOnly { repository =>
val labelNames = params("labelNames").split(",")
val labels = getLabels(repository.owner, repository.name).filter(x => labelNames.contains(x.labelName))
html.labellist(labels)
})
ajaxPost("/:owner/:repository/issues/:id/label/new")(collaboratorsOnly { repository =>
defining(params("id").toInt){ issueId =>
registerIssueLabel(repository.owner, repository.name, issueId, params("labelId").toInt)
@@ -459,7 +465,11 @@ trait IssuesControllerBase extends ControllerBase {
"issues",
searchIssue(condition, false, (page - 1) * IssueLimit, IssueLimit, owner -> repoName),
page,
(getCollaborators(owner, repoName) :+ owner).sorted,
if(!getAccountByUserName(owner).exists(_.isGroupAccount)){
(getCollaborators(owner, repoName) :+ owner).sorted
} else {
getCollaborators(owner, repoName)
},
getMilestones(owner, repoName),
getLabels(owner, repoName),
countIssue(condition.copy(state = "open" ), false, owner -> repoName),

View File

@@ -0,0 +1,11 @@
package gitbucket.core.controller
import gitbucket.core.admin.plugins.html
import gitbucket.core.plugin.PluginRegistry
import gitbucket.core.util.AdminAuthenticator
class PluginsController extends ControllerBase with AdminAuthenticator {
get("/admin/plugins")(adminOnly {
html.plugins(PluginRegistry().getPlugins())
})
}

View File

@@ -46,7 +46,10 @@ trait PullRequestsControllerBase extends ControllerBase {
"requestRepositoryName" -> trim(text(required, maxlength(100))),
"requestBranch" -> trim(text(required, maxlength(100))),
"commitIdFrom" -> trim(text(required, maxlength(40))),
"commitIdTo" -> trim(text(required, maxlength(40)))
"commitIdTo" -> trim(text(required, maxlength(40))),
"assignedUserName" -> trim(optional(text())),
"milestoneId" -> trim(optional(number())),
"labelNames" -> trim(optional(text()))
)(PullRequestForm.apply)
val mergeForm = mapping(
@@ -62,7 +65,11 @@ trait PullRequestsControllerBase extends ControllerBase {
requestRepositoryName: String,
requestBranch: String,
commitIdFrom: String,
commitIdTo: String)
commitIdTo: String,
assignedUserName: Option[String],
milestoneId: Option[Int],
labelNames: Option[String]
)
case class MergeForm(message: String)
@@ -176,7 +183,7 @@ trait PullRequestsControllerBase extends ControllerBase {
pullreq,
statuses,
repository,
s"${context.baseUrl}/git/${pullreq.requestUserName}/${pullreq.requestRepositoryName}.git")
getRepository(pullreq.requestUserName, pullreq.requestRepositoryName, context.baseUrl).get)
}
} getOrElse NotFound
})
@@ -307,32 +314,44 @@ trait PullRequestsControllerBase extends ControllerBase {
originRepository.owner, originRepository.name, originId,
forkedRepository.owner, forkedRepository.name, forkedId)
(oldGit.getRepository.resolve(rootId), newGit.getRepository.resolve(forkedId))
(Option(oldGit.getRepository.resolve(rootId)), Option(newGit.getRepository.resolve(forkedId)))
} else {
// Commit id
(oldGit.getRepository.resolve(originId), newGit.getRepository.resolve(forkedId))
(Option(oldGit.getRepository.resolve(originId)), Option(newGit.getRepository.resolve(forkedId)))
}
val (commits, diffs) = getRequestCompareInfo(
originRepository.owner, originRepository.name, oldId.getName,
forkedRepository.owner, forkedRepository.name, newId.getName)
(oldId, newId) match {
case (Some(oldId), Some(newId)) => {
val (commits, diffs) = getRequestCompareInfo(
originRepository.owner, originRepository.name, oldId.getName,
forkedRepository.owner, forkedRepository.name, newId.getName)
html.compare(
commits,
diffs,
(forkedRepository.repository.originUserName, forkedRepository.repository.originRepositoryName) match {
case (Some(userName), Some(repositoryName)) => (userName, repositoryName) :: getForkedRepositories(userName, repositoryName)
case _ => (forkedRepository.owner, forkedRepository.name) :: getForkedRepositories(forkedRepository.owner, forkedRepository.name)
},
commits.flatten.map(commit => getCommitComments(forkedRepository.owner, forkedRepository.name, commit.id, false)).flatten.toList,
originId,
forkedId,
oldId.getName,
newId.getName,
forkedRepository,
originRepository,
forkedRepository,
hasWritePermission(forkedRepository.owner, forkedRepository.name, context.loginAccount))
html.compare(
commits,
diffs,
(forkedRepository.repository.originUserName, forkedRepository.repository.originRepositoryName) match {
case (Some(userName), Some(repositoryName)) => (userName, repositoryName) :: getForkedRepositories(userName, repositoryName)
case _ => (forkedRepository.owner, forkedRepository.name) :: getForkedRepositories(forkedRepository.owner, forkedRepository.name)
},
commits.flatten.map(commit => getCommitComments(forkedRepository.owner, forkedRepository.name, commit.id, false)).flatten.toList,
originId,
forkedId,
oldId.getName,
newId.getName,
forkedRepository,
originRepository,
forkedRepository,
hasWritePermission(originRepository.owner, originRepository.name, context.loginAccount),
(getCollaborators(originRepository.owner, originRepository.name) ::: (if(getAccountByUserName(originRepository.owner).get.isGroupAccount) Nil else List(originRepository.owner))).sorted,
getMilestones(originRepository.owner, originRepository.name),
getLabels(originRepository.owner, originRepository.name)
)
}
case (oldId, newId) =>
redirect(s"/${forkedRepository.owner}/${forkedRepository.name}/compare/" +
s"${originOwner}:${oldId.map(_ => originId).getOrElse(originRepository.repository.defaultBranch)}..." +
s"${forkedOwner}:${newId.map(_ => forkedId).getOrElse(forkedRepository.repository.defaultBranch)}")
}
}
}) getOrElse NotFound
})
@@ -368,46 +387,61 @@ trait PullRequestsControllerBase extends ControllerBase {
})
post("/:owner/:repository/pulls/new", pullRequestForm)(referrersOnly { (form, repository) =>
val loginUserName = context.loginAccount.get.userName
defining(repository.owner, repository.name){ case (owner, name) =>
val writable = hasWritePermission(owner, name, context.loginAccount)
val loginUserName = context.loginAccount.get.userName
val issueId = createIssue(
owner = repository.owner,
repository = repository.name,
loginUser = loginUserName,
title = form.title,
content = form.content,
assignedUserName = None,
milestoneId = None,
isPullRequest = true)
val issueId = createIssue(
owner = repository.owner,
repository = repository.name,
loginUser = loginUserName,
title = form.title,
content = form.content,
assignedUserName = if(writable) form.assignedUserName else None,
milestoneId = if(writable) form.milestoneId else None,
isPullRequest = true)
createPullRequest(
originUserName = repository.owner,
originRepositoryName = repository.name,
issueId = issueId,
originBranch = form.targetBranch,
requestUserName = form.requestUserName,
requestRepositoryName = form.requestRepositoryName,
requestBranch = form.requestBranch,
commitIdFrom = form.commitIdFrom,
commitIdTo = form.commitIdTo)
createPullRequest(
originUserName = repository.owner,
originRepositoryName = repository.name,
issueId = issueId,
originBranch = form.targetBranch,
requestUserName = form.requestUserName,
requestRepositoryName = form.requestRepositoryName,
requestBranch = form.requestBranch,
commitIdFrom = form.commitIdFrom,
commitIdTo = form.commitIdTo)
// fetch requested branch
fetchAsPullRequest(repository.owner, repository.name, form.requestUserName, form.requestRepositoryName, form.requestBranch, issueId)
// record activity
recordPullRequestActivity(repository.owner, repository.name, loginUserName, issueId, form.title)
// call web hook
callPullRequestWebHook("opened", repository, issueId, context.baseUrl, context.loginAccount.get)
// notifications
getIssue(repository.owner, repository.name, issueId.toString) foreach { issue =>
Notifier().toNotify(repository, issue, form.content.getOrElse("")){
Notifier.msgPullRequest(s"${context.baseUrl}/${repository.owner}/${repository.name}/pull/${issueId}")
// insert labels
if(writable){
form.labelNames.map { value =>
val labels = getLabels(owner, name)
value.split(",").foreach { labelName =>
labels.find(_.labelName == labelName).map { label =>
registerIssueLabel(repository.owner, repository.name, issueId, label.labelId)
}
}
}
}
}
redirect(s"/${repository.owner}/${repository.name}/pull/${issueId}")
// fetch requested branch
fetchAsPullRequest(owner, name, form.requestUserName, form.requestRepositoryName, form.requestBranch, issueId)
// record activity
recordPullRequestActivity(owner, name, loginUserName, issueId, form.title)
// call web hook
callPullRequestWebHook("opened", repository, issueId, context.baseUrl, context.loginAccount.get)
// notifications
getIssue(owner, name, issueId.toString) foreach { issue =>
Notifier().toNotify(repository, issue, form.content.getOrElse("")){
Notifier.msgPullRequest(s"${context.baseUrl}/${owner}/${name}/pull/${issueId}")
}
}
redirect(s"/${owner}/${name}/pull/${issueId}")
}
})
/**
@@ -459,7 +493,11 @@ trait PullRequestsControllerBase extends ControllerBase {
"pulls",
searchIssue(condition, true, (page - 1) * PullRequestLimit, PullRequestLimit, owner -> repoName),
page,
(getCollaborators(owner, repoName) :+ owner).sorted,
if(!getAccountByUserName(owner).exists(_.isGroupAccount)){
(getCollaborators(owner, repoName) :+ owner).sorted
} else {
getCollaborators(owner, repoName)
},
getMilestones(owner, repoName),
getLabels(owner, repoName),
countIssue(condition.copy(state = "open" ), true, owner -> repoName),

View File

@@ -22,6 +22,7 @@ import org.apache.commons.io.FileUtils
import org.eclipse.jgit.api.{ArchiveCommand, Git}
import org.eclipse.jgit.archive.{TgzFormat, ZipFormat}
import org.eclipse.jgit.dircache.DirCache
import org.eclipse.jgit.errors.MissingObjectException
import org.eclipse.jgit.lib._
import org.eclipse.jgit.revwalk.RevCommit
import org.eclipse.jgit.treewalk._
@@ -249,7 +250,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
)
redirect(s"/${repository.owner}/${repository.name}/blob/${form.branch}/${
if(form.path.length == 0) form.newFileName else s"${form.path}/${form.newFileName}"
if(form.path.length == 0) urlEncode(form.newFileName) else s"${form.path}/${urlEncode(form.newFileName)}"
}")
})
@@ -270,7 +271,7 @@ trait RepositoryViewerControllerBase extends ControllerBase {
)
redirect(s"/${repository.owner}/${repository.name}/blob/${form.branch}/${
if(form.path.length == 0) form.newFileName else s"${form.path}/${form.newFileName}"
if(form.path.length == 0) urlEncode(form.newFileName) else s"${form.path}/${urlEncode(form.newFileName)}"
}")
})
@@ -344,16 +345,21 @@ trait RepositoryViewerControllerBase extends ControllerBase {
get("/:owner/:repository/commit/:id")(referrersOnly { repository =>
val id = params("id")
using(Git.open(getRepositoryDir(repository.owner, repository.name))){ git =>
defining(JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(id))){ revCommit =>
JGitUtil.getDiffs(git, id) match { case (diffs, oldCommitId) =>
html.commit(id, new JGitUtil.CommitInfo(revCommit),
JGitUtil.getBranchesOfCommit(git, revCommit.getName),
JGitUtil.getTagsOfCommit(git, revCommit.getName),
getCommitComments(repository.owner, repository.name, id, false),
repository, diffs, oldCommitId, hasWritePermission(repository.owner, repository.name, context.loginAccount))
try {
using(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
defining(JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(id))) { revCommit =>
JGitUtil.getDiffs(git, id) match {
case (diffs, oldCommitId) =>
html.commit(id, new JGitUtil.CommitInfo(revCommit),
JGitUtil.getBranchesOfCommit(git, revCommit.getName),
JGitUtil.getTagsOfCommit(git, revCommit.getName),
getCommitComments(repository.owner, repository.name, id, false),
repository, diffs, oldCommitId, hasWritePermission(repository.owner, repository.name, context.loginAccount))
}
}
}
} catch {
case e:MissingObjectException => NotFound
}
})

View File

@@ -21,6 +21,7 @@ object AutoUpdate {
* The history of versions. A head of this sequence is the current BitBucket version.
*/
val versions = Seq(
new Version(3, 6),
new Version(3, 5),
new Version(3, 4),
new Version(3, 3),

View File

@@ -10,28 +10,64 @@ trait LinkConverter { self: RequestCache =>
* Converts issue id, username and commit id to link.
*/
protected def convertRefsLinks(value: String, repository: RepositoryService.RepositoryInfo,
issueIdPrefix: String = "#", escapeHtml: Boolean = true)(implicit context: Context): String = {
issueIdPrefix: String = "#", escapeHtml: Boolean = true)(implicit context: Context): String = {
// escape HTML tags
val escaped = if(escapeHtml) value.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;") else value
escaped
// convert issue id to link
.replaceBy(("(?<=(^|\\W))" + issueIdPrefix + "([0-9]+)(?=(\\W|$))").r){ m =>
getIssue(repository.owner, repository.name, m.group(2)) match {
case Some(issue) if(issue.isPullRequest)
=> Some(s"""<a href="${context.path}/${repository.owner}/${repository.name}/pull/${m.group(2)}">#${m.group(2)}</a>""")
case Some(_) => Some(s"""<a href="${context.path}/${repository.owner}/${repository.name}/issues/${m.group(2)}">#${m.group(2)}</a>""")
case None => Some(s"""#${m.group(2)}""")
}
// convert username/project@SHA to link
.replaceBy("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)/([a-zA-Z0-9\\-_\\.]+)@([a-f0-9]{40})(?=(\\W|$))".r){ m =>
getAccountByUserName(m.group(2)).map { _ =>
s"""<a href="${context.path}/${m.group(2)}/${m.group(3)}/commit/${m.group(4)}">${m.group(2)}/${m.group(3)}@${m.group(4).substring(0, 7)}</a>"""
}
}
// convert username/project#Num to link
.replaceBy( ("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)/([a-zA-Z0-9\\-_\\.]+)" + issueIdPrefix + "([0-9]+)(?=(\\W|$))").r){ m =>
getIssue(m.group(2), m.group(3), m.group(4)) match {
case Some(issue) if (issue.isPullRequest)
=> Some( s"""<a href="${context.path}/${m.group(2)}/${m.group(3)}/pull/${m.group(4)}">${m.group(2)}/${m.group(3)}#${m.group(4)}</a>""")
case Some(_) => Some( s"""<a href="${context.path}/${m.group(2)}/${m.group(3)}/issues/${m.group(4)}">${m.group(2)}/${m.group(3)}#${m.group(4)}</a>""")
case None => Some( s"""${m.group(2)}/${m.group(3)}#${m.group(4)}""")
}
}
// convert username@SHA to link
.replaceBy( ("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)@([a-f0-9]{40})(?=(\\W|$))").r ) { m =>
getAccountByUserName(m.group(2)).map { _ =>
s"""<a href="${context.path}/${m.group(2)}/${repository.name}/commit/${m.group(3)}">${m.group(2)}@${m.group(3).substring(0, 7)}</a>"""
}
}
// convert username#Num to link
.replaceBy( ("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)" + issueIdPrefix + "([0-9]+)(?=(\\W|$))").r ) { m =>
getIssue(m.group(2), repository.name, m.group(3)) match {
case Some(issue) if(issue.isPullRequest)
=> Some(s"""<a href="${context.path}/${m.group(2)}/${repository.name}/pull/${m.group(3)}">${m.group(2)}#${m.group(3)}</a>""")
case Some(_) => Some(s"""<a href="${context.path}/${m.group(2)}/${repository.name}/issues/${m.group(3)}">${m.group(2)}#${m.group(3)}</a>""")
case None => Some(s"""${m.group(2)}#${m.group(3)}""")
}
}
// convert issue id to link
.replaceBy(("(?<=(^|\\W))(GH-|" + issueIdPrefix + ")([0-9]+)(?=(\\W|$))").r){ m =>
getIssue(repository.owner, repository.name, m.group(3)) match {
case Some(issue) if(issue.isPullRequest)
=> Some(s"""<a href="${context.path}/${repository.owner}/${repository.name}/pull/${m.group(3)}">${m.group(2)}${m.group(3)}</a>""")
case Some(_) => Some(s"""<a href="${context.path}/${repository.owner}/${repository.name}/issues/${m.group(3)}">${m.group(2)}${m.group(3)}</a>""")
case None => Some(s"""${m.group(2)}${m.group(3)}""")
}
}
// convert @username to link
.replaceBy("(?<=(^|\\W))@([a-zA-Z0-9\\-_]+)(?=(\\W|$))".r){ m =>
.replaceBy("(?<=(^|\\W))@([a-zA-Z0-9\\-_\\.]+)(?=(\\W|$))".r){ m =>
getAccountByUserName(m.group(2)).map { _ =>
s"""<a href="${context.path}/${m.group(2)}">@${m.group(2)}</a>"""
}
}
// convert commit id to link
.replaceAll("(?<=(^|\\W))([a-f0-9]{40})(?=(\\W|$))", s"""<a href="${context.path}/${repository.owner}/${repository.name}/commit/$$2">$$2</a>""")
.replaceAll("(?<=(^|[^\\w/@]))([a-f0-9]{40})(?=(\\W|$))", s"""<a href="${context.path}/${repository.owner}/${repository.name}/commit/$$2">$$2</a>""")
}
}

View File

@@ -14,9 +14,9 @@
</div>
<div class="block">
@if(account.url.isDefined){
<div><i class="icon-home"></i> <a href="@account.url">@account.url</a></div>
<div><i class="octicon octicon-home"></i> <a href="@account.url">@account.url</a></div>
}
<div><i class="icon-time"></i> <span class="muted">Joined on</span> @date(account.registeredDate)</div>
<div><i class="octicon octicon-clock"></i> <span class="muted">Joined on</span> @date(account.registeredDate)</div>
</div>
@if(groupNames.nonEmpty){
<div>

View File

@@ -13,7 +13,7 @@ isCreateRepoOptionPublic: Boolean)(implicit context: gitbucket.core.controller.C
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="javascript:void(0);" data-name="@loginAccount.get.userName"><i class="icon-ok"></i> <span>@avatar(loginAccount.get.userName, 20) @loginAccount.get.userName</span></a></li>
<li><a href="javascript:void(0);" data-name="@loginAccount.get.userName"><i class="octicon octicon-check"></i> <span>@avatar(loginAccount.get.userName, 20) @loginAccount.get.userName</span></a></li>
@groupNames.map { groupName =>
<li><a href="javascript:void(0);" data-name="@groupName"><i class="icon-white"></i> <span>@avatar(groupName, 20) @groupName</span></a></li>
}
@@ -40,7 +40,7 @@ isCreateRepoOptionPublic: Boolean)(implicit context: gitbucket.core.controller.C
<fieldset>
<label class="radio">
<input type="radio" name="isPrivate" value="true" @if(!isCreateRepoOptionPublic){checked}>
<span class="strong"><i class="icon-lock"></i>&nbsp;</i>&nbsp;Private</span><br>
<span class="strong"><i class="octicon octicon-lock"></i>&nbsp;</i>&nbsp;Private</span><br>
<div>
<span>Only collaborators can read this repository.</span>
</div>

View File

@@ -16,7 +16,7 @@
<div class="block-header">
<a href="@url(repository)">@repository.name</a>
@if(repository.repository.isPrivate){
<i class="icon-lock"></i>
<i class="octicon octicon-lock"></i>
}
</div>
@if(repository.repository.originUserName.isDefined){

View File

@@ -3,19 +3,20 @@
<div class="container">
<div class="row-fluid">
<div class="span3">
<div class="box">
<ul class="nav nav-tabs nav-stacked side-menu">
<li@if(active=="users"){ class="active"}>
<a href="@path/admin/users">User Management</a>
</li>
<li@if(active=="system"){ class="active"}>
<a href="@path/admin/system">System Settings</a>
</li>
<li>
<a href="@path/console/login.jsp">H2 Console</a>
</li>
</ul>
</div>
<ul class="nav nav-tabs nav-stacked side-menu" id="system-admin-menu-container">
<li@if(active=="users"){ class="active"}>
<a href="@path/admin/users">User Management</a>
</li>
<li@if(active=="system"){ class="active"}>
<a href="@path/admin/system">System Settings</a>
</li>
<li@if(active=="plugins"){ class="active"}>
<a href="@path/admin/plugins">Plugins</a>
</li>
<li>
<a href="@path/console/login.jsp">H2 Console</a>
</li>
</ul>
</div>
<div class="span9">
@body

View File

@@ -0,0 +1,30 @@
@(plugins: List[gitbucket.core.plugin.PluginInfo])(implicit context: gitbucket.core.controller.Context)
@import context._
@import gitbucket.core.view.helpers._
@html.main("Plugins"){
@admin.html.menu("plugins") {
<h1>Installed plugins</h1>
@if(plugins.size > 0) {
<ul>
@plugins.map {plugin =>
<li><a href="#@plugin.pluginId">@plugin.pluginId:@plugin.version</a></li>
}
</ul>
@plugins.map {plugin =>
<div class="box">
<div class="box-header">@plugin.pluginName</div>
<div class="box-content">
<p><span class="strong">Id:&nbsp;</span>@plugin.pluginId</p>
<p><span class="strong">Version:&nbsp;</span>@plugin.version</p>
<p><span class="strong">Name:&nbsp;</span>@plugin.pluginName</p>
<p class="muted">@plugin.description</p>
</div>
</div>
}
} else {
<p>No plugin detected on your gitbucket installation.</p>
}
}
}

View File

@@ -280,9 +280,9 @@
</div>
</div>
</div>
<fieldset>
<div class="align-right" style="margin-top: 20px;">
<input type="submit" class="btn btn-success" value="Apply changes"/>
</fieldset>
</div>
</form>
}
}

View File

@@ -43,10 +43,10 @@
<div>
<hr>
@if(!account.isGroupAccount){
<i class="icon-envelope"></i> @account.mailAddress
<i class="octicon octicon-mail"></i> @account.mailAddress
}
@account.url.map { url =>
<i class="icon-home"></i> @url
<i class="octicon octicon-home"></i> @url
}
</div>
<div>

View File

@@ -8,7 +8,7 @@
@helper.html.dropdown(
value = if(branch.length == 40) branch.substring(0, 10) else branch,
prefix = if(branch.length == 40) "tree" else if(repository.branchList.contains(branch)) "branch" else "tree",
mini = true
mini = false
) {
<li><div id="branch-control-title">Switch branches<button id="branch-control-close" class="pull-right">&times</button></div></li>
<li><input id="branch-control-input" type="text" placeholder="Find or create branch ..."/></li>

View File

@@ -1,6 +1,6 @@
@(condition: => Boolean)
@if(condition){
<i class="icon-ok"></i>
<i class="octicon octicon-check"></i>
} else {
<i class="icon-white"></i>
}

View File

@@ -24,8 +24,8 @@
</span>
<span class="pull-right">
@if(hasWritePermission || loginAccount.map(_.userName == comment.commentedUserName).getOrElse(false)){
<a href="#" data-comment-id="@comment.commentId"><i class="icon-pencil"></i></a>&nbsp;
<a href="#" data-comment-id="@comment.commentId"><i class="icon-remove-circle"></i></a>
<a href="#" data-comment-id="@comment.commentId"><i class="octicon octicon-pencil"></i></a>&nbsp;
<a href="#" data-comment-id="@comment.commentId"><i class="octicon octicon-x"></i></a>
}
</span>
</div>

View File

@@ -1,7 +1,7 @@
@(id: String, value: String)(html: Html)
<div class="input-append" style="margin-bottom: 0px;">
@(id: String, value: String, prepend: Boolean = false)(html: Html)
<div class="input-append @if(prepend){input-prepend}" style="margin-bottom: 0px;">
@html
<span id="@id" class="add-on btn" data-clipboard-text="@value" data-placement="bottom" title="copy to clipboard"><i class="icon-check"></i></span>
<span id="@id" class="add-on btn" data-clipboard-text="@value" data-placement="bottom" title="copy to clipboard"><i class="octicon octicon-clippy"></i></span>
</div>
<script>
// copy to clipboard

View File

@@ -2,7 +2,7 @@
@import gitbucket.core.view.helpers
<div id="@name" class="input-append date" data-date-format="yyyy-mm-dd" data-date="@value.map(helpers.date)">
<input class="span2" name="@name" type="text" readonly="" value="@value.map(helpers.date)" size="16"/>
<span class="add-on"><i class="icon-calendar"></i></span>
<span class="add-on"><i class="octicon octicon-calendar"></i></span>
</div>
<script>
$(function(){

View File

@@ -9,7 +9,7 @@
@if(flat){style="border: none; background-color: #eee;"}
class="dropdown-toggle @if(!flat){btn} else {flat} @if(mini){btn-mini} else {btn-small}" data-toggle="dropdown">
@if(value.isEmpty){
<i class="icon-cog"></i>
<i class="octicon octicon-gear"></i>
} else {
@if(prefix.nonEmpty){
<span class="muted">@prefix:</span>

View File

@@ -24,57 +24,64 @@
@if(loginAccount.isEmpty){
@signinform(settings)
} else {
<table class="table table-bordered">
<tr>
<th class="metal">
<div class="pull-right">
<a href="@path/new" class="btn btn-success btn-mini">New repository</a>
</div>
Your repositories (@userRepositories.size)
</th>
</tr>
<div class="box-header">
<div class="pull-right">
<a href="@path/new" class="btn btn-success btn-mini">New repository</a>
</div>
<span class="strong">Your repositories</span> <span class="label">@userRepositories.size</span>
</div>
@if(userRepositories.isEmpty){
<tr>
<td>No repositories</td>
</tr>
<div class="box-content-bottom">
No repositories
</div>
} else {
@userRepositories.map { repository =>
<tr>
<td>
@helper.html.repositoryicon(repository, false)
@if(repository.owner == loginAccount.get.userName){
<a href="@url(repository)"><span class="strong">@repository.name</span></a>
} else {
<a href="@url(repository)">@repository.owner/<span class="strong">@repository.name</span></a>
}
</td>
</tr>
}
<div class="box-content-bottom" style="padding: 0px;">
@defining(20){ max =>
@userRepositories.zipWithIndex.map { case (repository, i) =>
<div class="box-content-row repo-link" style="@if(i > max - 1){display:none;}">
@helper.html.repositoryicon(repository, false)
@if(repository.owner == loginAccount.get.userName){
<a href="@url(repository)"><span class="strong">@repository.name</span></a>
} else {
<a href="@url(repository)">@repository.owner/<span class="strong">@repository.name</span></a>
}
</div>
}
@if(userRepositories.size > max){
<div class="box-content-row show-more">
<a href="javascript:void(0);" id="show-more-repos">Show more @{userRepositories.size - max} pages...</a>
</div>
}
}
</div>
}
</table>
}
<table class="table table-bordered">
<tr>
<th class="metal">
Recent updated repositories
</th>
</tr>
@if(recentRepositories.isEmpty){
<tr>
<td>No repositories</td>
</tr>
} else {
<div class="box-header">
<span class="strong">Recent updated repositories</span>
</div>
@if(recentRepositories.isEmpty){
<div class="box-content-bottom">
No repositories
</div>
} else {
<div class="box-content-bottom" style="padding: 0px;">
@recentRepositories.map { repository =>
<tr>
<td>
@helper.html.repositoryicon(repository, false)
<a href="@url(repository)">@repository.owner/<span class="strong">@repository.name</span></a>
</td>
</tr>
<div class="box-content-row">
@helper.html.repositoryicon(repository, false)
<a href="@url(repository)">@repository.owner/<span class="strong">@repository.name</span></a>
</div>
}
}
</table>
</div>
}
</div>
</div>
</div>
}
<script>
$(function(){
$('#show-more-repos').click(function(e){
$('div.repo-link').show();
$(e.target).parents('div.show-more').remove();
});
});
</script>

View File

@@ -8,7 +8,7 @@
<hr/><br/>
<form method="POST" validate="true">
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
<div class="box issue-comment-box">
<div class="issue-comment-box">
<div class="box-content">
@helper.html.preview(
repository = repository,
@@ -17,18 +17,18 @@
enableRefsLink = true,
enableTaskList = true,
hasWritePermission = hasWritePermission,
style = "width: 635px; height: 100px; max-height: 150px;",
style = "",
elastic = true
)
<div style="text-align: right;">
<input type="hidden" name="issueId" value="@issue.issueId"/>
<input type="submit" class="btn btn-success" formaction="@url(repository)/issue_comments/new" value="Comment"/>
@if((reopenable || !issue.closed) && (hasWritePermission || issue.openedUserName == loginAccount.get.userName)){
<input type="submit" class="btn" formaction="@url(repository)/issue_comments/state" value="@{if(issue.closed) "Reopen" else "Close"}" id="action"/>
}
</div>
</div>
</div>
<div class="pull-right">
<input type="hidden" name="issueId" value="@issue.issueId"/>
<input type="submit" class="btn btn-success" formaction="@url(repository)/issue_comments/new" value="Comment"/>
@if((reopenable || !issue.closed) && (hasWritePermission || issue.openedUserName == loginAccount.get.userName)){
<input type="submit" class="btn" formaction="@url(repository)/issue_comments/state" value="@{if(issue.closed) "Reopen" else "Close"}" id="action"/>
}
</div>
</form>
}
<script>

View File

@@ -8,16 +8,16 @@
@import gitbucket.core.model.CommitComment
@if(issue.isDefined){
<div class="issue-avatar-image">@avatar(issue.get.openedUserName, 48)</div>
<div class="box issue-comment-box">
<div class="box-header-small">
<div class="issue-comment-box">
<div class="box-header">
@user(issue.get.openedUserName, styleClass="username strong") <span class="muted">commented @helper.html.datetimeago(issue.get.registeredDate)</span>
<span class="pull-right">
@if(hasWritePermission || loginAccount.map(_.userName == issue.get.openedUserName).getOrElse(false)){
<a href="#" data-issue-id="@issue.get.issueId"><i class="icon-pencil" aria-label="Edit"></i></a>
<a href="#" data-issue-id="@issue.get.issueId"><i class="octicon octicon-pencil" aria-label="Edit"></i></a>
}
</span>
</div>
<div class="box-content issue-content markdown-body" id="issueContent">
<div class="box-content-bottom issue-content markdown-body" id="issueContent">
@markdown(issue.get.content getOrElse "No description provided.", repository, false, true, true, hasWritePermission)
</div>
</div>
@@ -28,7 +28,7 @@
@if(comment.action != "close" && comment.action != "reopen" && comment.action != "delete_branch"){
<div class="issue-avatar-image">@avatar(comment.commentedUserName, 48)</div>
<div class="box issue-comment-box" id="comment-@comment.commentId">
<div class="box-header-small">
<div class="box-header">
@user(comment.commentedUserName, styleClass="username strong")
<span class="muted">
@if(comment.action == "comment"){
@@ -41,12 +41,12 @@
<span class="pull-right">
@if(comment.action != "commit" && comment.action != "merge" && comment.action != "refer"
&& (hasWritePermission || loginAccount.map(_.userName == comment.commentedUserName).getOrElse(false))){
<a href="#" data-comment-id="@comment.commentId"><i class="icon-pencil" aria-label="Edit"></i></a>&nbsp;
<a href="#" data-comment-id="@comment.commentId"><i class="icon-remove-circle" aria-label="Remove"></i></a>
<a href="#" data-comment-id="@comment.commentId"><i class="octicon octicon-pencil" aria-label="Edit"></i></a>&nbsp;
<a href="#" data-comment-id="@comment.commentId"><i class="octicon octicon-x" aria-label="Remove"></i></a>
}
</span>
</div>
<div class="box-content"class="issue-content" id="commentContent-@comment.commentId">
<div class="box-content-bottom issue-content" id="commentContent-@comment.commentId">
@if(comment.action == "commit" && comment.content.split(" ").last.matches("[a-f0-9]{40}")){
@defining(comment.content.substring(comment.content.length - 40)){ id =>
<div class="pull-right"><a href="@path/@repository.owner/@repository.name/commit/@id" class="monospace">@id.substring(0, 7)</a></div>
@@ -78,8 +78,8 @@
</div>
}
@if(comment.action == "close" || comment.action == "close_comment"){
<div class="small issue-comment-action">
<span class="label label-important">Closed</span>
<div class="issue-comment-action">
<i class="octicon octicon-circle-slash danger"></i>
@avatar(comment.commentedUserName, 20)
@if(issue.isDefined && issue.get.isPullRequest){
@user(comment.commentedUserName, styleClass="username strong") closed the pull request @helper.html.datetimeago(comment.registeredDate)
@@ -89,14 +89,14 @@
</div>
}
@if(comment.action == "reopen" || comment.action == "reopen_comment"){
<div class="small issue-comment-action">
<span class="label label-success">Reopened</span>
<div class="issue-comment-action issue-reopened">
<i class="octicon octicon-primitive-dot"></i>
@avatar(comment.commentedUserName, 20)
@user(comment.commentedUserName, styleClass="username strong") reopened the issue @helper.html.datetimeago(comment.registeredDate)
</div>
}
@if(comment.action == "delete_branch"){
<div class="small issue-comment-action">
<div class="issue-comment-action">
<span class="label">Deleted</span>
@avatar(comment.commentedUserName, 20)
@user(comment.commentedUserName, styleClass="username strong") deleted the <span class="label label-info monospace">@pullreq.map(_.requestBranch)</span> branch @helper.html.datetimeago(comment.registeredDate)
@@ -110,7 +110,7 @@
<script>
$(function(){
@if(issue.isDefined){
$('.issue-comment-box i.icon-pencil').click(function(){
$('.issue-comment-box i.octicon-pencil').click(function(){
var id = $(this).closest('a').data('comment-id');
var url = '@url(repository)/issue_comments/_data/' + id;
var $content = $('#commentContent-' + id);
@@ -130,7 +130,7 @@ $(function(){
});
return false;
});
$('.issue-comment-box i.icon-remove-circle').click(function(){
$('.issue-comment-box i.octicon-x').click(function(){
if(confirm('Are you sure you want to delete this?')) {
var id = $(this).closest('a').data('comment-id');
$.post('@url(repository)/issue_comments/delete/' + id,
@@ -144,7 +144,7 @@ $(function(){
return false;
});
}
$(document).on('click', '.commit-comment-box i.icon-pencil', function(){
$(document).on('click', '.commit-comment-box i.octicon-pencil', function(){
var id = $(this).closest('a').data('comment-id');
var url = '@url(repository)/commit_comments/_data/' + id;
var $content = $('.commit-commentContent-' + id, $(this).closest('.box'));
@@ -158,7 +158,7 @@ $(function(){
});
return false;
});
$(document).on('click', '.commit-comment-box i.icon-remove-circle', function(){
$(document).on('click', '.commit-comment-box i.octicon-x', function(){
if(confirm('Are you sure you want to delete this?')) {
var id = $(this).closest('a').data('comment-id');
$.post('@url(repository)/commit_comments/delete/' + id,

View File

@@ -10,148 +10,33 @@
@navigation("issues", false, repository)
<br/><br/><hr style="margin-bottom: 10px;">
<form action="@url(repository)/issues/new" method="POST" validate="true">
<div class="row-fluid">
<div class="span9">
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
<div class="box issue-box">
<div class="box-content">
<span id="error-title" class="error"></span>
<input type="text" name="title" value="" placeholder="Title" style="width: 565px;" autofocus/>
<div>
<span id="label-assigned">No one is assigned</span>
@if(hasWritePermission){
<input type="hidden" name="assignedUserName" value=""/>
@helper.html.dropdown() {
<li><a href="javascript:void(0);" class="assign" data-name=""><i class="icon-remove-circle"></i> Clear assignee</a></li>
@collaborators.map { collaborator =>
<li><a href="javascript:void(0);" class="assign" data-name="@collaborator"><i class="icon-while"></i>@avatar(collaborator, 20) @collaborator</a></li>
}
}
}
<div class="pull-right">
<span id="label-milestone">No milestone</span>
@if(hasWritePermission){
<input type="hidden" name="milestoneId" value=""/>
@helper.html.dropdown() {
<li><a href="javascript:void(0);" class="milestone" data-id=""><i class="icon-remove-circle"></i> Clear this milestone</a></li>
@milestones.filter(_.closedDate.isEmpty).map { milestone =>
<li>
<a href="javascript:void(0);" class="milestone" data-id="@milestone.milestoneId" data-title="@milestone.title">
<i class="icon-while"></i> @milestone.title
<div class="small" style="padding-left: 20px;">
@milestone.dueDate.map { dueDate =>
@if(isPast(dueDate)){
<i class="octicon octicon-alert" style="color:#BD2C00;"></i><span class="milestone-alert">Due by @date(dueDate)</span>
} else {
<span class="muted">Due by @date(dueDate)</span>
}
}.getOrElse {
<span class="muted">No due date</span>
}
</div>
</a>
</li>
}
}
}
<div class="row-fluid">
<div class="span10">
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
<div class="box issue-box">
<div class="box-content">
<span id="error-title" class="error"></span>
<input type="text" name="title" value="" placeholder="Title" style="width: 690px;" autofocus/>
@helper.html.preview(
repository = repository,
content = "",
enableWikiLink = false,
enableRefsLink = true,
enableTaskList = true,
hasWritePermission = hasWritePermission,
style = "width: 690px; height: 200px; max-height: 250px;",
elastic = true
)
<div class="align-right">
<input type="submit" class="btn btn-success" value="Submit new issue"/>
</div>
</div>
<hr>
@helper.html.preview(
repository = repository,
content = "",
enableWikiLink = false,
enableRefsLink = true,
enableTaskList = true,
hasWritePermission = hasWritePermission,
style = "width: 565px; height: 200px; max-height: 250px;",
elastic = true
)
</div>
</div>
<div class="pull-right">
<input type="submit" class="btn btn-success" value="Submit new issue"/>
<div class="span2">
@issueinfo(None, Nil, Nil, collaborators, milestones.map(x => (x, 0, 0)), labels, hasWritePermission, repository)
</div>
</div>
<div class="span3">
@if(hasWritePermission){
<span class="strong">Labels</span>
<div>
<div id="label-list">
<ul class="label-list nav nav-pills nav-stacked">
@labels.map { label =>
<li>
<a href="javascript:void(0);" class="toggle-label" data-label="@label.labelName" data-bgcolor="@label.color" data-fgcolor="@label.fontColor">
<span style="background-color: #@label.color;" class="label-color">&nbsp;&nbsp;</span>
@label.labelName
</a>
</li>
}
</ul>
<input type="hidden" name="labelNames" value=""/>
</div>
</div>
}
</div>
</div>
</form>
}
}
<script>
$(function(){
$('a.assign').click(function(){
var userName = $(this).data('name');
$('a.assign i.icon-ok').attr('class', 'icon-white');
if(userName == ''){
$('#label-assigned').text('No one will be assigned');
} else {
$('#label-assigned').html($('<span>')
.append($('<a class="username strong">').attr('href', '@path/' + userName).text(userName))
.append(' will be assigned'));
$('a.assign[data-name=' + jqSelectorEscape(userName) + '] i').attr('class', 'icon-ok');
}
$('input[name=assignedUserName]').val(userName);
});
$('a.milestone').click(function(){
var title = $(this).data('title');
var milestoneId = $(this).data('id');
$('a.milestone i.icon-ok').attr('class', 'icon-white');
if(milestoneId == ''){
$('#label-milestone').text('No milestone');
} else {
$('#label-milestone').html($('<span class="strong">').text(title));
$('a.milestone[data-id=' + milestoneId + '] i').attr('class', 'icon-ok');
}
$('input[name=milestoneId]').val(milestoneId);
});
$('a.toggle-label').click(function(){
if($(this).data('selected') == true){
$(this).css({
'background-color': 'white',
'color' : 'black',
'font-weight' : 'normal'
});
$(this).data('selected', false);
} else {
$(this).css({
'background-color': '#' + $(this).data('bgcolor'),
'color' : '#' + $(this).data('fgcolor'),
'font-weight' : 'bold'
});
$(this).data('selected', true);
}
var labelNames = Array();
$('a.toggle-label').each(function(i, e){
if($(e).data('selected') == true){
labelNames.push($(e).data('label'));
}
});
$('input[name=labelNames]').val(labelNames.join(','));
});
});
</script>

View File

@@ -2,7 +2,7 @@
@import context._
<span id="error-edit-content-@commentId" class="error"></span>
@helper.html.attached(owner, repository){
<textarea style="width: 635px; height: 100px;" id="edit-content-@commentId">@content</textarea>
<textarea id="edit-content-@commentId">@content</textarea>
}
<div>
<input type="button" id="cancel-comment-@commentId" class="btn btn-small btn-danger" value="Cancel"/>

View File

@@ -1,7 +1,7 @@
@(content: Option[String], issueId: Int, owner: String, repository: String)(implicit context: gitbucket.core.controller.Context)
@import context._
@helper.html.attached(owner, repository){
<textarea style="width: 635px; height: 100px; max-height: 300px;" id="edit-content">@content.getOrElse("")</textarea>
<textarea id="edit-content">@content.getOrElse("")</textarea>
}
<div>
<input type="button" id="cancel-issue" class="btn btn-small btn-danger" value="Cancel"/>

View File

@@ -13,9 +13,9 @@
<div>
<div class="show-title pull-right">
@if(hasWritePermission || loginAccount.map(_.userName == issue.openedUserName).getOrElse(false)){
<a class="btn btn-small" href="#" id="edit">Edit</a>
<a class="btn" href="#" id="edit">Edit</a>
}
<a class="btn btn-small btn-success" href="@url(repository)/issues/new">New issue</a>
<a class="btn btn-success" href="@url(repository)/issues/new">New issue</a>
</div>
<div class="edit-title pull-right" style="display: none;">
<a class="btn" href="#" id="update">Save</a> <a href="#" id="cancel">Cancel</a>
@@ -45,13 +45,14 @@
</span>
<br/><br/>
<hr>
<br/>
<div class="row-fluid">
<div class="span10">
@commentlist(Some(issue), comments, hasWritePermission, repository)
@commentform(issue, true, hasWritePermission, repository)
</div>
<div class="span2">
@issueinfo(issue, comments, issueLabels, collaborators, milestones, labels, hasWritePermission, repository)
@issueinfo(Some(issue), comments, issueLabels, collaborators, milestones, labels, hasWritePermission, repository)
</div>
</div>
}

View File

@@ -1,4 +1,4 @@
@(issue: gitbucket.core.model.Issue,
@(issue: Option[gitbucket.core.model.Issue],
comments: List[gitbucket.core.model.Comment],
issueLabels: List[gitbucket.core.model.Label],
collaborators: List[String],
@@ -6,6 +6,7 @@
labels: List[gitbucket.core.model.Label],
hasWritePermission: Boolean,
repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context)
@import context._
@import gitbucket.core.view.helpers._
<div style="margin-bottom: 8px;">
<span class="muted small strong">Labels</span>
@@ -22,6 +23,9 @@
</li>
}
}
@if(issue.isEmpty){
<input type="hidden" name="labelNames" value=""/>
}
</div>
}
</div>
@@ -34,11 +38,14 @@
@if(hasWritePermission){
<div class="pull-right">
@helper.html.dropdown(right = true) {
<li><a href="javascript:void(0);" class="milestone" data-id=""><i class="icon-remove-circle"></i> Clear this milestone</a></li>
<li><a href="javascript:void(0);" class="milestone" data-id=""><i class="octicon octicon-x"></i> Clear this milestone</a></li>
@milestones.filter(_._1.closedDate.isEmpty).map { case (milestone, _, _) =>
<li>
<a href="javascript:void(0);" class="milestone" data-id="@milestone.milestoneId" data-title="@milestone.title">
@helper.html.checkicon(Some(milestone.milestoneId) == issue.milestoneId) @milestone.title
@issue.map { issue =>
@helper.html.checkicon(Some(milestone.milestoneId) == issue.milestoneId)
}
@milestone.title
<div class="small" style="padding-left: 20px;">
@milestone.dueDate.map { dueDate =>
@if(isPast(dueDate)){
@@ -58,14 +65,14 @@
}
</div>
<div id="milestone-progress-area">
@issue.milestoneId.map { milestoneId =>
@issue.flatMap(_.milestoneId).map { milestoneId =>
@milestones.collect { case (milestone, openCount, closeCount) if(milestone.milestoneId == milestoneId) =>
@issues.milestones.html.progress(openCount + closeCount, closeCount)
}
}
</div>
<span id="label-milestone">
@issue.milestoneId.map { milestoneId =>
@issue.flatMap(_.milestoneId).map { milestoneId =>
@milestones.collect { case (milestone, _, _) if(milestone.milestoneId == milestoneId) =>
<span class="strong small">@milestone.title</span>
}
@@ -73,17 +80,20 @@
<span class="muted small">No milestone</span>
}
</span>
@if(issue.isEmpty){
<input type="hidden" name="milestoneId" value=""/>
}
<hr/>
<div style="margin-bottom: 8px;">
<span class="muted small strong">Assignee</span>
@if(hasWritePermission){
<div class="pull-right">
@helper.html.dropdown(right = true) {
<li><a href="javascript:void(0);" class="assign" data-name=""><i class="icon-remove-circle"></i> Clear assignee</a></li>
<li><a href="javascript:void(0);" class="assign" data-name=""><i class="octicon octicon-x"></i> Clear assignee</a></li>
@collaborators.map { collaborator =>
<li>
<a href="javascript:void(0);" class="assign" data-name="@collaborator">
@helper.html.checkicon(Some(collaborator) == issue.assignedUserName)@avatar(collaborator, 20) @collaborator
@helper.html.checkicon(issue.exists(_.assignedUserName == collaborator))@avatar(collaborator, 20) @collaborator
</a>
</li>
}
@@ -92,39 +102,37 @@
}
</div>
<span id="label-assigned">
@issue.assignedUserName.map { userName =>
@issue.flatMap(_.assignedUserName).map { userName =>
@avatar(userName, 20) @user(userName, styleClass="username strong small")
}.getOrElse{
<span class="muted small">No one</span>
}
</span>
<hr/>
<div style="margin-bottom: 8px;">
@defining((issue.openedUserName :: comments.map(_.commentedUserName)).distinct){ participants =>
<div class="muted small strong">@participants.size @plural(participants.size, "participant")</div>
@participants.map { participant => @avatarLink(participant, 20, tooltip = true) }
}
</div>
@if(issue.isEmpty){
<input type="hidden" name="assignedUserName" value=""/>
}
@issue.map { issue =>
<hr/>
<div style="margin-bottom: 8px;">
@defining((issue.openedUserName :: comments.map(_.commentedUserName)).distinct){ participants =>
<div class="muted small strong">@participants.size @plural(participants.size, "participant")</div>
@participants.map { participant =>
@avatarLink(participant, 20, tooltip = true)
}
}
</div>
}
<script>
$(function(){
@issue.map { issue =>
$('a.toggle-label').click(function(){
var path, icon;
var i = $(this).children('i');
if(i.hasClass('icon-ok')){
path = 'delete';
icon = 'icon-white';
} else {
path = 'new';
icon = 'icon-ok';
}
var path = switchLabel($(this));
$.post('@url(repository)/issues/@issue.issueId/label/' + path,
{
labelId : $(this).data('label-id')
},
function(data){
i.removeClass().addClass(icon);
$('ul.label-list').empty().html(data);
});
{ labelId : $(this).data('label-id') },
function(data){
$('ul.label-list').empty().html(data);
}
);
return false;
});
@@ -132,42 +140,92 @@ $(function(){
var title = $(this).data('title');
var milestoneId = $(this).data('id');
$.post('@url(repository)/issues/@issue.issueId/milestone',
{
milestoneId: milestoneId
},
function(data){
console.log(data);
$('a.milestone i.icon-ok').attr('class', 'icon-white');
if(milestoneId == ''){
$('#label-milestone').html($('<span class="muted small">').text('No milestone'));
$('#milestone-progress-area').empty();
} else {
$('#label-milestone').html($('<span class="strong small">').text(title));
$('#milestone-progress-area').html(data);
$('a.milestone[data-id=' + milestoneId + '] i').attr('class', 'icon-ok');
{ milestoneId: milestoneId },
function(data){
displayMilestone(title, milestoneId, data);
}
});
);
});
$('a.assign').click(function(){
var $this = $(this);
var userName = $this.data('name');
$.post('@url(repository)/issues/@issue.issueId/assign',
{
assignedUserName: userName
},
function(){
$('a.assign i.icon-ok').attr('class', 'icon-white');
if(userName == ''){
$('#label-assigned').html($('<span class="muted small">').text('No one'));
} else {
$('#label-assigned').empty()
.append($this.find('img.avatar-mini').clone(false)).append(' ')
.append($('<a class="username strong small">').attr('href', '@context.path/' + userName).text(userName));
$('a.assign[data-name=' + jqSelectorEscape(userName) + '] i').attr('class', 'icon-ok');
{ assignedUserName: userName },
function(){
displayAssignee($this, userName);
}
);
});
}.getOrElse {
$('a.toggle-label').click(function(){
switchLabel($(this));
var labelNames = Array();
$('a.toggle-label').each(function(i, e){
if($(e).children('i').hasClass('icon-ok') == true){
labelNames.push($(e).text().trim());
}
});
$('input[name=labelNames]').val(labelNames.join(','));
$.post('@url(repository)/issues/new/label',
{ labelNames : labelNames.join(',') },
function(data){
$('ul.label-list').empty().html(data);
}
);
});
$('a.milestone').click(function(){
var title = $(this).data('title');
var milestoneId = $(this).data('id');
displayMilestone(title, milestoneId);
$('input[name=milestoneId]').val(milestoneId);
});
$('a.assign').click(function(){
var $this = $(this);
var userName = $this.data('name');
displayAssignee($this, userName);
$('input[name=assignedUserName]').val(userName);
});
}
function switchLabel($this){
var i = $this.children('i');
if(i.hasClass('icon-ok')){
i.removeClass().addClass('icon-white');
return 'delete';
} else {
i.removeClass().addClass('icon-ok');
return 'new';
}
}
function displayMilestone(title, milestoneId, progress){
$('a.milestone i.icon-ok').attr('class', 'icon-white');
if(milestoneId == ''){
$('#label-milestone').html($('<span class="muted small">').text('No milestone'));
$('#milestone-progress-area').empty();
} else {
$('#label-milestone').html($('<span class="strong small">').text(title));
if(progress){
$('#milestone-progress-area').html(progress);
}
$('a.milestone[data-id=' + milestoneId + '] i').attr('class', 'icon-ok');
}
}
function displayAssignee($this, userName){
$('a.assign i.icon-ok').attr('class', 'icon-white');
if(userName == ''){
$('#label-assigned').html($('<span class="muted small">').text('No one'));
} else {
$('#label-assigned').empty()
.append($this.find('img.avatar-mini').clone(false)).append(' ')
.append($('<a class="username strong small">').attr('href', '@context.path/' + userName).text(userName));
$('a.assign[data-name=' + jqSelectorEscape(userName) + '] i').attr('class', 'icon-ok');
}
}
});
</script>

View File

@@ -138,7 +138,7 @@
}
}
@helper.html.dropdown("Assignee", flat = true) {
<li><a href="javascript:void(0);" class="toggle-assign" data-name=""><i class="icon-remove-circle"></i> Clear assignee</a></li>
<li><a href="javascript:void(0);" class="toggle-assign" data-name=""><i class="octicon octicon-x"></i> Clear assignee</a></li>
@collaborators.map { collaborator =>
<li><a href="javascript:void(0);" class="toggle-assign" data-name="@collaborator"><i class="icon-white"></i>@avatar(collaborator, 20) @collaborator</a></li>
}

View File

@@ -41,7 +41,7 @@
<form id="search" action="@path/search" method="POST">
<div class="navbar">
<div class="navbar-inner">
<div class="container" style="width: 920px;">
<div class="container" style="width: 980px;">
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
@@ -66,15 +66,16 @@
<div class="nav-collapse collapse pull-right header-menu">
@if(loginAccount.isDefined){
<div class="btn-group" style="margin-top: 0px;">
<a class="dropdown-toggle menu" data-toggle="dropdown" href="#"><i class="octicon octicon-plus" style="font-size: 20px; vertical-align: top; margin-top: 10px;"></i><span class="caret" style="vertical-align: middle;"></span></a>
<ul class="dropdown-menu">
<a class="dropdown-toggle menu" data-toggle="dropdown" href="#"><i class="octicon octicon-plus" style="font-size: 20px; vertical-align: middle;height:20px !important;"></i><span class="caret" style="vertical-align: middle;"></span></a>
<ul class="dropdown-menu pull-right">
<li><a href="@path/new">New repository</a></li>
<li><a href="@path/groups/new">New group</a></li>
</ul>
</div>
<div class="btn-group" style="margin-top: 0px;">
<a class="dropdown-toggle menu" data-toggle="dropdown" href="#" data-toggle="tooltip" data-placement="bottom" title="Signed is as @loginAccount.get.userName">@avatar(loginAccount.get.userName, 16)<span class="caret" style="vertical-align: middle;"></span></a>
<ul class="dropdown-menu">
<ul class="dropdown-menu pull-right">
<li><a href="@url(loginAccount.get.userName)">Your profile</a></li>
<li><a href="@url(loginAccount.get.userName)/_edit">Account settings</a></li>
@if(loginAccount.get.isAdmin){
<li><a href="@path/admin/users">System administration</a></li>

View File

@@ -11,7 +11,6 @@
@sidemenu(path: String, name: String, icon: String, label: String, count: Int = 0) = {
<li @if(active == name){class="active"} @if(!expand){data-toggle="tooltip" data-placement="left" data-original-title="@label"}>
<div class="@if(active == name){margin} else {gradient} pull-left"></div>
<a href="@url(repository)@path">
<i class="menu-icon @if(active == name){menu-icon-active} octicon octicon-@{icon} "></i>
@if(expand){ @label}
@@ -40,7 +39,7 @@
<span class="add-on count"><a href="@url(repository)/network/members">@repository.forkedCount</a></span>
</div>
@if(loginAccount.isDefined && isNoGroup){
<form id="fork-form" method="post" action="@path/@repository.owner/@repository.name/fork">
<form id="fork-form" method="post" action="@path/@repository.owner/@repository.name/fork" style="display: none;">
<input type="hidden" name="account" value="@loginAccount.get.userName"/>
</form>
}
@@ -100,7 +99,7 @@
@repository.repository.description.map { description =>
<p class="description">@description</p>
}
<div style="border: 1px solid #eee; padding: 4px; margin-bottom: 10px;">
<div style="margin-bottom: 10px;" class="box-content">
<table class="fill-width">
<tr>
<td style="width: 33%; text-align: center;">

View File

@@ -4,32 +4,42 @@
@import context._
@import gitbucket.core.view.helpers._
@import gitbucket.core.model._
<div class="box">
<table class="table table-file-list" style="border: 1px solid silver;">
@commits.map { day =>
<tr>
<th colspan="4" class="box-header" style="font-weight: normal;">@date(day.head.commitTime)</th>
</tr>
@day.map { commit =>
<tr>
<td style="width: 20%;">
@avatar(commit, 20)
@user(commit.authorName, commit.authorEmailAddress, "username")
</td>
<td>@commit.shortMessage</td>
<td style="width: 10%; text-align: right">
<span class="badge" style="display: inline">@if(comments.isDefined){
@comments.get.flatMap @{
case comment: CommitComment => Some(comment)
case other => None
}.count(t => t.commitId == commit.id && !t.pullRequest)
}</span>
</td>
<td style="width: 10%; text-align: right;">
<a href="@url(repository)/commit/@commit.id" class="monospace">@commit.id.substring(0, 7)</a>
</td>
</tr>
}
<div class="commit-list">
@commits.map { day =>
<div class="muted" style="background-color: white;">
<i class="octicon octicon-git-commit"></i> Commits on @date(day.head.commitTime)
</div>
<div class="box-commits">
@day.map { commit =>
<div class="box-content-row" style="padding: 8px;">
<ul class="nav nav-pills-group pull-right" style="margin-top: 2px; margin-bottom: 0px; margin-right: 4px;">
<li class="first"><a href="@url(repository)/commit/@commit.id" class="link monospace">@commit.id.substring(0, 7)</a></li>
<li class="last"><a href="@url(repository)/tree/@commit.id" style="padding-top: 9px; padding-bottom: 10px;"><i class="octicon octicon-code link"></i></a></li>
</ul>
<div>
<div class="commit-avatar-image">@avatar(commit, 40)</div>
<div class="commit-message-box">
<a href="@url(repository)/commit/@commit.id" class="commit-message" style="font-weight: bold;">@link(commit.summary, repository)</a>
@if(commit.description.isDefined){
<a href="javascript:void(0)" onclick="$('#description-@commit.id').toggle();" class="omit">...</a>
}
<br>
@if(commit.description.isDefined){
<pre id="description-@commit.id" style="display: none;" class="commit-description">@link(commit.description.get, repository)</pre>
}
<div class="small">
@user(commit.authorName, commit.authorEmailAddress, "username")
<span class="muted">authored @helper.html.datetimeago(commit.authorTime)</span>
@if(commit.isDifferentFromAuthor) {
<span class="octicon octicon-arrow-right" style="margin-top : -2px;"></span>
@user(commit.committerName, commit.committerEmailAddress, "username")
<span class="muted">committed @helper.html.datetimeago(commit.authorTime)</span>
}
</div>
</div>
</div>
</div>
}
</table>
</div>
}
</div>

View File

@@ -9,18 +9,16 @@
repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
originRepository: gitbucket.core.service.RepositoryService.RepositoryInfo,
forkedRepository: gitbucket.core.service.RepositoryService.RepositoryInfo,
hasWritePermission: Boolean)(implicit context: gitbucket.core.controller.Context)
hasOriginWritePermission: Boolean,
collaborators: List[String],
milestones: List[gitbucket.core.model.Milestone],
labels: List[gitbucket.core.model.Label])(implicit context: gitbucket.core.controller.Context)
@import context._
@import gitbucket.core.view.helpers._
@html.main(s"Pull Requests - ${repository.owner}/${repository.name}", Some(repository)){
@html.menu("pulls", repository){
<div class="pullreq-info">
<div id="compare-info">
<a href="#" id="edit-compare-condition" class="btn btn-mini pull-right">Edit</a>
<span class="label label-info monospace">@originRepository.owner:@originId</span> ... <span class="label label-info monospace">@forkedRepository.owner:@forkedId</span>
</div>
<div id="compare-edit" style="display: none;">
<a href="#" id="cancel-condition-editing" class="pull-right"><i class="icon-remove-circle"></i></a>
<div id="compare-edit">
@helper.html.dropdown(originRepository.owner + "/" + originRepository.name, "base fork") {
@members.map { case (owner, name) =>
<li><a href="#" class="origin-owner" data-owner="@owner" data-name="@name">@helper.html.checkicon(owner == originRepository.owner) @owner/@name</a></li>
@@ -43,41 +41,52 @@
}
}
</div>
</div>
@if(commits.nonEmpty && hasWritePermission){
<div style="margin-bottom: 10px;" id="create-pull-request">
<a href="#" class="btn btn-success" id="show-form">Create pull request</a>
<div class="check-conflict" style="display: none;">
<img src="@assets/common/images/indicator.gif"/> Checking...
</div>
<div id="pull-request-form" class="box" style="display: none;">
<div class="box-content">
<form method="POST" action="@path/@originRepository.owner/@originRepository.name/pulls/new" validate="true">
<div style="width: 240px; position: absolute; margin-left: 610px;">
<div class="check-conflict" style="display: none;">
<img src="@assets/common/images/indicator.gif"/> Checking...
</div>
@if(commits.nonEmpty && loginAccount.isDefined){
<div style="margin-bottom: 10px; padding: 8px; background-color: #fff9ea" id="create-pull-request" class="box-content">
<a href="#" class="btn btn-success" id="show-form">Create pull request</a>
&nbsp;&nbsp;
<span class="muted">Discuss and review the changes in this comparison with others.</span>
</div>
<div id="pull-request-form" @*class="box"*@ style="display: none; margin-bottom: 20px;">
<form method="POST" action="@path/@originRepository.owner/@originRepository.name/pulls/new" validate="true">
<div class="row-fluid">
<div class="span10">
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
<div class="box issue-box">
<div class="box-content">
<span class="error" id="error-title"></span>
<input type="text" name="title" style="width: 690px" placeholder="Title"/>
@helper.html.preview(
repository = repository,
content = "",
enableWikiLink = false,
enableRefsLink = true,
enableTaskList = true,
hasWritePermission = true,
style = "width: 690px; height: 200px;"
)
<input type="hidden" name="targetUserName" value="@originRepository.owner"/>
<input type="hidden" name="targetBranch" value="@originId"/>
<input type="hidden" name="requestUserName" value="@forkedRepository.owner"/>
<input type="hidden" name="requestRepositoryName" value="@forkedRepository.name"/>
<input type="hidden" name="requestBranch" value="@forkedId"/>
<input type="hidden" name="commitIdFrom" value="@sourceId"/>
<input type="hidden" name="commitIdTo" value="@commitId"/>
<div class="align-right">
<input type="submit" class="btn btn-success" value="Create pull request"/>
</div>
</div>
</div>
<div style="width: 600px; border-right: 1px solid #d4d4d4;">
<span class="error" id="error-title"></span>
<input type="text" name="title" style="width: 580px" placeholder="Title"/>
@helper.html.preview(
repository = repository,
content = "",
enableWikiLink = false,
enableRefsLink = true,
enableTaskList = true,
hasWritePermission = hasWritePermission,
style = "width: 580px; height: 200px;"
)
<input type="hidden" name="targetUserName" value="@originRepository.owner"/>
<input type="hidden" name="targetBranch" value="@originId"/>
<input type="hidden" name="requestUserName" value="@forkedRepository.owner"/>
<input type="hidden" name="requestRepositoryName" value="@forkedRepository.name"/>
<input type="hidden" name="requestBranch" value="@forkedId"/>
<input type="hidden" name="commitIdFrom" value="@sourceId"/>
<input type="hidden" name="commitIdTo" value="@commitId"/>
</div>
</form>
</div>
<div class="span2">
@issues.html.issueinfo(None, Nil, Nil, collaborators, milestones.map((_, 0, 0)), labels, hasOriginWritePermission, repository)
</div>
</div>
</form>
</div>
}
@if(commits.isEmpty){
@@ -90,72 +99,119 @@
</tr>
</table>
} else {
@pulls.html.commits(commits, Some(comments), repository)
@helper.html.diff(diffs, repository, Some(commitId), Some(sourceId), true, None, hasWritePermission, false)
<div style="margin-bottom: 10px;" class="box-content">
<table class="fill-width">
<tr>
<td style="width: 25%; text-align: center;">
<i class="octicon octicon-commit"></i>
@defining(commits.flatten){ commits =>
<strong>@commits.size</strong> @plural(commits.size, "commit")
}
</td>
<td style="width: 25%; text-align: center;">
<i class="octicon octicon-diff"></i>
<strong>@diffs.size</strong> @plural(diffs.size, "file") changed
</td>
<td style="width: 25%; text-align: center;">
<i class="octicon octicon-comment"></i>
@defining(comments.collect { case c: gitbucket.core.model.CommitComment => c }){ comments =>
<strong>@comments.size</strong> commit @plural(comments.size, "comment")
}
</td>
<td style="width: 25%; text-align: center;">
<i class="octicon octicon-organization"></i>
@defining(commits.flatMap(_.map(_.authorEmailAddress)).distinct){ contributors =>
<strong>@contributors.size</strong> @plural(contributors.size, "contributor")
}
</td>
</tr>
</table>
</div>
<div class="box" style="margin-bottom: 20px;">
@commits.map { day =>
<div style="margin-top: 8px; margin-bottom: 8px;" class="muted">
Commits on @date(day.head.commitTime)
</div>
<table style="width: 100%;">
@day.map { commit =>
<tr>
<td style="width: 20%;">
<i class="octicon octicon-git-commit"></i>
@avatar(commit, 20)
@user(commit.authorName, commit.authorEmailAddress, "username strong")
</td>
<td><span class="monospace">@commit.shortMessage</span></td>
@*
<span class="badge" style="display: inline">@if(comments.isDefined){
@comments.get.flatMap @{
case comment: CommitComment => Some(comment)
case other => None
}.count(t => t.commitId == commit.id && !t.pullRequest)
}</span>
*@
<td style="width: 10%; text-align: right;">
<a href="@url(repository)/commit/@commit.id" class="monospace">@commit.id.substring(0, 7)</a>
</td>
</tr>
}
</table>
}
</div>
@helper.html.diff(diffs, repository, Some(commitId), Some(sourceId), true, None, false, false)
<p>Showing you all comments on commits in this comparison.</p>
@issues.html.commentlist(None, comments, hasWritePermission, repository, None)
@issues.html.commentlist(None, comments, false, repository, None)
}
}
}
<script>
$(function(){
$('#edit-compare-condition').click(function(){
$('#compare-info').hide();
$('#compare-edit').show();
});
$('#cancel-condition-editing').click(function(){
$('#compare-info').show();
$('#compare-edit').hide();
});
$('a.origin-owner, a.forked-owner, a.origin-branch, a.forked-branch').click(function(){
var e = $(this);
e.parents('ul').find('i').attr('class', 'icon-white');
e.find('i').attr('class', 'icon-ok');
e.find('i').attr('class', 'octicon-check');
e.parents('div.btn-group').find('button span.strong').text(e.text());
@if(members.isEmpty){
location.href = '@url(repository)/compare/' +
$.trim($('i.icon-ok').parents('a.origin-branch').data('branch')) + '...' +
$.trim($('i.icon-ok').parents('a.forked-branch').data('branch'));
$.trim($('i.octicon-check').parents('a.origin-branch').data('branch')) + '...' +
$.trim($('i.octicon-check').parents('a.forked-branch').data('branch'));
} else {
location.href = '@path/' +
$.trim($('i.icon-ok').parents('a.forked-owner' ).data('owner')) + '/' +
$.trim($('i.icon-ok').parents('a.forked-owner' ).data('name')) +'/compare/' +
$.trim($('i.icon-ok').parents('a.origin-owner' ).data('owner')) + ':' +
$.trim($('i.icon-ok').parents('a.origin-branch').data('branch')) + '...' +
$.trim($('i.icon-ok').parents('a.forked-owner' ).data('owner')) + ':' +
$.trim($('i.icon-ok').parents('a.forked-branch').data('branch'));
$.trim($('i.octicon-check').parents('a.forked-owner' ).data('owner')) + '/' +
$.trim($('i.octicon-check').parents('a.forked-owner' ).data('name')) +'/compare/' +
$.trim($('i.octicon-check').parents('a.origin-owner' ).data('owner')) + ':' +
$.trim($('i.octicon-check').parents('a.origin-branch').data('branch')) + '...' +
$.trim($('i.octicon-check').parents('a.forked-owner' ).data('owner')) + ':' +
$.trim($('i.octicon-check').parents('a.forked-branch').data('branch'));
}
});
$('#show-form').click(function(){
$(this).hide();
$('#create-pull-request').hide();
$('#pull-request-form').show();
});
if(location.search.substr(1).split("&").indexOf("expand=1")!=-1){
$('#show-form').click();
}
@if(hasWritePermission){
@if(loginAccount.isDefined){
function checkConflict(from, to){
$('.check-conflict').show();
$.get('@url(repository)/compare/' + from + '...' + to + '/mergecheck',
$.get('@url(forkedRepository)/compare/' + from + '...' + to + '/mergecheck',
function(data){ $('.check-conflict').html(data); });
}
@if(members.isEmpty){
checkConflict(
$.trim($('i.icon-ok').parents('a.origin-branch').data('branch')),
$.trim($('i.icon-ok').parents('a.forked-branch').data('branch'))
$.trim($('i.octicon-check').parents('a.origin-branch').data('branch')),
$.trim($('i.octicon-check').parents('a.forked-branch').data('branch'))
);
} else {
checkConflict(
$.trim($('i.icon-ok').parents('a.origin-owner' ).data('owner')) + ":" +
$.trim($('i.icon-ok').parents('a.origin-branch').data('branch')),
$.trim($('i.icon-ok').parents('a.forked-owner' ).data('owner')) + ":" +
$.trim($('i.icon-ok').parents('a.forked-branch').data('branch'))
$.trim($('i.octicon-check').parents('a.origin-owner' ).data('owner')) + ":" +
$.trim($('i.octicon-check').parents('a.origin-branch').data('branch')),
$.trim($('i.octicon-check').parents('a.forked-owner' ).data('owner')) + ":" +
$.trim($('i.octicon-check').parents('a.forked-branch').data('branch'))
);
}
}

View File

@@ -45,7 +45,7 @@
}
</div>
<div class="span2">
@issues.html.issueinfo(issue, comments, issueLabels, collaborators, milestones, labels, hasWritePermission, repository)
@issues.html.issueinfo(Some(issue), comments, issueLabels, collaborators, milestones, labels, hasWritePermission, repository)
</div>
</div>
<script>

View File

@@ -1,9 +1,12 @@
@(hasConflict: Boolean)
@if(hasConflict){
<h4>We cant automatically merge these branches</h4>
<p>Don't worry, you can still submit the pull request.</p>
} else {
<h4 style="color: #468847;">Able to merge</h4>
<p>These branches can be automatically merged.</p>
}
<input type="submit" class="btn btn-success btn-block" value="Create pull request"/>
<div style="margin-top: 8px;">
@if(hasConflict){
<i class="octicon octicon-x" style="color: #bd2c00"></i>
<span class="strong" style="color: #bd2c00;">Cant automatically merge.</span>
<span class="muted">Dont worry, you can still create the pull request.</span>
} else {
<i class="octicon octicon-check" style="color: #6cc644"></i>
<span class="strong" style="color: #6cc644">Able to merge.</span>
<span class="muted">These branches can be automatically merged.</span>
}
</div>

View File

@@ -3,8 +3,9 @@
issue: gitbucket.core.model.Issue,
pullreq: gitbucket.core.model.PullRequest,
statuses: List[model.CommitStatus],
repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
requestRepositoryUrl: String)(implicit context: gitbucket.core.controller.Context)
originRepository: gitbucket.core.service.RepositoryService.RepositoryInfo,
forkedRepository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context)
@import gitbucket.core.service.SystemSettingsService
@import context._
@import gitbucket.core.view.helpers._
@import model.CommitState
@@ -22,100 +23,101 @@
@status.description.map{ desc => <span class="muted">— @desc</span> }
</div>
}
}else{
@defining(statuses.groupBy(_.state)){ stateMap => @defining(CommitState.combine(stateMap.keySet)){ state =>
<div class="build-status-item">
<a class="pull-right" id="toggle-all-checks"></a>
<span class="build-status-icon text-@{state.name}">@commitStateIcon(state)</span>
<strong class="text-@{state.name}">@commitStateText(state, pullreq.commitIdTo)</strong>
<span class="text-@{state.name}">— @{stateMap.map{ case (keyState, states) => states.size+" "+keyState.name }.mkString(", ")} checks</span>
</div>
<div class="build-statuses-list" style="@if(state==CommitState.SUCCESS){ display:none; }else{ }">
@statuses.map{ status =>
} else {
@defining(statuses.groupBy(_.state)){ stateMap =>
@defining(CommitState.combine(stateMap.keySet)){ state =>
<div class="build-status-item">
@status.targetUrl.map{ url => <a class="pull-right" href="@url">Details</a> }
<span class="build-status-icon text-@{status.state.name}">@commitStateIcon(status.state)</span>
<span class="text-@{status.state.name}">@status.context</span>
@status.description.map{ desc => <span class="muted">— @desc</span> }
<a class="pull-right" id="toggle-all-checks"></a>
<span class="build-status-icon text-@{state.name}">@commitStateIcon(state)</span>
<strong class="text-@{state.name}">@commitStateText(state, pullreq.commitIdTo)</strong>
<span class="text-@{state.name}">— @{stateMap.map{ case (keyState, states) => states.size+" "+keyState.name }.mkString(", ")} checks</span>
</div>
}
</div>
} }
<div class="build-statuses-list" style="@if(state==CommitState.SUCCESS){ display:none; }else{ }">
@statuses.map{ status =>
<div class="build-status-item">
@status.targetUrl.map{ url => <a class="pull-right" href="@url">Details</a> }
<span class="build-status-icon text-@{status.state.name}">@commitStateIcon(status.state)</span>
<span class="text-@{status.state.name}">@status.context</span>
@status.description.map{ desc => <span class="muted">— @desc</span> }
</div>
}
</div>
}
}
}
</div>
}
<div class="pull-right">
<input type="button" class="btn @if(!hasProblem){ btn-success }" id="merge-pull-request-button" value="Merge pull request"@if(hasConflict){ disabled="true"}/>
</div>
<div>
@if(hasConflict){
<span class="strong">We cant automatically merge this pull request.</span>
} else{ @if(hasProblem){
<span class="strong">Merge with caution!</span>
} else {
<span class="strong">This pull request can be automatically merged.</span>
} }
</div>
<div class="small">
@if(hasConflict){
<a href="#" id="show-command-line">Use the command line</a> to resolve conflicts before continuing.
} else {
You can also merge branches on the <a href="#" id="show-command-line">command line</a>.
}
</div>
<div id="command-line" style="display: none;">
<hr>
@if(hasConflict){
<span class="strong">Checkout via command line</span>
<p>
If you cannot merge a pull request automatically here, you have the option of checking
it out via command line to resolve conflicts and perform a manual merge.
</p>
} else {
<span class="strong">Merging via command line</span>
<p>
If you do not want to use the merge button or an automatic merge cannot be performed,
you can perform a manual merge on the command line.
</p>
}
@helper.html.copy("repository-url-copy", requestRepositoryUrl){
<input type="text" style="width: 500px;" value="@requestRepositoryUrl" id="repository-url" readonly>
}
<div>
<p>
<span class="strong">Step 1:</span> Check out a new branch to test the changes — run this from your project directory
</p>
@defining(s"git checkout -b ${pullreq.requestUserName}-${pullreq.requestBranch} ${pullreq.branch}"){ command =>
@helper.html.copy("merge-command-copy-1", command){
<pre style="width: 500px; float: left;">@command</pre>
}
}
</div>
<div>
<p>
<span class="strong">Step 2:</span> Bring in @{pullreq.requestUserName}'s changes and test
</p>
@defining(s"git pull ${requestRepositoryUrl} ${pullreq.requestBranch}"){ command =>
@helper.html.copy("merge-command-copy-2", command){
<pre style="width: 500px; float: left;">@command</pre>
}
}
</div>
<div>
<p>
<span class="strong">Step 3:</span> Merge the changes and update the server
</p>
@defining(s"git checkout ${pullreq.branch}\ngit merge ${pullreq.requestUserName}-${pullreq.requestBranch}\ngit push origin ${pullreq.branch}"){ command =>
@helper.html.copy("merge-command-copy-3", command){
<pre style="width: 500px; float: left;">@command</pre>
}
}
</div>
</div>
<div class="pull-right">
<input type="button" class="btn @if(!hasProblem){ btn-success }" id="merge-pull-request-button" value="Merge pull request"@if(hasConflict){ disabled="true"}/>
</div>
<div>
@if(hasConflict){
<span class="strong">We cant automatically merge this pull request.</span>
} else {
@if(hasProblem){
<span class="strong">Merge with caution!</span>
} else {
<span class="strong">This pull request can be automatically merged.</span>
}
}
</div>
<div class="small">
@if(hasConflict){
<a href="#" id="show-command-line">Use the command line</a> to resolve conflicts before continuing.
} else {
You can also merge branches on the <a href="#" id="show-command-line">command line</a>.
}
</div>
<div id="command-line" style="display: none;">
<hr>
@if(hasConflict){
<span class="strong">Checkout via command line</span>
<p>
If you cannot merge a pull request automatically here, you have the option of checking
it out via command line to resolve conflicts and perform a manual merge.
</p>
} else {
<span class="strong">Merging via command line</span>
<p>
If you do not want to use the merge button or an automatic merge cannot be performed,
you can perform a manual merge on the command line.
</p>
}
@helper.html.copy("repository-url-copy", forkedRepository.httpUrl, true){
<div class="btn-group" data-toggle="buttons-radio">
<button class="btn btn-small active" type="button" id="repository-url-http">HTTP</button>
@if(settings.ssh && loginAccount.isDefined){
<button class="btn btn-small" type="button" id="repository-url-ssh" style="border-radius: 0px;">SSH</button>
}
</div>
<input type="text" style="width: 500px;" value="@forkedRepository.httpUrl" id="repository-url" readonly>
}
<div>
<p>
<span class="strong">Step 1:</span> From your project repository, check out a new branch and test the changes.
</p>
@defining(s"git checkout -b ${pullreq.requestUserName}-${pullreq.requestBranch} ${pullreq.branch}\n" +
s"git pull ${forkedRepository.httpUrl} ${pullreq.requestBranch}"){ command =>
@helper.html.copy("merge-command-copy-1", command){
<pre style="width: 600px; float: left; font-size: 12px; border-radius: 3px 0px 3px 3px;" id="merge-command">@Html(command)</pre>
}
}
</div>
<div>
<p>
<span class="strong">Step 2:</span> Merge the changes and update on the server.
</p>
@defining(s"git checkout ${pullreq.branch}\ngit merge --no-ff ${pullreq.requestUserName}-${pullreq.requestBranch}\n" +
s"git push origin ${pullreq.branch}"){ command =>
@helper.html.copy("merge-command-copy-2", command){
<pre style="width: 600px; float: left; font-size: 12px; border-radius: 3px 0px 3px 3px;">@command</pre>
}
}
</div>
</div>
</div>
<div id="confirm-merge-form" style="display: none;">
<form method="POST" action="@url(repository)/pull/@pullreq.issueId/merge">
<form method="POST" action="@url(originRepository)/pull/@pullreq.issueId/merge">
<div class="strong">
Merge pull request #@issue.issueId from @{pullreq.requestUserName}/@{pullreq.requestBranch}
</div>
@@ -149,5 +151,31 @@ $(function(){
$('#merge-pull-request').hide();
$('#confirm-merge-form').show();
});
@if(settings.ssh && loginAccount.isDefined){
$('#repository-url-http').click(function(){
// Update URL box
$('#repository-url').val('@forkedRepository.httpUrl');
$('#repository-url-copy').attr('data-clipboard-text', $('#repository-url').val());
// Update command guidance
$('#merge-command').text($('#merge-command').text().replace(
'@forkedRepository.sshUrl(settings.sshPort.getOrElse(SystemSettingsService.DefaultSshPort), loginAccount.get.userName)',
'@forkedRepository.httpUrl'
));
$('#merge-command-copy-1').attr('data-clipboard-text', $('#merge-command').text());
});
$('#repository-url-ssh').click(function(){
// Update URL box
$('#repository-url').val('@forkedRepository.sshUrl(settings.sshPort.getOrElse(SystemSettingsService.DefaultSshPort), loginAccount.get.userName)');
$('#repository-url-copy').attr('data-clipboard-text', $('#repository-url').val());
// Update command guidance
$('#merge-command').text($('#merge-command').text().replace(
'@forkedRepository.httpUrl',
'@forkedRepository.sshUrl(settings.sshPort.getOrElse(SystemSettingsService.DefaultSshPort), loginAccount.get.userName)'
));
$('#merge-command-copy-1').attr('data-clipboard-text', $('#merge-command').text());
});
}
});
</script>

View File

@@ -18,9 +18,9 @@
<div>
<div class="show-title pull-right">
@if(hasWritePermission || loginAccount.map(_.userName == issue.openedUserName).getOrElse(false)){
<a class="btn btn-small" href="#" id="edit">Edit</a>
<a class="btn" href="#" id="edit">Edit</a>
}
<a class="btn btn-small btn-success" href="@url(repository)/issues/new">New issue</a>
<a class="btn btn-success" href="@url(repository)/issues/new">New issue</a>
</div>
<div class="edit-title pull-right" style="display: none;">
<a class="btn" href="#" id="update">Save</a> <a href="#" id="cancel">Cancel</a>

View File

@@ -11,7 +11,7 @@
@html.menu("code", repository){
<div class="head">
<div class="pull-right hide-if-blame"><div class="btn-group">
<a href="@url(repository)/find/@encodeRefName(branch)" class="btn btn-mini" data-toggle="tooltip" data-placement="bottom" data-hotkey="t" title="Quickly jump between files"><i class="icon icon-th-list"></i></a>
<a href="@url(repository)/find/@encodeRefName(branch)" class="btn btn-mini" data-toggle="tooltip" data-placement="bottom" data-hotkey="t" title="Quickly jump between files"><i class="octicon octicon-list-unordered"></i></a>
</div></div>
<div class="line-age-legend">
<span>Newer</span>
@@ -47,57 +47,50 @@
}
}
</div>
<table class="table table-bordered blobview">
<tr>
<th style="font-weight: normal;">
<div class="pull-left">
@avatar(latestCommit, 20)
@user(latestCommit.authorName, latestCommit.authorEmailAddress, "username strong")
<span class="muted">@helper.html.datetimeago(latestCommit.commitTime)</span>
<a href="@url(repository)/commit/@latestCommit.id" class="commit-message">@link(latestCommit.summary, repository)</a>
</div>
<div class="btn-group pull-right">
@if(hasWritePermission && content.viewType == "text" && repository.branchList.contains(branch)){
<a class="btn btn-mini" href="@url(repository)/edit/@encodeRefName(branch)/@pathList.mkString("/")">Edit</a>
}
<a class="btn btn-mini" href="?raw=true">Raw</a>
@if(content.viewType == "text"){
<a class="btn btn-mini blame-action" href="@url(repository)/blame/@latestCommit.id/@pathList.mkString("/")" data-url="@url(repository)/get-blame/@latestCommit.id/@pathList.mkString("/")" data-repository="@url(repository)">Blame</a>
}
<a class="btn btn-mini" href="@url(repository)/commits/@encodeRefName(branch)/@pathList.mkString("/")">History</a>
@if(hasWritePermission){
<a class="btn btn-mini btn-danger" href="@url(repository)/remove/@encodeRefName(branch)/@pathList.mkString("/")">Delete</a>
}
</div>
</th>
</tr>
<tr>
<td>
@if(content.viewType == "text"){
@defining(isRenderable(pathList.reverse.head)){ isRrenderable =>
@if(!isBlame && isRrenderable) {
<div class="box-content markdown-body" style="border: none; padding-left: 16px; padding-right: 16px;">
@renderMarkup(pathList, content.content.get, branch, repository, false, false, true)
</div>
} else {
<pre class="prettyprint linenums blob @if(!isRrenderable){ no-renderable } ">@content.content.get</pre>
}
}
}
@if(content.viewType == "image"){
<img src="?raw=true"/>
}
@if(content.viewType == "large" || content.viewType == "binary"){
<div style="text-align: center; padding-top: 20px; padding-bottom: 20px;">
<a href="?raw=true">View Raw</a><br>
<br>
(Sorry about that, but we can't show files that are this big right now)
<div class="box-header">
@avatar(latestCommit, 20)
@user(latestCommit.authorName, latestCommit.authorEmailAddress, "username strong")
<span class="muted">@helper.html.datetimeago(latestCommit.commitTime)</span>
<a href="@url(repository)/commit/@latestCommit.id" class="commit-message">@link(latestCommit.summary, repository)</a>
<div class="btn-group pull-right">
@if(hasWritePermission && content.viewType == "text" && repository.branchList.contains(branch)){
<a class="btn btn-mini" href="@url(repository)/edit/@encodeRefName(branch)/@pathList.mkString("/")">Edit</a>
}
<a class="btn btn-mini" href="?raw=true">Raw</a>
@if(content.viewType == "text"){
<a class="btn btn-mini blame-action" href="@url(repository)/blame/@latestCommit.id/@pathList.mkString("/")" data-url="@url(repository)/get-blame/@latestCommit.id/@pathList.mkString("/")" data-repository="@url(repository)">Blame</a>
}
<a class="btn btn-mini" href="@url(repository)/commits/@encodeRefName(branch)/@pathList.mkString("/")">History</a>
@if(hasWritePermission && repository.branchList.contains(branch)){
<a class="btn btn-mini btn-danger" href="@url(repository)/remove/@encodeRefName(branch)/@pathList.mkString("/")">Delete</a>
}
</div>
</div>
@if(content.viewType == "text"){
@defining(isRenderable(pathList.reverse.head)){ isRrenderable =>
@if(!isBlame && isRrenderable) {
<div class="box-content-bottom markdown-body" style="padding-left: 16px; padding-right: 16px;">
@renderMarkup(pathList, content.content.get, branch, repository, false, false, true)
</div>
} else {
<div class="box-content-bottom">
<pre class="prettyprint linenums blob @if(!isRrenderable){ no-renderable } ">@content.content.get</pre>
</div>
}
</td>
</tr>
</table>
}
}
@if(content.viewType == "image"){
<div class="box-content-bottom">
<img src="?raw=true"/>
</div>
}
@if(content.viewType == "large" || content.viewType == "binary"){
<div class="box-content-bottom" style="text-align: center; padding-top: 20px; padding-bottom: 20px;">
<a href="?raw=true">View Raw</a><br>
<br>
(Sorry about that, but we can't show files that are this big right now)
</div>
}
}
}
<script src="@assets/vendors/jquery/jquery.ba-hashchange.js"></script>
@@ -111,36 +104,38 @@ $(window).load(function(){
function updateSourceLineNum(){
$('.source-line-num').remove();
var pos = pre.find('ol.linenums').position();
$('<div class="source-line-num">').css({
height:pre.height(),
width:'48px',
cursor:'pointer',
position: 'absolute',
top : pos.top + 'px',
left : pos.left + 'px'
}).click(function(e){
$(window).hashchange(function(){})
var pos = $(this).data("pos");
if(!pos){
pos = $('ol.linenums li').map(function(){ return {id:$(this).attr("id"),top:$(this).position().top} }).toArray();
$(this).data("pos",pos);
}
for(var i=0;i<pos.length-1;i++){
if(pos[i+1].top>e.pageY){
break;
if(pos){
$('<div class="source-line-num">').css({
height : pre.height(),
width : '48px',
cursor : 'pointer',
position: 'absolute',
top : pos.top + 'px',
left : pos.left + 'px'
}).click(function(e){
$(window).hashchange(function(){})
var pos = $(this).data("pos");
if(!pos){
pos = $('ol.linenums li').map(function(){ return { id: $(this).attr("id"), top: $(this).position().top} }).toArray();
$(this).data("pos",pos);
}
}
var line = pos[i].id.replace(/^L/,'');
var hash = location.hash;
if(e.shiftKey == true && hash.match(/#L\d+(-L\d+)?/)){
var lines = hash.split('-');
location.hash = lines[0] + '-L' + line;
} else {
var p = $("#L"+line).attr('id',"");
location.hash = '#L' + line;
p.attr('id','L'+line);
}
}).appendTo(pre);
for(var i = 0; i < pos.length-1; i++){
if(pos[i + 1].top > e.pageY){
break;
}
}
var line = pos[i].id.replace(/^L/,'');
var hash = location.hash;
if(e.shiftKey == true && hash.match(/#L\d+(-L\d+)?/)){
var lines = hash.split('-');
location.hash = lines[0] + '-L' + line;
} else {
var p = $("#L"+line).attr('id',"");
location.hash = '#L' + line;
p.attr('id','L'+line);
}
}).appendTo(pre);
}
}
var repository = $('.blame-action').data('repository');
$('.blame-action').click(function(e){
@@ -152,11 +147,11 @@ $(window).load(function(){
});
function updateBlame(){
var m = /^\/(blame|blob)(\/.*)$/.exec(location.href.substring(repository.length));
var m = /\/(blame|blob)(\/.*)$/.exec(location.href);
var mode = m[1];
$('.blame-action').toggleClass("active", mode=='blame').attr('href', repository + (m[1]=='blame'?'/blob':'/blame')+m[2]);
if(pre.parents("td").find(".blame").length){
pre.parents("div.container").toggleClass("blame-container", mode=='blame');
$('.blame-action').toggleClass("active", mode=='blame').attr('href', repository + (m[1] == 'blame' ? '/blob' : '/blame') + m[2]);
if(pre.parents("div.box-content-bottom").find(".blame").length){
pre.parents("div.container").toggleClass("blame-container", mode == 'blame');
updateSourceLineNum();
return;
}
@@ -164,47 +159,47 @@ $(window).load(function(){
updateSourceLineNum();
return;
}
$(document.body).toggleClass('no-box-shadow',document.body.style.boxShadow===undefined);
$(document.body).toggleClass('no-box-shadow', document.body.style.boxShadow===undefined);
$('.blame-action').addClass("active");
var base = $('<div class="blame">').css({height:pre.height()}).prependTo(pre.parents("td")[0]);
var base = $('<div class="blame">').css({height: pre.height()}).prependTo(pre.parents("div.box-content-bottom"));
base.parents("div.container").addClass("blame-container");
updateSourceLineNum();
$.get($('.blame-action').data('url')).done(function(data){
var blame = data.blame;
var index = [];
for(var i=0;i<blame.length;i++){
for(var j=0;j<blame[i].lines.length;j++){
index[blame[i].lines[j]]=blame[i];
for(var i = 0; i < blame.length; i++){
for(var j = 0; j < blame[i].lines.length; j++){
index[blame[i].lines[j]] = blame[i];
}
}
var blame, lastDiv, now=new Date().getTime();
var blame, lastDiv, now = new Date().getTime();
$('pre.prettyprint ol.linenums li').each(function(i, e){
var p=$(e).position();
var h=$(e).height();
var p = $(e).position();
var h = $(e).height();
if(blame == index[i]){
lastDiv.css("min-height",(p.top+h+1) - lastDiv.position().top);
lastDiv.css("min-height",(p.top + h + 1) - lastDiv.position().top);
}else{
$(e).addClass('blame-sep')
blame = index[i];
var sha = $('<div class="blame-sha">')
.append($('<a>').attr("href",data.root+'/commit/'+blame.id).text(blame.id.substr(0,7)));
.append($('<a>').attr("href", data.root + '/commit/' + blame.id).text(blame.id.substr(0,7)));
if(blame.prev){
sha.append($('<br />'))
.append($('<a class="muted-link">').text('prev').attr("href",data.root+'/blame/'+blame.prev+'/'+(blame.prevPath||data.path)));
.append($('<a class="muted-link">').text('prev').attr("href", data.root + '/blame/' + blame.prev + '/' + (blame.prevPath || data.path)));
}
lastDiv = $('<div class="blame-info">')
.addClass('heat'+Math.min(10,Math.max(1,Math.ceil((now-blame.commited)/(24*3600*1000*70)))))
.toggleClass('blame-last',blame.id==data.last)
.addClass('heat' + Math.min(10, Math.max(1, Math.ceil((now - blame.commited) / (24 * 3600 * 1000 * 70)))))
.toggleClass('blame-last', blame.id == data.last)
.data('line', (i + 1))
.css({
"top" : p.top + 'px',
"min-height" : h+'px'
"top" : p.top + 'px',
"min-height" : h + 'px'
})
.append(sha)
.append($(blame.avatar).addClass('avatar').css({"float":"left"}))
.append($(blame.avatar).addClass('avatar').css({"float": "left"}))
.append($('<div class="blame-commit-title">').text(blame.message))
.append($('<div class="muted">').html(blame.author+ " authed "+blame.authed))
.append($('<div class="muted">').html(blame.author + " authed " + blame.authed))
.appendTo(base);
}
});
@@ -214,6 +209,8 @@ $(window).load(function(){
updateBlame();
});
var scrolling = false;
/**
* Hightlight lines which are specified by URL hash.
*/
@@ -224,7 +221,7 @@ function updateHighlighting(){
var lines = hash.substr(1).split('-');
if(lines.length == 1){
$('#' + lines[0]).addClass('highlight');
if(!updateHighlighting.scrolling){
if(!scrolling){
$(window).scrollTop($('#' + lines[0]).offset().top - 40);
}
} else if(lines.length > 1){
@@ -233,11 +230,11 @@ function updateHighlighting(){
for(var i = start; i <= end; i++){
$('#L' + i).addClass('highlight');
}
if(!updateHighlighting.scrolling){
if(!scrolling){
$(window).scrollTop($('#L' + start).offset().top - 40);
}
}
updateHighlighting.scrolling = true;
scrolling = true;
}
}
</script>

View File

@@ -35,7 +35,7 @@
}.getOrElse {
encodeRefName(repository.repository.defaultBranch)
}}...@{encodeRefName(branch.name)}?expand=1" class="btn btn-small">New Pull Request</a>
}else{
} else {
<a href="@url(repository)/compare/@{repository.repository.parentUserName.map { parent =>
urlEncode(parent) + ":" + encodeRefName(repository.repository.defaultBranch)
}.getOrElse {
@@ -45,9 +45,9 @@
}
@if(hasWritePermission){
@if(prs.map(!_._2.closed).getOrElse(false)){
<a class="btn disabled btn-mini" data-toggle="tooltip" title="You cant delete this branch because it has an open pull request"><i class="icon icon-trash icon-white"></i></a>
<a class="btn disabled btn-mini" data-toggle="tooltip" title="You cant delete this branch because it has an open pull request"><i class="octicon octicon-trashcan"></i></a>
}else{
<a href="@url(repository)/delete/@encodeRefName(branch.name)" class="btn @if(info.isMerged){ btn-warning }else{ btn-danger } delete-branch btn-mini" data-name="@branch.name" @if(info.isMerged){ data-toggle="tooltip" title="this branch is merged" }><i class="icon icon-trash icon-white"></i></a>
<a href="@url(repository)/delete/@encodeRefName(branch.name)" class="btn @if(info.isMerged){ btn-warning }else{ btn-danger } delete-branch btn-mini" data-name="@branch.name" @if(info.isMerged){ data-toggle="tooltip" title="this branch is merged" }><i class="octicon octicon-trashcan"></i></a>
}
}
}

View File

@@ -14,7 +14,7 @@
@html.menu("code", repository){
<table class="table table-bordered">
<tr>
<th>
<th class="box-header">
<div class="pull-right align-right">
<a href="@url(repository)/tree/@commit.id" class="btn btn-small">Browse code</a>
</div>
@@ -74,7 +74,7 @@
</div>
@if(commit.isDifferentFromAuthor) {
<div class="committer">
<span class="icon-arrow-right"></span>
<span class="octicon octicon-arrow-right"></span>
<span>@user(commit.committerName, commit.committerEmailAddress, "username strong")</span>
<span class="muted"> committed @helper.html.datetimeago(commit.commitTime)</span>
</div>

View File

@@ -10,72 +10,81 @@
@html.main(s"${repository.owner}/${repository.name}", Some(repository)) {
@html.menu("code", repository){
<div class="head">
@helper.html.branchcontrol(
branch,
repository,
hasWritePermission
){
@repository.branchList.map { x =>
<li><a href="@url(repository)/commits/@encodeRefName(x)">@helper.html.checkicon(x == branch) @x</a></li>
}
}
@if(pathList.isEmpty){
<a href="@url(repository)/tree/@encodeRefName(branch)">@repository.name</a> / Commit History
@helper.html.branchcontrol(
branch,
repository,
hasWritePermission
){
@repository.branchList.map { x =>
<li><a href="@url(repository)/commits/@encodeRefName(x)">@helper.html.checkicon(x == branch) @x</a></li>
}
}
}
@if(pathList.nonEmpty){
<span class="muted">History for</span>
<a href="@url(repository)/tree/@encodeRefName(branch)">@repository.name</a> /
<a class="strong" href="@url(repository)/tree/@encodeRefName(branch)">@repository.name</a> /
@pathList.zipWithIndex.map { case (section, i) =>
@if(i == pathList.length - 1){
@section
<span class="strong">@section</span>
} else {
<a href="@url(repository)/tree/@encodeRefName(branch)/@pathList.take(i + 1).mkString("/")">@section</a> /
<a class="strong" href="@url(repository)/tree/@encodeRefName(branch)/@pathList.take(i + 1).mkString("/")">@section</a> /
}
}
}
</div>
@commits.map { day =>
<table class="table table-bordered">
<tr>
<th>@date(day.head.commitTime)</th>
</tr>
@day.map { commit =>
<tr>
<td>
<div class="pull-right align-right">
<a href="@url(repository)/commit/@commit.id" class="btn btn-small monospace">@commit.id.substring(0, 10)</a><br>
<a href="@url(repository)/tree/@commit.id" class="small">Browse code</a>
</div>
<div>
<div class="commit-avatar-image">@avatar(commit, 40)</div>
<div class="commit-message-box">
<a href="@url(repository)/commit/@commit.id" class="commit-message" style="font-weight: bold;">@link(commit.summary, repository)</a>
@if(commit.description.isDefined){
<a href="javascript:void(0)" onclick="$('#description-@commit.id').toggle();" class="omit">...</a>
}
<br>
@if(commit.description.isDefined){
<pre id="description-@commit.id" style="display: none;" class="commit-description">@link(commit.description.get, repository)</pre>
}
<div class="small">
@user(commit.authorName, commit.authorEmailAddress, "username")
<span class="muted">authored @helper.html.datetimeago(commit.authorTime)</span>
@if(commit.isDifferentFromAuthor) {
<span class="icon-arrow-right" style="margin-top : -2px ;"></span>
@user(commit.committerName, commit.committerEmailAddress, "username")
<span class="muted">committed @helper.html.datetimeago(commit.authorTime)</span>
<div class="commit-list">
@commits.map { day =>
<div class="muted" style="background-color: white;">
<i class="octicon octicon-git-commit"></i> Commits on @date(day.head.commitTime)
</div>
<div class="box-commits">
@day.map { commit =>
<div class="box-content-row" style="padding: 8px;">
<ul class="nav nav-pills-group pull-right" style="margin-top: 2px; margin-bottom: 0px; margin-right: 4px;">
<li class="first"><a href="@url(repository)/commit/@commit.id" class="link monospace">@commit.id.substring(0, 7)</a></li>
<li class="last"><a href="@url(repository)/tree/@commit.id" style="padding-top: 9px; padding-bottom: 10px;"><i class="octicon octicon-code link"></i></a></li>
</ul>
<div>
<div class="commit-avatar-image">@avatar(commit, 40)</div>
<div class="commit-message-box">
<a href="@url(repository)/commit/@commit.id" class="commit-message" style="font-weight: bold;">@link(commit.summary, repository)</a>
@if(commit.description.isDefined){
<a href="javascript:void(0)" onclick="$('#description-@commit.id').toggle();" class="omit">...</a>
}
<br>
@if(commit.description.isDefined){
<pre id="description-@commit.id" style="display: none;" class="commit-description">@link(commit.description.get, repository)</pre>
}
<div class="small">
@user(commit.authorName, commit.authorEmailAddress, "username")
<span class="muted">authored @helper.html.datetimeago(commit.authorTime)</span>
@if(commit.isDifferentFromAuthor) {
<span class="octicon octicon-arrow-right" style="margin-top : -2px;"></span>
@user(commit.committerName, commit.committerEmailAddress, "username")
<span class="muted">committed @helper.html.datetimeago(commit.authorTime)</span>
}
</div>
</div>
</div>
</div>
</td>
</tr>
}
</div>
}
</div>
<div class="pagination" style="text-align: center; margin-top: 30px">
<ul>
@if(page <= 1){
<li class="disabled"><span>Newer</span></li>
} else {
<li><a href="?page=@{page - 1}">Newer</a></li>
}
</table>
}
<div class="btn-group">
<button class="btn" onclick="location.href='?page=@{page - 1}'"@if(page <= 1){ disabled="true"}>&lt; Newer</button>
<button class="btn" onclick="location.href='?page=@{page + 1}'"@if(!hasNext){ disabled="true"}>Older &gt;</button>
@if(!hasNext){
<li class="disabled"><span>Older</span></li>
} else {
<li><a href="?page=@{page + 1}">Older</a></li>
}
</ul>
</div>
}
}

View File

@@ -15,15 +15,15 @@
@html.menu("code", repository, Some(branch), pathList.isEmpty, groupNames.isEmpty, info, error){
<div class="head">
<div class="pull-right"><div class="btn-group">
<a href="@url(repository)/find/@encodeRefName(branch)" class="btn btn-mini" data-toggle="tooltip" data-placement="bottom" data-hotkey="t" title="Quickly jump between files"><i class="icon icon-th-list"></i></a>
<a href="@url(repository)/find/@encodeRefName(branch)" class="btn btn-small" data-toggle="tooltip" data-placement="bottom" data-hotkey="t" title="Quickly jump between files"><i class="octicon octicon-list-unordered"></i></a>
@if(pathList.nonEmpty){
<a href="@url(repository)/commits/@encodeRefName(branch)/@pathList.mkString("/")" class="btn btn-mini" data-toggle="tooltip" data-placement="bottom" title="Browse commits for this branch"><i class="icon icon-time"></i></a>
<a href="@url(repository)/commits/@encodeRefName(branch)/@pathList.mkString("/")" class="btn btn-small" data-toggle="tooltip" data-placement="bottom" title="Browse commits for this branch"><i class="octicon octicon-clock"></i></a>
}
</div></div>
@branchPullRequest.map{ case (pullRequest, issue) =>
<a href="@url(repository)/pull/@pullRequest.issueId" class="btn btn-pullrequest-branch btn-mini" title="@issue.title" data-toggle="tooltip">#@pullRequest.issueId</a>
<a href="@url(repository)/pull/@pullRequest.issueId" class="btn btn-small btn-pullrequest-branch" title="@issue.title" data-toggle="tooltip">#@pullRequest.issueId</a>
}.getOrElse{
<a href="@url(repository)/compare?head=@urlEncode(encodeRefName(branch))" class="btn btn-success btn-mini"><i class="icon-white icon-retweet" data-toggle="tooltip" title="Compare, review, create a pull request"></i></a>
<a href="@url(repository)/compare?head=@urlEncode(encodeRefName(branch))" class="btn btn-small btn-success"><i class="octicon octicon-git-compare" data-toggle="tooltip" title="Compare, review, create a pull request"></i></a>
}
@helper.html.branchcontrol(
branch,
@@ -44,7 +44,7 @@
</div>
<table class="table table-file-list">
<tr>
<th colspan="4" style="font-weight: normal;">
<th colspan="4" style="font-weight: normal; border: none;">
<a href="@url(repository)/commit/@latestCommit.id" class="commit-message">@link(latestCommit.summary, repository)</a>
@if(latestCommit.description.isDefined){
<a href="javascript:void(0)" onclick="$('#description-@latestCommit.id').toggle();" class="omit">...</a>
@@ -66,7 +66,7 @@
</div>
@if(latestCommit.isDifferentFromAuthor) {
<div class="committer">
<span class="icon-arrow-right"></span>
<span class="octicon octicon-arrow-right"></span>
<span>@user(latestCommit.committerName, latestCommit.committerEmailAddress, "username strong")</span>
<span class="muted"> committed @helper.html.datetimeago(latestCommit.commitTime)</span>
</div>
@@ -77,7 +77,7 @@
</tr>
@if(pathList.size > 0){
<tr>
<td width="16"></td>
<td width="16" class="file-icon"></td>
<td><a href="@url(repository)@if(pathList.size > 1){/tree/@encodeRefName(branch)/@pathList.init.mkString("/")}">..</a></td>
<td></td>
<td></td>
@@ -85,7 +85,7 @@
}
@files.map { file =>
<tr>
<td width="16">
<td width="16" class="file-icon">
@if(file.isDirectory){
@if(file.linkUrl.isDefined){
<i class="octicon octicon-file-symlink-directory"></i>
@@ -96,7 +96,7 @@
<i class="octicon octicon-file-text"></i>
}
</td>
<td>
<td class="content-name">
@if(file.isDirectory){
@if(file.linkUrl.isDefined){
<a href="@file.linkUrl">
@@ -118,8 +118,8 @@
}
</td>
<td class="mute">
<a href="@url(repository)/commit/@file.commitId" class="commit-message">@link(file.message, repository)</a>
[@user(file.author, file.mailAddress)]
<a href="@url(repository)/commit/@file.commitId" class="commit-message shorten-text" title="@file.message">@link(file.message, repository)</a>
<span class="commit-author">[@user(file.author, file.mailAddress)]</span>
</td>
<td style="text-align: right;">@helper.html.datetimeago(file.time, false)</td>
</tr>
@@ -128,7 +128,7 @@
@readme.map { case(filePath, content) =>
<div id="readme">
<div class="box-header">@filePath.reverse.head</div>
<div class="box-content markdown-body">@renderMarkup(filePath, content, branch, repository, false, false, true)</div>
<div class="box-content-bottom markdown-body" style="padding-left: 16px; padding-right: 16px;">@renderMarkup(filePath, content, branch, repository, false, false, true)</div>
</div>
}
}

View File

@@ -27,8 +27,8 @@
<table id="tree-finder-results" class="table table-file-list" data-url="@url(repository)/tree-list/@treeId">
<tbody class="tree-browser-result-template">
<tr class="tree-browser-result">
<td class="icon"><span class="icon icon-chevron-right"></span></td>
<td class="icon"><img src="@assets/common/images/file.png"/></td>
<td class="icon"><span class="octicon octicon-chevron-right"></span></td>
<td class="icon"><i class="octicon octicon-file-text"></i></td>
<td>
<a href="@url(repository)/blob/@encodeRefName(branch)"></a>
</td>

View File

@@ -24,7 +24,7 @@
Opened by <a href="@url(issue.openedUserName)" class="username">@issue.openedUserName</a>
@helper.html.datetimeago(issue.registeredDate)
@if(issue.commentCount > 0){
&nbsp;&nbsp;<i class="icon-comment"></i><span class="strong">@issue.commentCount</span> @plural(issue.commentCount, "comment")
&nbsp;&nbsp;<i class="octicon octicon-comment"></i><span class="strong">@issue.commentCount</span> @plural(issue.commentCount, "comment")
}
</div>
</div>

View File

@@ -91,9 +91,9 @@
</div>
</div>
*@
<fieldset>
<div class="align-right" style="margin-top: 20px;">
<input type="submit" class="btn btn-success" value="Apply changes"/>
</fieldset>
</div>
</form>
}
}

View File

@@ -1,29 +1,23 @@
@(systemSettings: gitbucket.core.service.SystemSettingsService.SystemSettings)(implicit context: gitbucket.core.controller.Context)
@import context._
<table class="table table-bordered">
<tr>
<th class="metal">
@if(systemSettings.allowAccountRegistration){
<div class="pull-right">
<a href="@path/register" class="btn btn-mini">Create new account</a>
</div>
}
Sign in
</th>
</tr>
<tr>
<td>
<form action="@path/signin" method="POST" validate="true">
<label for="userName">Username:</label>
<span id="error-userName" class="error"></span>
<input type="text" name="userName" id="userName" style="width: 95%" autofocus/>
<label for="password">Password:</label>
<span id="error-password" class="error"></span>
<input type="password" name="password" id="password" style="width: 95%"/>
<div>
<input type="submit" class="btn btn-success" value="Sign in"/>
</div>
</form>
</td>
</tr>
</table>
<div class="box-header">
@if(systemSettings.allowAccountRegistration){
<div class="pull-right">
<a href="@path/register" class="btn btn-mini">Create new account</a>
</div>
}
<span class="strong">Sign in</span>
</div>
<div class="box-content-bottom">
<form action="@path/signin" method="POST" validate="true">
<label for="userName">Username:</label>
<span id="error-userName" class="error"></span>
<input type="text" name="userName" id="userName" style="width: 95%" autofocus/>
<label for="password">Password:</label>
<span id="error-password" class="error"></span>
<input type="password" name="password" id="password" style="width: 95%"/>
<div>
<input type="submit" class="btn btn-success" value="Sign in"/>
</div>
</form>
</div>

View File

@@ -21,7 +21,7 @@
</ul>
<form action="@url(repository)/wiki/@if(page.isEmpty){_new} else {_edit}" method="POST" validate="true">
<span id="error-pageName" class="error"></span>
<input type="text" name="pageName" value="@pageName" style="width: 850px; font-weight: bold;" placeholder="Input a page name."/>
<input type="text" name="pageName" value="@pageName" style="width: 910px; font-weight: bold;" placeholder="Input a page name."/>
@helper.html.preview(
repository = repository,
content = page.map(_.content).getOrElse(""),
@@ -29,11 +29,11 @@
enableRefsLink = false,
enableTaskList = false,
hasWritePermission = false,
style = "width: 850px; height: 400px;",
style = "width: 910px; height: 400px;",
styleClass = "monospace",
placeholder = ""
)
<input type="text" name="message" value="" style="width: 850px;" placeholder="Write a small message here explaining this change. (Optional)"/>
<input type="text" name="message" value="" style="width: 910px;" placeholder="Write a small message here explaining this change. (Optional)"/>
<input type="hidden" name="currentPageName" value="@pageName"/>
<input type="hidden" name="id" value="@page.map(_.id)"/>
<input type="submit" value="Save" class="btn btn-success">

View File

@@ -25,20 +25,23 @@
</li>
</ul>
<div style="width: 200px;" class="pull-right">
<table class="table table-bordered">
<tr>
<th class="metal">Pages <span class="label">@pages.length</span></th>
</tr>
<tr>
<td>
<ul style="margin-left: 0px; margin-bottom: 0px; word-break: break-all; width: 182px;">
@pages.map { page =>
<li style="margin-left:0px; list-style-type: none;"><a href="@url(repository)/wiki/@urlEncode(page)">@page</a></li>
}
</ul>
</td>
</tr>
</table>
@defining(15){ max =>
<div class="box-header">
<span class="strong">Pages</span> <span class="label">@pages.length</span>
</div>
<div class="box-content-bottom" style="padding: 0px;">
@pages.zipWithIndex.map { case (page, i) =>
<div class="box-content-row page-link" style="border: none; @if(i > max - 1){display:none;}">
<a href="@url(repository)/wiki/@urlEncode(page)" class="strong">@page</a>
</div>
}
@if(pages.size > max){
<div class="box-content-row show-more">
<a href="javascript:void(0);" id="show-more-pages">Show more @{pages.size - max} pages...</a>
</div>
}
</div>
}
<div class="small">
<strong>Clone this wiki locally</strong>
</div>
@@ -58,9 +61,14 @@
</div>
}
}
@if(settings.ssh && loginAccount.isDefined){
<script>
$(function(){
<script>
$(function(){
$('#show-more-pages').click(function(e){
$('div.page-link').show();
$(e.target).parents('div.show-more').remove();
});
@if(settings.ssh && loginAccount.isDefined){
$('#repository-url-http').click(function(){
$('#repository-url').val('@httpUrl(repository)');
$('#repository-url-copy').attr('data-clipboard-text', $('#repository-url').val());
@@ -69,6 +77,6 @@
$('#repository-url').val('@sshUrl(repository, settings, loginAccount.get.userName)');
$('#repository-url-copy').attr('data-clipboard-text', $('#repository-url').val());
});
});
</script>
}
}
});
</script>

View File

@@ -60,6 +60,10 @@ h6 {
.head .octicon,.head .mega-octicon{
color : #BBB;
}
.align-right {
text-align: right;
}
/* ======================================================================== */
/* Global Header */
/* ======================================================================== */
@@ -131,15 +135,6 @@ a.global-header-menu {
line-height: 3.5;
}
/*
img.plugin-global-menu {
width: 16px;
height: 16px;
position: relative;
top: -2px;
}
*/
/* ======================================================================== */
/* General Styles */
/* ======================================================================== */
@@ -155,7 +150,7 @@ div.head div.forked {
}
div.container {
width: 920px;
width: 980px;
}
div.container-wide {
@@ -184,6 +179,12 @@ span.error {
font-weight: bold;
}
.shorten-text {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
a.commit-message, a.commit-id, a.username, a.issue-comment-count {
color: #333333;
}
@@ -199,6 +200,15 @@ a.omit:hover {
background-color: #aaa;
}
div.show-more {
text-align: center;
border-top: 1px solid silver;
}
div.show-more a {
color: #7aa1d3;
}
span.count-right {
float: right;
font-weight: bold;
@@ -227,82 +237,81 @@ h3 {
margin-top: 0px;
}
div.box {
background-color: #efefef;
padding: 2px;
margin-bottom: 10px;
}
div.box-header {
font-size: 120%;
font-weight: bold;
background-color: #e0e0e0;
background-image: -moz-linear-gradient(#fafafa, #e0e0e0);
background-image: -webkit-linear-gradient(#fafafa, #e0e0e0);
background-image: linear-gradient(#fafafa, #e0e0e0);
background-repeat: repeat-x;
background-color: #f5f5f5;
margin: 0;
border-top-left-radius: 1px;
border-top-right-radius: 1px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border: 1px solid #d8d8d8;
border-bottom: none;
padding: 8px 10px 8px 10px;
text-shadow: 0 1px 0 #fff
}
div.box-header-small {
background-color: #e0e0e0;
background-image: -moz-linear-gradient(#fafafa, #e0e0e0);
background-image: -webkit-linear-gradient(#fafafa, #e0e0e0);
background-image: linear-gradient(#fafafa, #e0e0e0);
background-repeat: repeat-x;
margin: 0;
border-top-left-radius: 1px;
border-top-right-radius: 1px;
border: 1px solid #d8d8d8;
border-bottom: none;
padding: 6px 4px 6px 4px;
text-shadow: 0 1px 0 #fff
padding: 8px 8px 8px 8px;
}
.inline-comment div.box-header-small {
background: #f2f8fa;
}
.commit-list {
position: relative;
}
.commit-list::before {
position: absolute;
top: 0;
bottom: 0;
left: 6px;
z-index: -1;
display: block;
width: 2px;
content: "";
background-color: #f3f3f3;
}
ul.nav-pills-group .link {
color: #4078c0;
}
div.box-commits {
background-color: white;
border: 1px solid #d8d8d8;
padding-left: 0px;
padding-right: 0px;
margin-top: 10px;
margin-bottom: 10px;
margin-left: 20px;
}
div.box-content {
background-color: white;
border: 1px solid #d8d8d8;
padding: 4px;
border-radius: 3px;
}
th.box-header {
background-color: #e0e0e0;
background-image: -moz-linear-gradient(#fafafa, #e0e0e0);
background-image: -webkit-linear-gradient(#fafafa, #e0e0e0);
background-image: linear-gradient(#fafafa, #e0e0e0);
background-repeat: repeat-x;
margin: 0;
border-top-left-radius: 1px;
border-top-right-radius: 1px;
div > div.box-content-row:nth-of-type(1) {
border: none;
}
div.box-content-row {
border-top: 1px solid #d8d8d8;
padding: 4px;
}
div.box-content-bottom {
background-color: white;
border: 1px solid #d8d8d8;
border-bottom: none;
text-shadow: 0 1px 0 #fff
padding: 4px;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
margin-bottom: 20px;
}
table.table th.box-header {
background-color: #f5f5f5;
}
th.box-header .octicon {
display: inline;
}
th.metal {
background-color: #e0e0e0;
background-image: -moz-linear-gradient(#fafafa, #e8e8e8);
background-image: -webkit-linear-gradient(#fafafa, #e8e8e8);
background-image: linear-gradient(#fafafa, #e8e8e8);
background-repeat: repeat-x;
margin: 0;
border-top-left-radius: 1px;
border-top-right-radius: 1px;
display: inline;
}
dl {
@@ -374,6 +383,22 @@ span.highlight {
cursor: pointer;
}
.btn .octicon {
color: #333;
}
.btn-success .octicon {
color: #fff;
}
.btn-warning .octicon {
color: #fff;
}
.btn-danger .octicon {
color: #fff;
}
/****************************************************************************/
/* Side Menu */
/****************************************************************************/
@@ -381,23 +406,30 @@ ul.sidemenu {
margin-left: 0px;
}
ul.sidemenu a:hover{
ul.sidemenu a {
display: block;
padding: 8px 10px;
}
ul.sidemenu a:hover {
text-decoration: none;
}
ul.sidemenu li.active {
border-top: 1px solid #eee;
border-bottom: 1px solid #eee;
border-right: 2px solid #bb4444;
border-right: 3px solid #bb4444;
border-left: 1px solid white;
}
ul.sidemenu div.gradient {
width: 5px;
height: 30px;
background: linear-gradient(to right, #eee, #fff);
margin-right: 4px;
border-left: 1px solid #eee;
ul.sidemenu li.active a {
background-color: #fff;
}
ul.sidemenu {
background-image: -webkit-linear-gradient(left, #f6f6f6 0%, #fff 8px);
background-image: linear-gradient(to right, #f6f6f6 0%, #fff 8px);
box-shadow: inset 1px 0 0 #eee;
}
ul.sidemenu div.margin {
@@ -408,8 +440,6 @@ ul.sidemenu div.margin {
}
ul.sidemenu li {
line-height: 30px;
height: 30px;
border-left: 1px solid #eee;
margin-left:0px;
border-right: 2px solid white;
@@ -485,36 +515,24 @@ ul.nav-stacked.side-menu li.active a:hover {
}
.nav-tabs.nav-stacked.side-menu > li:first-child > a {
-webkit-border-top-right-radius: 0px;
border-top-right-radius: 0px;
-webkit-border-top-left-radius: 0px;
border-top-left-radius: 0px;
-moz-border-radius-topright: 0px;
-moz-border-radius-topleft: 0px;
border-top-right-radius: 3px;
border-top-left-radius: 3px;
}
.nav-tabs.nav-stacked.side-menu > li:last-child > a {
-webkit-border-bottom-right-radius: 0px;
border-bottom-right-radius: 0px;
-webkit-border-bottom-left-radius: 0px;
border-bottom-left-radius: 0px;
-moz-border-radius-bottomright: 0px;
-moz-border-radius-bottomleft: 0px;
border-bottom-right-radius: 3px;
border-bottom-left-radius: 3px;
}
/****************************************************************************/
/* Repositories */
/****************************************************************************/
div.repository-icon {
position: absolute;
position: absolute;
}
div.repository-content {
margin-left: 40px;
margin-left: 40px;
}
.branches .muted-link{
@@ -604,15 +622,11 @@ p.description {
a.header-link {
color: #888;
font-size: 90%;
}
a.header-link i.octicon {
opacity: 0.5;
display: block;
}
a.header-link strong {
color: black;
font-size: 90%;
}
a.header-link:hover {
@@ -639,14 +653,17 @@ a.header-link:hover i.octicon-x{
color: #FFF;
}
/*
table.blobview {
table-layout: fixed;
}
*/
table.table-file-list {
margin-bottom: 0px;
border: 1px solid #ddd;
border-radius: 3px;
border-collapse: separate;
}
table.table-file-list th, table.table-file-list td {
@@ -665,6 +682,25 @@ table.table-file-list td {
font-size: small;
}
table.table-file-list .file-icon {
padding-right: 1px;
}
table.table-file-list .content-name {
max-width: 180px;
}
table.table-file-list .commit-message {
max-width: 415px;
display: inline-block;
}
table.table-file-list .commit-author {
color: #999;
font-size: 12px;
float: right;
}
th, td, .table th, .table td {
padding-top: 4px;
padding-bottom: 4px;
@@ -876,6 +912,10 @@ a.issue-title {
font-size: 120%;
}
.label-success {
background-color: #6cc644;
}
ul.label-list {
list-style-type: none;
padding-left: 0px;
@@ -979,8 +1019,16 @@ div.issue-info {
}
div.issue-content {
padding: 8px;
background-color: #fbfbfb;
padding: 13px;
background-color: #fff;
}
div.issue-content p:first-child {
margin-top: 0;
}
div.issue-content p:last-child {
margin-bottom: 0;
}
h4#issueTitle {
@@ -1007,17 +1055,47 @@ div.issue-participants {
div.issue-comment-box, div.commit-comment-box {
margin-bottom: 15px;
margin-left: 50px;
margin-left: 70px;
max-width: 820px;
}
div.issue-comment-box textarea {
width: 670px;
height: 100px;
max-height: 300px;
}
div.issue-comment-action {
padding-bottom: 10px;
padding-top: 0px;
margin-left: 70px;
margin-bottom: 10px;
border-bottom: 4px solid #ddd;
}
div.issue-comment-action .octicon {
border-radius: 50%;
background-color: #f3f3f3;
color: #767676;
font-size: 18px;
margin-right: 7px;
width: 28px;
height: 28px;
line-height: 28px;
text-align: center;
border: 2px solid #fff;
}
div.issue-reopened .octicon {
background-color: #6cc644;
color: #fff;
}
div.issue-comment-action .octicon.danger {
background-color: #bd2c00;
color: #fff;
}
.nav-pills > li > span.issue-label {
display: block;
padding: 0px 8px 2px 8px;
@@ -1406,6 +1484,7 @@ div.markdown-body {
font: 15px Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
word-wrap: break-word;
}
div.markdown-body h1 {
border-bottom: 1px solid #ddd;
font-size: 2.5em;
@@ -1676,9 +1755,12 @@ h6 a.markdown-anchor-link {
padding-left: 50px;
}
/*
div.container.blame-container{
width:1270px;
}
*/
.line-age-legend {
display: none;
}

View File

@@ -231,13 +231,13 @@ body {
}
a {
color: #0088cc;
color: #4078c0;
text-decoration: none;
}
a:hover,
a:focus {
color: #005580;
color: #4078c0;
text-decoration: underline;
}

View File

@@ -56,7 +56,7 @@ class JsonFormatSpec extends Specification {
"default_branch" : "master",
"owner" : $apiUserJson,
"forks_count" : 0,
"watchers_coun" : 0,
"watchers_count" : 0,
"url" : "${context.baseUrl}/api/v3/repos/octocat/Hello-World",
"http_url" : "${context.baseUrl}/git/octocat/Hello-World.git",
"clone_url" : "${context.baseUrl}/git/octocat/Hello-World.git",