parent
ac97ea573c
commit
c69c01d2b6
6 changed files with 73 additions and 16 deletions
|
@ -36,6 +36,7 @@ type ProjectBoard struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
Title string
|
Title string
|
||||||
Default bool `xorm:"NOT NULL DEFAULT false"` // issues not assigned to a specific board will be assigned to this board
|
Default bool `xorm:"NOT NULL DEFAULT false"` // issues not assigned to a specific board will be assigned to this board
|
||||||
|
Sorting int8 `xorm:"DEFAULT 0"`
|
||||||
|
|
||||||
ProjectID int64 `xorm:"INDEX NOT NULL"`
|
ProjectID int64 `xorm:"INDEX NOT NULL"`
|
||||||
CreatorID int64 `xorm:"NOT NULL"`
|
CreatorID int64 `xorm:"NOT NULL"`
|
||||||
|
@ -157,15 +158,24 @@ func getProjectBoard(e Engine, boardID int64) (*ProjectBoard, error) {
|
||||||
return board, nil
|
return board, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateProjectBoard updates the title of a project board
|
// UpdateProjectBoard updates a project board
|
||||||
func UpdateProjectBoard(board *ProjectBoard) error {
|
func UpdateProjectBoard(board *ProjectBoard) error {
|
||||||
return updateProjectBoard(x, board)
|
return updateProjectBoard(x, board)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateProjectBoard(e Engine, board *ProjectBoard) error {
|
func updateProjectBoard(e Engine, board *ProjectBoard) error {
|
||||||
_, err := e.ID(board.ID).Cols(
|
var fieldToUpdate []string
|
||||||
"title",
|
|
||||||
).Update(board)
|
if board.Sorting != 0 {
|
||||||
|
fieldToUpdate = append(fieldToUpdate, "sorting")
|
||||||
|
}
|
||||||
|
|
||||||
|
if board.Title != "" {
|
||||||
|
fieldToUpdate = append(fieldToUpdate, "title")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := e.ID(board.ID).Cols(fieldToUpdate...).Update(board)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +188,7 @@ func GetProjectBoards(projectID int64) (ProjectBoardList, error) {
|
||||||
func getProjectBoards(e Engine, projectID int64) ([]*ProjectBoard, error) {
|
func getProjectBoards(e Engine, projectID int64) ([]*ProjectBoard, error) {
|
||||||
var boards = make([]*ProjectBoard, 0, 5)
|
var boards = make([]*ProjectBoard, 0, 5)
|
||||||
|
|
||||||
if err := e.Where("project_id=? AND `default`=?", projectID, false).Find(&boards); err != nil {
|
if err := e.Where("project_id=? AND `default`=?", projectID, false).OrderBy("Sorting").Find(&boards); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,3 +287,17 @@ func (bs ProjectBoardList) LoadIssues() (IssueList, error) {
|
||||||
}
|
}
|
||||||
return issues, nil
|
return issues, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateProjectBoardSorting update project board sorting
|
||||||
|
func UpdateProjectBoardSorting(bs ProjectBoardList) error {
|
||||||
|
for i := range bs {
|
||||||
|
_, err := x.ID(bs[i].ID).Cols(
|
||||||
|
"sorting",
|
||||||
|
).Update(bs[i])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -487,10 +487,10 @@ type UserCreateProjectForm struct {
|
||||||
UID int64 `binding:"Required"`
|
UID int64 `binding:"Required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditProjectBoardTitleForm is a form for editing the title of a project's
|
// EditProjectBoardForm is a form for editing a project board
|
||||||
// board
|
type EditProjectBoardForm struct {
|
||||||
type EditProjectBoardTitleForm struct {
|
|
||||||
Title string `binding:"Required;MaxSize(100)"`
|
Title string `binding:"Required;MaxSize(100)"`
|
||||||
|
Sorting int8
|
||||||
}
|
}
|
||||||
|
|
||||||
// _____ .__.__ __
|
// _____ .__.__ __
|
||||||
|
|
|
@ -403,7 +403,7 @@ func DeleteProjectBoard(ctx *context.Context) {
|
||||||
|
|
||||||
// AddBoardToProjectPost allows a new board to be added to a project.
|
// AddBoardToProjectPost allows a new board to be added to a project.
|
||||||
func AddBoardToProjectPost(ctx *context.Context) {
|
func AddBoardToProjectPost(ctx *context.Context) {
|
||||||
form := web.GetForm(ctx).(*auth.EditProjectBoardTitleForm)
|
form := web.GetForm(ctx).(*auth.EditProjectBoardForm)
|
||||||
if !ctx.Repo.IsOwner() && !ctx.Repo.IsAdmin() && !ctx.Repo.CanAccess(models.AccessModeWrite, models.UnitTypeProjects) {
|
if !ctx.Repo.IsOwner() && !ctx.Repo.IsAdmin() && !ctx.Repo.CanAccess(models.AccessModeWrite, models.UnitTypeProjects) {
|
||||||
ctx.JSON(403, map[string]string{
|
ctx.JSON(403, map[string]string{
|
||||||
"message": "Only authorized users are allowed to perform this action.",
|
"message": "Only authorized users are allowed to perform this action.",
|
||||||
|
@ -481,9 +481,9 @@ func checkProjectBoardChangePermissions(ctx *context.Context) (*models.Project,
|
||||||
return project, board
|
return project, board
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditProjectBoardTitle allows a project board's title to be updated
|
// EditProjectBoard allows a project board's to be updated
|
||||||
func EditProjectBoardTitle(ctx *context.Context) {
|
func EditProjectBoard(ctx *context.Context) {
|
||||||
form := web.GetForm(ctx).(*auth.EditProjectBoardTitleForm)
|
form := web.GetForm(ctx).(*auth.EditProjectBoardForm)
|
||||||
_, board := checkProjectBoardChangePermissions(ctx)
|
_, board := checkProjectBoardChangePermissions(ctx)
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
return
|
return
|
||||||
|
@ -493,6 +493,10 @@ func EditProjectBoardTitle(ctx *context.Context) {
|
||||||
board.Title = form.Title
|
board.Title = form.Title
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if form.Sorting != 0 {
|
||||||
|
board.Sorting = form.Sorting
|
||||||
|
}
|
||||||
|
|
||||||
if err := models.UpdateProjectBoard(board); err != nil {
|
if err := models.UpdateProjectBoard(board); err != nil {
|
||||||
ctx.ServerError("UpdateProjectBoard", err)
|
ctx.ServerError("UpdateProjectBoard", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -853,7 +853,7 @@ func RegisterRoutes(m *web.Route) {
|
||||||
m.Get("/new", repo.NewProject)
|
m.Get("/new", repo.NewProject)
|
||||||
m.Post("/new", bindIgnErr(auth.CreateProjectForm{}), repo.NewProjectPost)
|
m.Post("/new", bindIgnErr(auth.CreateProjectForm{}), repo.NewProjectPost)
|
||||||
m.Group("/{id}", func() {
|
m.Group("/{id}", func() {
|
||||||
m.Post("", bindIgnErr(auth.EditProjectBoardTitleForm{}), repo.AddBoardToProjectPost)
|
m.Post("", bindIgnErr(auth.EditProjectBoardForm{}), repo.AddBoardToProjectPost)
|
||||||
m.Post("/delete", repo.DeleteProject)
|
m.Post("/delete", repo.DeleteProject)
|
||||||
|
|
||||||
m.Get("/edit", repo.EditProject)
|
m.Get("/edit", repo.EditProject)
|
||||||
|
@ -861,7 +861,7 @@ func RegisterRoutes(m *web.Route) {
|
||||||
m.Post("/{action:open|close}", repo.ChangeProjectStatus)
|
m.Post("/{action:open|close}", repo.ChangeProjectStatus)
|
||||||
|
|
||||||
m.Group("/{boardID}", func() {
|
m.Group("/{boardID}", func() {
|
||||||
m.Put("", bindIgnErr(auth.EditProjectBoardTitleForm{}), repo.EditProjectBoardTitle)
|
m.Put("", bindIgnErr(auth.EditProjectBoardForm{}), repo.EditProjectBoard)
|
||||||
m.Delete("", repo.DeleteProjectBoard)
|
m.Delete("", repo.DeleteProjectBoard)
|
||||||
m.Post("/default", repo.SetDefaultProjectBoard)
|
m.Post("/default", repo.SetDefaultProjectBoard)
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
<div class="board">
|
<div class="board">
|
||||||
{{ range $board := .Boards }}
|
{{ range $board := .Boards }}
|
||||||
|
|
||||||
<div class="ui segment board-column">
|
<div class="ui segment board-column" data-id="{{.ID}}" data-sorting="{{.Sorting}}" data-url="{{$.RepoLink}}/projects/{{$.Project.ID}}/{{.ID}}">
|
||||||
<div class="board-column-header">
|
<div class="board-column-header">
|
||||||
<div class="ui large label board-label">{{.Title}}</div>
|
<div class="ui large label board-label">{{.Title}}</div>
|
||||||
{{if and $.CanWriteProjects (not $.Repository.IsArchived) $.PageIsProjects (ne .ID 0)}}
|
{{if and $.CanWriteProjects (not $.Repository.IsArchived) $.PageIsProjects (ne .ID 0)}}
|
||||||
|
|
|
@ -8,6 +8,34 @@ export default async function initProject() {
|
||||||
const {Sortable} = await import(/* webpackChunkName: "sortable" */'sortablejs');
|
const {Sortable} = await import(/* webpackChunkName: "sortable" */'sortablejs');
|
||||||
const boardColumns = document.getElementsByClassName('board-column');
|
const boardColumns = document.getElementsByClassName('board-column');
|
||||||
|
|
||||||
|
new Sortable(
|
||||||
|
document.getElementsByClassName('board')[0],
|
||||||
|
{
|
||||||
|
group: 'board-column',
|
||||||
|
draggable: '.board-column',
|
||||||
|
animation: 150,
|
||||||
|
onSort: () => {
|
||||||
|
const board = document.getElementsByClassName('board')[0];
|
||||||
|
const boardColumns = board.getElementsByClassName('board-column');
|
||||||
|
|
||||||
|
boardColumns.forEach((column, i) => {
|
||||||
|
if (parseInt($(column).data('sorting')) !== i) {
|
||||||
|
$.ajax({
|
||||||
|
url: $(column).data('url'),
|
||||||
|
data: JSON.stringify({sorting: i}),
|
||||||
|
headers: {
|
||||||
|
'X-Csrf-Token': csrf,
|
||||||
|
'X-Remote': true,
|
||||||
|
},
|
||||||
|
contentType: 'application/json',
|
||||||
|
method: 'PUT',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
for (const column of boardColumns) {
|
for (const column of boardColumns) {
|
||||||
new Sortable(
|
new Sortable(
|
||||||
column.getElementsByClassName('board')[0],
|
column.getElementsByClassName('board')[0],
|
||||||
|
@ -74,6 +102,7 @@ export default async function initProject() {
|
||||||
|
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.delete-project-board').each(function () {
|
$('.delete-project-board').each(function () {
|
||||||
$(this).click(function (e) {
|
$(this).click(function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
Reference in a new issue