mirror of
https://github.com/gitbucket/gitbucket.git
synced 2026-07-06 23:49:27 +02:00
Fix user interface of releases
This commit is contained in:
@@ -8,8 +8,6 @@
|
||||
<column name="TAG" type="varchar(100)" nullable="false"/>
|
||||
<column name="AUTHOR" type="varchar(100)" nullable="false"/>
|
||||
<column name="CONTENT" type="text" nullable="true"/>
|
||||
<column name="IS_DRAFT" type="boolean" nullable="false"/>
|
||||
<column name="IS_PRERELEASE" type="boolean" nullable="false"/>
|
||||
<column name="REGISTERED_DATE" type="datetime" nullable="false"/>
|
||||
<column name="UPDATED_DATE" type="datetime" nullable="false"/>
|
||||
</createTable>
|
||||
|
||||
@@ -2,7 +2,6 @@ package gitbucket.core.controller
|
||||
|
||||
import gitbucket.core.model.Account
|
||||
import gitbucket.core.service.{AccountService, RepositoryService, ReleaseService}
|
||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
import gitbucket.core.servlet.Database
|
||||
import gitbucket.core.util._
|
||||
import gitbucket.core.util.SyntaxSugars._
|
||||
@@ -89,21 +88,16 @@ class FileUploadController extends ScalatraServlet
|
||||
} getOrElse BadRequest()
|
||||
}
|
||||
|
||||
post("/release/:owner/:repository/:id"){
|
||||
session.get(Keys.Session.LoginAccount).collect { case loginAccount: Account =>
|
||||
post("/release/:owner/:repository/:tag"){
|
||||
session.get(Keys.Session.LoginAccount).collect { case _: Account =>
|
||||
val owner = params("owner")
|
||||
val repository = params("repository")
|
||||
val releaseId = params("id").toInt
|
||||
val release = getRelease(owner, repository, releaseId)
|
||||
val tag = params("tag")
|
||||
execute({ (file, fileId) =>
|
||||
val fileName = file.getName
|
||||
release.map { rel =>
|
||||
createReleaseAsset(owner, repository, releaseId, fileId, fileName, file.size, loginAccount)
|
||||
FileUtils.writeByteArrayToFile(new java.io.File(
|
||||
getReleaseFilesDir(owner, repository) + s"/${releaseId}",
|
||||
fileId), file.get)
|
||||
fileName
|
||||
}
|
||||
FileUtils.writeByteArrayToFile(
|
||||
new java.io.File(getReleaseFilesDir(owner, repository), tag + "/" + fileId),
|
||||
file.get
|
||||
)
|
||||
}, _ => true)
|
||||
}.getOrElse(BadRequest())
|
||||
}
|
||||
|
||||
@@ -6,11 +6,10 @@ import gitbucket.core.service.{AccountService, ActivityService, ReleaseService,
|
||||
import gitbucket.core.util.{FileUtil, ReadableUsersAuthenticator, ReferrerAuthenticator, WritableUsersAuthenticator}
|
||||
import gitbucket.core.util.Directory._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.util.SyntaxSugars._
|
||||
import gitbucket.core.view.Markdown
|
||||
import org.scalatra.forms._
|
||||
import gitbucket.core.releases.html
|
||||
import org.apache.commons.io.FileUtils
|
||||
import scala.collection.JavaConverters._
|
||||
|
||||
class ReleaseController extends ReleaseControllerBase
|
||||
with RepositoryService
|
||||
@@ -30,31 +29,25 @@ trait ReleaseControllerBase extends ControllerBase {
|
||||
with WritableUsersAuthenticator
|
||||
with ActivityService =>
|
||||
|
||||
case class ReleaseCreateForm(
|
||||
case class ReleaseForm(
|
||||
name: String,
|
||||
content: Option[String],
|
||||
isPrerelease: Boolean
|
||||
content: Option[String]
|
||||
)
|
||||
|
||||
val releaseCreateForm = mapping(
|
||||
"name" -> trim(text(required)),
|
||||
"content" -> trim(optional(text())),
|
||||
"isprerelease" -> boolean()
|
||||
)(ReleaseCreateForm.apply)
|
||||
|
||||
val releaseTitleEditForm = mapping(
|
||||
"title" -> trim(label("Title", text(required)))
|
||||
)(x => x)
|
||||
|
||||
val releaseEditForm = mapping(
|
||||
val releaseForm = mapping(
|
||||
"name" -> trim(text(required)),
|
||||
"content" -> trim(optional(text()))
|
||||
)(x => x)
|
||||
)(ReleaseForm.apply)
|
||||
|
||||
get("/:owner/:repository/releases")(referrersOnly {repository =>
|
||||
val releases = getReleases(repository.owner, repository.name)
|
||||
val assets = getReleaseAssetsMap(repository.owner, repository.name)
|
||||
|
||||
html.list(
|
||||
repository,
|
||||
getReleases(repository.owner, repository.name),
|
||||
getReleaseAssetsMap(repository.owner, repository.name),
|
||||
repository.tags.reverse.map { tag =>
|
||||
(tag, releases.find(_.tag == tag.name).map { release => (release, assets(release)) })
|
||||
},
|
||||
hasDeveloperRole(repository.owner, repository.name, context.loginAccount))
|
||||
})
|
||||
|
||||
@@ -68,93 +61,80 @@ trait ReleaseControllerBase extends ControllerBase {
|
||||
get("/:owner/:repository/releases/:id/assets/:fileId")(referrersOnly {repository =>
|
||||
val releaseId = params("id")
|
||||
val fileId = params("fileId")
|
||||
getRelease(repository.owner, repository.name, releaseId).flatMap{ release =>
|
||||
getReleaseAsset(repository.owner, repository.name, releaseId, fileId).flatMap{ asset =>
|
||||
response.setHeader("Content-Disposition", s"attachment; filename=${asset.label}")
|
||||
Some(RawData(FileUtil.getMimeType(asset.label), new File(getReleaseFilesDir(repository.owner, repository.name) + s"/${release.releaseId}", fileId)))
|
||||
}
|
||||
}.getOrElse(NotFound())
|
||||
(for {
|
||||
release <- getRelease(repository.owner, repository.name, releaseId)
|
||||
asset <- getReleaseAsset(repository.owner, repository.name, releaseId, fileId)
|
||||
} yield {
|
||||
response.setHeader("Content-Disposition", s"attachment; filename=${asset.label}")
|
||||
Some(RawData(
|
||||
FileUtil.getMimeType(asset.label),
|
||||
new File(getReleaseFilesDir(repository.owner, repository.name), release.tag + "/" + fileId)
|
||||
))
|
||||
}).getOrElse(NotFound())
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/releases/:id/assets/delete/:fileId")(writableUsersOnly { repository =>
|
||||
val releaseId = params("id")
|
||||
val fileId = params("fileId")
|
||||
for(
|
||||
release <- getRelease(repository.owner, repository.name, releaseId.toInt);
|
||||
asset <- getReleaseAsset(repository.owner, repository.name, releaseId, fileId)
|
||||
){
|
||||
FileUtils.forceDelete(new File(getReleaseFilesDir(repository.owner, repository.name) + s"/${release.releaseId}", fileId))
|
||||
}
|
||||
deleteReleaseAsset(repository.owner, repository.name, params("id").toInt, params("fileId"))
|
||||
org.json4s.jackson.Serialization.write(Map("message" -> "ok"))
|
||||
})
|
||||
|
||||
|
||||
get("/:owner/:repository/releases/:tag/create")(writableUsersOnly {repository =>
|
||||
val tag = params("tag")
|
||||
defining(repository.owner, repository.name){ case (owner, name) =>
|
||||
html.create(repository, tag)
|
||||
}
|
||||
html.form(repository, params("tag"), None)
|
||||
})
|
||||
|
||||
post("/:owner/:repository/releases/:tag/create", releaseCreateForm)(writableUsersOnly { (form, repository) =>
|
||||
post("/:owner/:repository/releases/:tag/create", releaseForm)(writableUsersOnly { (form, repository) =>
|
||||
val tag = params("tag")
|
||||
val release = createRelease(repository, form.name, form.content, tag, false, form.isPrerelease, context.loginAccount.get)
|
||||
recordReleaseActivity(repository.owner, repository.name, context.loginAccount.get.userName, release.releaseId, release.name)
|
||||
val loginAccount = context.loginAccount.get
|
||||
|
||||
// Insert into RELEASE
|
||||
val release = createRelease(repository.owner, repository.name, form.name, form.content, tag, loginAccount)
|
||||
|
||||
// Insert into RELEASE_ASSET
|
||||
request.getParameterNames.asScala.filter(_.startsWith("file:")).foreach { paramName =>
|
||||
val Array(_, fileId) = paramName.split(":")
|
||||
val fileName = params(paramName)
|
||||
val size = new java.io.File(getReleaseFilesDir(repository.owner, repository.name), tag + "/" + fileId).length
|
||||
|
||||
createReleaseAsset(repository.owner, repository.name, release.releaseId, fileId, fileName, size, loginAccount)
|
||||
}
|
||||
|
||||
recordReleaseActivity(repository.owner, repository.name, loginAccount.userName, release.releaseId, release.name)
|
||||
|
||||
redirect(s"/${release.userName}/${release.repositoryName}/releases/${release.releaseId}")
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/releases/delete/:id")(writableUsersOnly { repository =>
|
||||
for(
|
||||
release <- getRelease(repository.owner, repository.name, params("id"))
|
||||
){
|
||||
FileUtils.deleteDirectory(new File(getReleaseFilesDir(repository.owner, repository.name) + s"/${release.releaseId}"))
|
||||
}
|
||||
deleteRelease(repository.owner, repository.name, params("id"))
|
||||
org.json4s.jackson.Serialization.write(Map("message" -> "ok"))
|
||||
get("/:owner/:repository/releases/:id/edit")(writableUsersOnly {repository =>
|
||||
val releaseId = params("id").toInt
|
||||
getRelease(repository.owner, repository.name, releaseId).map { release =>
|
||||
html.form(repository, release.tag, Some(release, getReleaseAssets(repository.owner, repository.name, releaseId)))
|
||||
}.getOrElse(NotFound())
|
||||
})
|
||||
|
||||
ajaxPost("/:owner/:repository/releases/edit_title/:id", releaseTitleEditForm)(writableUsersOnly { (title, repository) =>
|
||||
defining(repository.owner, repository.name) { case (owner, name) =>
|
||||
getRelease(owner, name, params("id")).map { release =>
|
||||
updateRelease(owner, name, release.releaseId, title, release.content)
|
||||
redirect(s"/${owner}/${name}/releases/_data/${release.releaseId}")
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
post("/:owner/:repository/releases/:id/edit", releaseForm)(writableUsersOnly { (form, repository) =>
|
||||
val releaseId = params("id").toInt
|
||||
val loginAccount = context.loginAccount.get
|
||||
|
||||
ajaxPost("/:owner/:repository/releases/edit/:id", releaseEditForm)(writableUsersOnly { (content, repository) =>
|
||||
defining(repository.owner, repository.name){ case (owner, name) =>
|
||||
getRelease(owner, name, params("id")).map { release =>
|
||||
updateRelease(owner, name, release.releaseId, release.name, content)
|
||||
redirect(s"/${owner}/${name}/releases/_data/${release.releaseId}")
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
getRelease(repository.owner, repository.name, releaseId).map { release =>
|
||||
// Update RELEASE
|
||||
updateRelease(repository.owner, repository.name, releaseId, form.name, form.content)
|
||||
|
||||
ajaxGet("/:owner/:repository/releases/_data/:id")(writableUsersOnly { repository =>
|
||||
getRelease(repository.owner, repository.name, params("id")) map { x =>
|
||||
params.get("dataType") collect {
|
||||
case t if t == "html" => html.editrelease(x.content, x.releaseId, repository)
|
||||
} getOrElse {
|
||||
contentType = formats("json")
|
||||
org.json4s.jackson.Serialization.write(
|
||||
Map(
|
||||
"title" -> x.name,
|
||||
"content" -> Markdown.toHtml(
|
||||
markdown = x.content getOrElse "No description given.",
|
||||
repository = repository,
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableAnchor = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = true
|
||||
)
|
||||
)
|
||||
)
|
||||
// Delete and Insert RELEASE_ASSET
|
||||
deleteReleaseAssets(repository.owner, repository.name, releaseId)
|
||||
|
||||
request.getParameterNames.asScala.filter(_.startsWith("file:")).foreach { paramName =>
|
||||
val Array(_, fileId) = paramName.split(":")
|
||||
val fileName = params(paramName)
|
||||
val size = new java.io.File(getReleaseFilesDir(repository.owner, repository.name), release.tag + "/" + fileId).length
|
||||
|
||||
createReleaseAsset(repository.owner, repository.name, release.releaseId, fileId, fileName, size, loginAccount)
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
|
||||
redirect(s"/${release.userName}/${release.repositoryName}/releases/${release.releaseId}")
|
||||
}.getOrElse(NotFound())
|
||||
})
|
||||
|
||||
post("/:owner/:repository/releases/:id/delete")(writableUsersOnly { repository =>
|
||||
val releaseId = params("id")
|
||||
getRelease(repository.owner, repository.name, releaseId).foreach { release =>
|
||||
FileUtils.deleteDirectory(new File(getReleaseFilesDir(repository.owner, repository.name), release.tag))
|
||||
}
|
||||
deleteRelease(repository.owner, repository.name, releaseId)
|
||||
redirect(s"/${repository.owner}/${repository.name}/releases")
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -14,12 +14,10 @@ trait ReleaseComponent extends TemplateComponent {
|
||||
val tag = column[String]("TAG")
|
||||
val author = column[String]("AUTHOR")
|
||||
val content = column[Option[String]]("CONTENT")
|
||||
val isDraft = column[Boolean]("IS_DRAFT")
|
||||
val isPrerelease = column[Boolean]("IS_PRERELEASE")
|
||||
val registeredDate = column[java.util.Date]("REGISTERED_DATE")
|
||||
val updatedDate = column[java.util.Date]("UPDATED_DATE")
|
||||
|
||||
def * = (userName, repositoryName, releaseId, name, tag, author, content, isDraft, isPrerelease, registeredDate, updatedDate) <> (Release.tupled, Release.unapply)
|
||||
def * = (userName, repositoryName, releaseId, name, tag, author, content, registeredDate, updatedDate) <> (Release.tupled, Release.unapply)
|
||||
|
||||
def byPrimaryKey(owner: String, repository: String, releaseId: Int) = byRelease(owner, repository, releaseId)
|
||||
|
||||
@@ -46,8 +44,6 @@ case class Release(
|
||||
tag: String,
|
||||
author: String,
|
||||
content: Option[String],
|
||||
isDraft: Boolean,
|
||||
isPrerelease: Boolean,
|
||||
registeredDate: java.util.Date,
|
||||
updatedDate: java.util.Date
|
||||
)
|
||||
|
||||
@@ -3,42 +3,39 @@ package gitbucket.core.service
|
||||
import gitbucket.core.controller.Context
|
||||
import gitbucket.core.model.{Account, Release, ReleaseAsset}
|
||||
import gitbucket.core.util.StringUtil._
|
||||
import gitbucket.core.util.Implicits._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.model.Profile._
|
||||
import gitbucket.core.model.Profile.profile._
|
||||
import gitbucket.core.model.Profile.dateColumnType
|
||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||
|
||||
trait ReleaseService {
|
||||
self: AccountService with RepositoryService =>
|
||||
|
||||
def createReleaseAsset(owner: String, repository: String, releaseId: Int, fileName: String, label: String, size: Long, loginAccount: Account)(implicit s: Session): Unit = {
|
||||
ReleaseAssets insert ReleaseAsset(
|
||||
userName = owner,
|
||||
userName = owner,
|
||||
repositoryName = repository,
|
||||
releaseId = releaseId,
|
||||
fileName = fileName,
|
||||
label = label,
|
||||
size = size,
|
||||
uploader = loginAccount.userName,
|
||||
releaseId = releaseId,
|
||||
fileName = fileName,
|
||||
label = label,
|
||||
size = size,
|
||||
uploader = loginAccount.userName,
|
||||
registeredDate = currentDate,
|
||||
updatedDate = currentDate
|
||||
updatedDate = currentDate
|
||||
)
|
||||
}
|
||||
|
||||
def getReleaseAssets(owner: String, repository: String, releaseId: Int)(implicit s: Session): List[ReleaseAsset] = {
|
||||
def getReleaseAssets(owner: String, repository: String, releaseId: Int)(implicit s: Session): Seq[ReleaseAsset] = {
|
||||
ReleaseAssets.filter(x => x.byRelease(owner, repository, releaseId)).list
|
||||
}
|
||||
|
||||
def getReleaseAssets(owner: String, repository: String, releaseId: String)(implicit s: Session): List[ReleaseAsset] = {
|
||||
def getReleaseAssets(owner: String, repository: String, releaseId: String)(implicit s: Session): Seq[ReleaseAsset] = {
|
||||
if (isInteger(releaseId))
|
||||
getReleaseAssets(owner, repository, releaseId.toInt)
|
||||
else
|
||||
List.empty
|
||||
Seq.empty
|
||||
}
|
||||
|
||||
def getReleaseAssetsMap(owner: String, repository: String)(implicit s: Session): Map[Release, List[ReleaseAsset]] = {
|
||||
def getReleaseAssetsMap(owner: String, repository: String)(implicit s: Session): Map[Release, Seq[ReleaseAsset]] = {
|
||||
val releases = getReleases(owner, repository)
|
||||
releases.map(rel => (rel -> getReleaseAssets(owner, repository, rel.releaseId))).toMap
|
||||
}
|
||||
@@ -49,32 +46,26 @@ trait ReleaseService {
|
||||
else None
|
||||
}
|
||||
|
||||
def deleteReleaseAssets(owner: String, repository: String, releaseId: Int)(implicit s:Session): Unit = {
|
||||
def deleteReleaseAssets(owner: String, repository: String, releaseId: Int)(implicit s: Session): Unit = {
|
||||
ReleaseAssets.filter(x => x.byRelease(owner, repository, releaseId)) delete
|
||||
}
|
||||
|
||||
def deleteReleaseAsset(owner: String, repository: String, releaseId: Int, fileId: String)(implicit s: Session): Unit = {
|
||||
ReleaseAssets.filter(x => x.byPrimaryKey(owner, repository, releaseId, fileId)) delete
|
||||
}
|
||||
|
||||
def createRelease(repository: RepositoryInfo, name: String, content:Option[String], tag: String,
|
||||
isDraft: Boolean, isPrerelease: Boolean, loginAccount: Account)(implicit context: Context, s: Session): Release = {
|
||||
def createRelease(owner: String, repository: String, name: String, content: Option[String], tag: String,
|
||||
loginAccount: Account)(implicit context: Context, s: Session): Release = {
|
||||
Releases insert Release(
|
||||
userName = repository.owner,
|
||||
repositoryName = repository.name,
|
||||
name = name,
|
||||
tag = tag,
|
||||
author = loginAccount.userName,
|
||||
content = content,
|
||||
isDraft = isDraft,
|
||||
isPrerelease = isPrerelease,
|
||||
userName = owner,
|
||||
repositoryName = repository,
|
||||
name = name,
|
||||
tag = tag,
|
||||
author = loginAccount.userName,
|
||||
content = content,
|
||||
registeredDate = currentDate,
|
||||
updatedDate = currentDate
|
||||
updatedDate = currentDate
|
||||
)
|
||||
getReleaseByTag(repository.owner, repository.name, tag).get
|
||||
getReleaseByTag(owner, repository, tag).get
|
||||
}
|
||||
|
||||
def getReleases(owner: String, repository: String)(implicit s: Session): List[Release] = {
|
||||
def getReleases(owner: String, repository: String)(implicit s: Session): Seq[Release] = {
|
||||
Releases.filter(x => x.byRepository(owner, repository)).list
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
@(repository: gitbucket.core.service.RepositoryService.RepositoryInfo, tag: String)(implicit context: gitbucket.core.controller.Context)
|
||||
@import gitbucket.core.view.helpers
|
||||
@gitbucket.core.html.main(s"New Release - ${repository.owner}/${repository.name}", Some(repository)){
|
||||
@gitbucket.core.html.menu("releases", repository){
|
||||
<form action="@helpers.url(repository)/releases/@tag/create" method="POST" validate="true" class="form-group">
|
||||
<div class="row-fluid">
|
||||
<div class="col-md-12">
|
||||
<h3>New release for @tag</h3>
|
||||
<span id="error-name" class="error"></span>
|
||||
<input type="text" id="release-name" name="name" class="form-control" value="" placeholder="Title" style="margin-bottom: 6px;" autofocus/>
|
||||
@gitbucket.core.helper.html.preview(
|
||||
repository = repository,
|
||||
content = "",
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = true,
|
||||
completionContext = "releases",
|
||||
style = "height: 200px; max-height: 500px;",
|
||||
elastic = true,
|
||||
placeholder = "Describe this release"
|
||||
)
|
||||
<input type="checkbox" id="release-isprerelease" name="isprerelease"/>
|
||||
<label for="release-isprerelease">This is a pre-release</label>
|
||||
<div class="align-right">
|
||||
<input type="submit" class="btn btn-success" value="Submit new release"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
@(content: Option[String], releaseId: Int,
|
||||
repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context)
|
||||
@gitbucket.core.helper.html.attached(repository, "releases"){
|
||||
<textarea id="edit-content" class="form-control">@content.getOrElse("")</textarea>
|
||||
}
|
||||
<div>
|
||||
<input type="button" id="cancel-release" class="btn btn-default" value="Cancel"/>
|
||||
<input type="button" id="update-release" class="btn btn-success pull-right" value="Update comment"/>
|
||||
</div>
|
||||
<script>
|
||||
$(function(){
|
||||
var callback = function(data){
|
||||
$('#update, #cancel').removeAttr('disabled');
|
||||
$('#release-note').empty().html(data.content);
|
||||
};
|
||||
|
||||
$('#update-release').click(function(){
|
||||
$('#update, #cancel').attr('disabled', 'disabled');
|
||||
$.ajax({
|
||||
url: '@context.path/@repository.owner/@repository.name/releases/edit/@releaseId',
|
||||
type: 'POST',
|
||||
data: {
|
||||
content : $('#edit-content').val()
|
||||
}
|
||||
}).done(
|
||||
callback
|
||||
).fail(function(req) {
|
||||
$('#update, #cancel').removeAttr('disabled');
|
||||
});
|
||||
});
|
||||
|
||||
$('#cancel-release').click(function(){
|
||||
$('#update, #cancel').attr('disabled', 'disabled');
|
||||
$.get('@context.path/@repository.owner/@repository.name/releases/_data/@releaseId', callback);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
87
src/main/twirl/gitbucket/core/releases/form.scala.html
Normal file
87
src/main/twirl/gitbucket/core/releases/form.scala.html
Normal file
@@ -0,0 +1,87 @@
|
||||
@(repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
|
||||
tag: String,
|
||||
release: Option[(gitbucket.core.model.Release, Seq[gitbucket.core.model.ReleaseAsset])])(implicit context: gitbucket.core.controller.Context)
|
||||
@import gitbucket.core.view.helpers
|
||||
|
||||
@action = {
|
||||
@release.map { case (release, _) =>
|
||||
@helpers.url(repository)/releases/@release.releaseId/edit
|
||||
}.getOrElse {
|
||||
@helpers.url(repository)/releases/@helpers.encodeRefName(tag)/create
|
||||
}
|
||||
}
|
||||
|
||||
@gitbucket.core.html.main(s"New Release - ${repository.owner}/${repository.name}", Some(repository)){
|
||||
@gitbucket.core.html.menu("releases", repository){
|
||||
<form action="@action.toString.trim" method="POST" validate="true" class="form-group">
|
||||
<div class="row-fluid">
|
||||
<div class="co`l-md-12">
|
||||
@if(release.isEmpty){
|
||||
<h3>New release for @tag</h3>
|
||||
} else {
|
||||
<h3>Update release for @tag</h3>
|
||||
}
|
||||
<span id="error-name" class="error"></span>
|
||||
<input type="text" id="release-name" name="name" class="form-control" value="@release.map { case (release, _) => @release.name }.getOrElse(tag)" placeholder="Title" style="margin-bottom: 6px;" autofocus/>
|
||||
@gitbucket.core.helper.html.preview(
|
||||
repository = repository,
|
||||
content = release.flatMap { case (release, _) => release.content }.getOrElse(""),
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = true,
|
||||
completionContext = "releases",
|
||||
style = "height: 200px; max-height: 500px;",
|
||||
elastic = true,
|
||||
placeholder = "Describe this release"
|
||||
)
|
||||
<ul id="assets-list" class="collaborator">
|
||||
@release.map { case (release, assets) =>
|
||||
@assets.map { asset =>
|
||||
<li>
|
||||
<a href="@context.baseUrl/@repository.owner/@repository.name/_release/@helpers.encodeRefName(tag)/@asset.fileName"><i class="octicon octicon-file"></i>@asset.label</a>
|
||||
<a href="#" class="remove pull-right" style="padding-top: 0px;">(remove)</a>
|
||||
<input type="hidden" name="file:@asset.fileName" value="@asset.label"/>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
<div style="border: 1px dashed #ccc; color: gray; background-color: #eee; padding: 4px;">
|
||||
<div id="drop" class="clickable">Attach release files by dragging & dropping, or selecting them.</div>
|
||||
</div>
|
||||
<div class="align-right" style="margin-top: 12px;">
|
||||
@if(release.isEmpty){
|
||||
<input type="submit" class="btn btn-success" value="Submit new release"/>
|
||||
} else {
|
||||
<input type="submit" class="btn btn-success" value="Update release"/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
<script>
|
||||
$(function(){
|
||||
$(document).on('click', '.remove', function(){
|
||||
$(this).parent().remove();
|
||||
});
|
||||
|
||||
$("#drop").dropzone({
|
||||
maxFilesize: @{gitbucket.core.util.FileUtil.MaxFileSize / 1024 / 1024},
|
||||
url: '@context.path/upload/release/@repository.owner/@repository.name/@helpers.encodeRefName(tag)',
|
||||
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
|
||||
success: function(file, id) {
|
||||
var attach =
|
||||
'<li><a href="@context.baseUrl/@repository.owner/@repository.name/_release/@helpers.encodeRefName(tag)/' + id + '">' +
|
||||
'<i class="octicon octicon-file"></i>' + file.name + '</a>' +
|
||||
'<a href="#" class="remove pull-right" style="padding-top: 0px;">(remove)</a>' +
|
||||
'<input type="hidden" name="file:' + id + '" value="' + file.name + '"/>' + // TODO escape file.name
|
||||
'</li>';
|
||||
$('#assets-list').append(attach);
|
||||
$(file.previewElement).prevAll('div.dz-preview').addBack().remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -1,60 +1,64 @@
|
||||
@(repository: gitbucket.core.service.RepositoryService.RepositoryInfo,
|
||||
releases: List[gitbucket.core.model.Release],
|
||||
releaseAssetsMap: Map[gitbucket.core.model.Release, List[gitbucket.core.model.ReleaseAsset]],
|
||||
hasWritePermission: Boolean)(implicit context: gitbucket.core.controller.Context)
|
||||
releases: Seq[(gitbucket.core.util.JGitUtil.TagInfo, Option[(gitbucket.core.model.Release, Seq[gitbucket.core.model.ReleaseAsset])])],
|
||||
hasWritePermission: Boolean)(implicit context: gitbucket.core.controller.Context)
|
||||
@import gitbucket.core.view.helpers
|
||||
@gitbucket.core.html.main("Releases" + s" - ${repository.owner}/${repository.name}", Some(repository)){
|
||||
@gitbucket.core.html.menu("releases", repository){
|
||||
<table class="table table-bordered table-releases">
|
||||
<thead>
|
||||
<tr><th>@releases.length releases</div></th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@releases.map{ release =>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="col-md-1"><a href="@helpers.url(repository)/tree/helpers.encodeRefName(@release.tag)"><i class="octicon octicon-tag"></i>@release.tag</a></div>
|
||||
<div class="col-md-11" style="border-left: 1px solid #eee">
|
||||
<h3><a href="@helpers.url(repository)/releases/@release.releaseId">@release.name</a></h3>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<span class="muted">
|
||||
@helpers.avatar(release.author, 20)
|
||||
@helpers.user(release.author, styleClass="username strong")
|
||||
released this @gitbucket.core.helper.html.datetimeago(release.registeredDate)
|
||||
</span>
|
||||
</div>
|
||||
<div class="panel-body release-note markdown-body">
|
||||
@helpers.markdown(
|
||||
markdown = release.content getOrElse "No description provided.",
|
||||
repository = repository,
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = hasWritePermission
|
||||
)
|
||||
</div>
|
||||
<h2>Downloads</h2>
|
||||
<ul style="list-style: none">
|
||||
@releaseAssetsMap(release).map{ asset =>
|
||||
<li>
|
||||
<i class="octicon octicon-file"></i>
|
||||
<a href="@helpers.url(repository)/releases/@release.releaseId/assets/@asset.fileName">@asset.label</a>
|
||||
<span class="label label-default">@helpers.readableSize(Some(asset.size))</span>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<ul style="list-style: none;">
|
||||
<li><a href="@helpers.url(repository)/archive/@{helpers.encodeRefName(release.tag)}.zip"><i class="octicon octicon-file-zip"></i>ZIP</a></li>
|
||||
<li><a href="@helpers.url(repository)/archive/@{helpers.encodeRefName(release.tag)}.tar.gz"><i class="octicon octicon-file-zip"></i>TAR.GZ</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@gitbucket.core.html.menu("releases", repository){
|
||||
<table class="table table-bordered table-releases">
|
||||
<thead>
|
||||
<tr><th>@releases.length releases</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@releases.map { case (tag, release) =>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="col-md-2 text-right">
|
||||
<a href="@helpers.url(repository)/tree/@helpers.encodeRefName(tag.name)" class="strong"><i class="octicon octicon-tag"></i>@tag.name</a><br>
|
||||
<a href="@helpers.url(repository)/commit/@tag.id" class="monospace muted"><i class="octicon octicon-git-commit"></i>@tag.id.substring(0, 7)</a><br>
|
||||
<span class="muted">@gitbucket.core.helper.html.datetimeago(tag.time)</span>
|
||||
</div>
|
||||
<div class="col-md-10" style="border-left: 1px solid #eee">
|
||||
<div class="release-note markdown-body">
|
||||
@release.map { case (release, assets) =>
|
||||
<h3><a href="@helpers.url(repository)/releases/@release.releaseId">@release.name</a></h3>
|
||||
<p class="muted">
|
||||
@helpers.avatar(release.author, 20) @helpers.user(release.author, styleClass="username") released this @gitbucket.core.helper.html.datetimeago(release.registeredDate)
|
||||
</p>
|
||||
@helpers.markdown(
|
||||
markdown = release.content getOrElse "No description provided.",
|
||||
repository = repository,
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = hasWritePermission
|
||||
)
|
||||
}.getOrElse {
|
||||
@if(hasWritePermission){
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-success" href="@helpers.url(repository)/releases/@{helpers.encodeRefName(tag.name)}/create" id="edit">Create release</a>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
<h4>Downloads</h4>
|
||||
<ul style="list-style: none; padding-left: 8px;">
|
||||
@release.map { case (release, assets) =>
|
||||
@assets.map { asset =>
|
||||
<li>
|
||||
<i class="octicon octicon-file"></i><a href="@helpers.url(repository)/releases/@release.releaseId/assets/@asset.fileName">@asset.label</a>
|
||||
<span class="label label-default">@helpers.readableSize(Some(asset.size))</span>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
<li><a href="@helpers.url(repository)/archive/@{helpers.encodeRefName(tag.name)}.zip"><i class="octicon octicon-file-zip"></i>Source code (zip)</a></li>
|
||||
<li><a href="@helpers.url(repository)/archive/@{helpers.encodeRefName(tag.name)}.tar.gz"><i class="octicon octicon-file-zip"></i>Source code (tar.gz)</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
@@ -1,161 +1,65 @@
|
||||
@(release: gitbucket.core.model.Release,
|
||||
assets: List[gitbucket.core.model.ReleaseAsset],
|
||||
hasWritePermission: Boolean,
|
||||
repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context)
|
||||
assets: Seq[gitbucket.core.model.ReleaseAsset],
|
||||
hasWritePermission: Boolean,
|
||||
repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context)
|
||||
@import gitbucket.core.view.helpers
|
||||
@gitbucket.core.html.main(s"${release.name} - Release ${release.releaseId} - ${repository.owner}/${repository.name}", Some(repository)){
|
||||
@gitbucket.core.html.menu("releases", repository){
|
||||
<div class="row">
|
||||
<div class="col-md-1">
|
||||
<div><a href="@helpers.url(repository)/tree/@release.tag"><i class="octicon octicon-tag"></i>@release.tag</a></div>
|
||||
</div>
|
||||
<div class="col-md-11" style="border-left: 1px solid #eee">
|
||||
<div>
|
||||
<div class="show-title pull-right">
|
||||
@if(hasWritePermission){
|
||||
<a class="btn btn-default" href="#" id="edit">Edit title</a>
|
||||
<a class="btn btn-danger" href="#" id="delete-release">Delete</a>
|
||||
}
|
||||
</div>
|
||||
<div class="edit-title pull-right" style="display: none;">
|
||||
<a class="btn btn-success" href="#" id="update">Save</a> <a class="btn btn-default" href="#" id="cancel">Cancel</a>
|
||||
</div>
|
||||
<h1 class="body-title">
|
||||
<span class="show-title">
|
||||
<span id="show-title">@release.name</span>
|
||||
</span>
|
||||
<span class="edit-title" style="display: none;">
|
||||
<span id="error-edit-title" class="error"></span>
|
||||
<input type="text" class="form-control" style="width: 700px;" id="edit-title" value="@release.name"/>
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<span class="muted">
|
||||
@helpers.avatar(release.author, 20)
|
||||
@helpers.user(release.author, styleClass="username strong") released this @gitbucket.core.helper.html.datetimeago(release.registeredDate)
|
||||
</span>
|
||||
<span class="pull-right">
|
||||
@if(hasWritePermission){
|
||||
<a href="#"><i class="octicon octicon-pencil" aria-label="Edit" id="edit-notes"></i></a>
|
||||
@gitbucket.core.html.menu("releases", repository){
|
||||
<div class="row">
|
||||
<div class="col-md-2 text-right">
|
||||
@defining(repository.tags.find(_.name == release.tag)){ tag =>
|
||||
@tag.map { tag =>
|
||||
<a href="@helpers.url(repository)/tree/@helpers.encodeRefName(tag.name)" class="strong"><i class="octicon octicon-tag"></i>@tag.name</a><br>
|
||||
<a href="@helpers.url(repository)/commit/@tag.id" class="monospace muted"><i class="octicon octicon-git-commit"></i>@tag.id.substring(0, 7)</a><br>
|
||||
<span class="muted">@gitbucket.core.helper.html.datetimeago(tag.time)</span>
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
<div class="panel-body markdown-body" id="release-note">
|
||||
@helpers.markdown(
|
||||
markdown = release.content getOrElse "No description provided.",
|
||||
repository = repository,
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = hasWritePermission
|
||||
)
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<h2>Downloads</h2>
|
||||
@if(hasWritePermission){
|
||||
<div style="border: 3px dashed #ccc; background-color: #eee" >
|
||||
<div id="drop" class="clickable">Attach release files by dragging & dropping, or selecting them.</div>
|
||||
</div>
|
||||
}
|
||||
<ul style="list-style: none;" id="attachedFiles">
|
||||
@assets.map{ asset =>
|
||||
<li>
|
||||
<i class="octicon octicon-file"></i>
|
||||
<a href="@helpers.url(repository)/releases/@release.releaseId/assets/@asset.fileName">@asset.label</a>
|
||||
<span class="label label-default">@helpers.readableSize(Some(asset.size))</span>
|
||||
</div>
|
||||
<div class="col-md-10" style="border-left: 1px solid #eee">
|
||||
<div class="markdown-body">
|
||||
<h3>
|
||||
@release.name
|
||||
@if(hasWritePermission){
|
||||
<a href="#" data-asset-file-name="@asset.fileName" class="label label-danger delete-asset">Delete</a>
|
||||
<div class="pull-right">
|
||||
<form method="POST" action="@helpers.url(repository)/releases/@release.releaseId/delete" id="delete-form">
|
||||
<a class="btn btn-default" href="@helpers.url(repository)/releases/@release.releaseId/edit" id="edit">Edit</a>
|
||||
<input type="submit" class="btn btn-danger" value="Delete">
|
||||
</form>
|
||||
</div>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<ul style="list-style: none;">
|
||||
<li><a href="@helpers.url(repository)/archive/@{helpers.encodeRefName(release.tag)}.zip"><i class="octicon octicon-file-zip"></i>ZIP</a></li>
|
||||
<li><a href="@helpers.url(repository)/archive/@{helpers.encodeRefName(release.tag)}.tar.gz"><i class="octicon octicon-file-zip"></i>TAR.GZ</a></li>
|
||||
</ul>
|
||||
</h3>
|
||||
<p class="muted">
|
||||
@helpers.avatar(release.author, 20) @helpers.user(release.author, styleClass="username") released this @gitbucket.core.helper.html.datetimeago(release.registeredDate)
|
||||
</p>
|
||||
@helpers.markdown(
|
||||
markdown = release.content getOrElse "No description provided.",
|
||||
repository = repository,
|
||||
enableWikiLink = false,
|
||||
enableRefsLink = true,
|
||||
enableLineBreaks = true,
|
||||
enableTaskList = true,
|
||||
hasWritePermission = hasWritePermission
|
||||
)
|
||||
<h4>Downloads</h4>
|
||||
<ul style="list-style: none; padding-left: 8px;" id="attachedFiles">
|
||||
@assets.map{ asset =>
|
||||
<li>
|
||||
<i class="octicon octicon-file"></i><a href="@helpers.url(repository)/releases/@release.releaseId/assets/@asset.fileName">@asset.label</a>
|
||||
<span class="label label-default">@helpers.readableSize(Some(asset.size))</span>
|
||||
</li>
|
||||
}
|
||||
<li><a href="@helpers.url(repository)/archive/@{helpers.encodeRefName(release.tag)}.zip"><i class="octicon octicon-file-zip"></i>Source code (zip)</a></li>
|
||||
<li><a href="@helpers.url(repository)/archive/@{helpers.encodeRefName(release.tag)}.tar.gz"><i class="octicon octicon-file-zip"></i>Source code (tar.gz)</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
<script>
|
||||
$(function(){
|
||||
$('.delete-asset').click(function(){
|
||||
var name = $(this).data('asset-file-name');
|
||||
var url = '@helpers.url(repository)/releases/@release.releaseId/assets/delete/' + name;
|
||||
var li = $(this).closest('li');
|
||||
$.post(url,
|
||||
function(data){
|
||||
li.remove();
|
||||
});
|
||||
return false;
|
||||
});
|
||||
$('#edit').click(function(){
|
||||
$('.edit-title').show();
|
||||
$('.show-title').hide();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#update').click(function(){
|
||||
$(this).attr('disabled', 'disabled');
|
||||
$.ajax({
|
||||
url: '@helpers.url(repository)/releases/edit_title/@release.releaseId',
|
||||
type: 'POST',
|
||||
data: {
|
||||
title : $('#edit-title').val()
|
||||
}
|
||||
}).done(function(data){
|
||||
$('#show-title').empty().text(data.title);
|
||||
$('#cancel').click();
|
||||
$(this).removeAttr('disabled');
|
||||
}).fail(function(req){
|
||||
$(this).removeAttr('disabled');
|
||||
$('#error-edit-title').text($.parseJSON(req.responseText).title);
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#cancel').click(function(){
|
||||
$('.edit-title').hide();
|
||||
$('.show-title').show();
|
||||
return false;
|
||||
});
|
||||
$('#edit-notes').click(function(){
|
||||
var id = @release.releaseId;
|
||||
var url = '@helpers.url(repository)/releases/_data/' + id;
|
||||
var $content = $('#release-note');
|
||||
|
||||
$.get(url,
|
||||
{
|
||||
dataType : 'html'
|
||||
},
|
||||
function(data){
|
||||
$content.empty().html(data);
|
||||
});
|
||||
return false;
|
||||
});
|
||||
$('#delete-release').click(function(){
|
||||
if(confirm('Are you sure you want to delete this?')) {
|
||||
$.post('@helpers.url(repository)/releases/delete/' + @release.releaseId,
|
||||
function(data){
|
||||
location.href = "@helpers.url(repository)/releases";
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
$("#drop").dropzone({
|
||||
maxFilesize: @{gitbucket.core.util.FileUtil.MaxFileSize / 1024 / 1024},
|
||||
url: '@context.path/upload/release/@repository.owner/@repository.name/@release.releaseId',
|
||||
previewTemplate: "<div class=\"dz-preview\">\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress>Uploading your files...</span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
|
||||
success: function(file, id) {
|
||||
var attach = '<li><a href="@context.baseUrl/@repository.owner/@repository.name/_release/@release.releaseId/' + id + '">'
|
||||
+ '<i class="octicon octicon-file"></i>' + file.name + '</a></li>';
|
||||
$('#attachedFiles').append(attach);
|
||||
}
|
||||
$('#delete-form').submit(function(){
|
||||
return confirm('Are you sure you want to delete this release?');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@
|
||||
<a href="@helpers.url(repository)/releases/@release.releaseId">Release</a>
|
||||
}.getOrElse{
|
||||
@if(hasWritePermission){
|
||||
<div class="show-title pull-right">
|
||||
<a class="btn btn-success" href="@helpers.url(repository)/releases/@{helpers.encodeRefName(tag.name)}/create">Create release</a>
|
||||
</div>
|
||||
}else{
|
||||
<br />
|
||||
<div class="show-title pull-right">
|
||||
<a class="btn btn-success btn-min" href="@helpers.url(repository)/releases/@{helpers.encodeRefName(tag.name)}/create">Create release</a>
|
||||
</div>
|
||||
} else {
|
||||
<br />
|
||||
}
|
||||
}
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user