aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain <romdum@users.noreply.github.com>2021-02-11 17:32:27 +0100
committerGitHub <noreply@github.com>2021-02-11 17:32:27 +0100
commitc69c01d2b6b08a89448b5596fd2233fa4e802ac3 (patch)
tree16d461903abbd5bd29ae4905b8506a752d632619
parentac97ea573c1b10d03e72775e8f74b9fe5453bfc8 (diff)
downloadgitea-c69c01d2b6b08a89448b5596fd2233fa4e802ac3.tar.gz
gitea-c69c01d2b6b08a89448b5596fd2233fa4e802ac3.zip
Sort / Move project boards (#14634)
Sort Project board (#14533)
-rw-r--r--models/project_board.go34
-rw-r--r--modules/forms/repo_form.go8
-rw-r--r--routers/repo/projects.go12
-rw-r--r--routers/routes/web.go4
-rw-r--r--templates/repo/projects/view.tmpl2
-rw-r--r--web_src/js/features/projects.js29
6 files changed, 73 insertions, 16 deletions
diff --git a/models/project_board.go b/models/project_board.go
index a9c0b3ed8b..e56bf8f819 100644
--- a/models/project_board.go
+++ b/models/project_board.go
@@ -36,6 +36,7 @@ type ProjectBoard struct {
ID int64 `xorm:"pk autoincr"`
Title string
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"`
CreatorID int64 `xorm:"NOT NULL"`
@@ -157,15 +158,24 @@ func getProjectBoard(e Engine, boardID int64) (*ProjectBoard, error) {
return board, nil
}
-// UpdateProjectBoard updates the title of a project board
+// UpdateProjectBoard updates a project board
func UpdateProjectBoard(board *ProjectBoard) error {
return updateProjectBoard(x, board)
}
func updateProjectBoard(e Engine, board *ProjectBoard) error {
- _, err := e.ID(board.ID).Cols(
- "title",
- ).Update(board)
+ var fieldToUpdate []string
+
+ 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
}
@@ -178,7 +188,7 @@ func GetProjectBoards(projectID int64) (ProjectBoardList, error) {
func getProjectBoards(e Engine, projectID int64) ([]*ProjectBoard, error) {
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
}
@@ -277,3 +287,17 @@ func (bs ProjectBoardList) LoadIssues() (IssueList, error) {
}
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
+}
diff --git a/modules/forms/repo_form.go b/modules/forms/repo_form.go
index ac968a1dd5..f177b21f05 100644
--- a/modules/forms/repo_form.go
+++ b/modules/forms/repo_form.go
@@ -487,10 +487,10 @@ type UserCreateProjectForm struct {
UID int64 `binding:"Required"`
}
-// EditProjectBoardTitleForm is a form for editing the title of a project's
-// board
-type EditProjectBoardTitleForm struct {
- Title string `binding:"Required;MaxSize(100)"`
+// EditProjectBoardForm is a form for editing a project board
+type EditProjectBoardForm struct {
+ Title string `binding:"Required;MaxSize(100)"`
+ Sorting int8
}
// _____ .__.__ __
diff --git a/routers/repo/projects.go b/routers/repo/projects.go
index 49bcfef0ce..4aa03e9efc 100644
--- a/routers/repo/projects.go
+++ b/routers/repo/projects.go
@@ -403,7 +403,7 @@ func DeleteProjectBoard(ctx *context.Context) {
// AddBoardToProjectPost allows a new board to be added to a project.
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) {
ctx.JSON(403, map[string]string{
"message": "Only authorized users are allowed to perform this action.",
@@ -481,9 +481,9 @@ func checkProjectBoardChangePermissions(ctx *context.Context) (*models.Project,
return project, board
}
-// EditProjectBoardTitle allows a project board's title to be updated
-func EditProjectBoardTitle(ctx *context.Context) {
- form := web.GetForm(ctx).(*auth.EditProjectBoardTitleForm)
+// EditProjectBoard allows a project board's to be updated
+func EditProjectBoard(ctx *context.Context) {
+ form := web.GetForm(ctx).(*auth.EditProjectBoardForm)
_, board := checkProjectBoardChangePermissions(ctx)
if ctx.Written() {
return
@@ -493,6 +493,10 @@ func EditProjectBoardTitle(ctx *context.Context) {
board.Title = form.Title
}
+ if form.Sorting != 0 {
+ board.Sorting = form.Sorting
+ }
+
if err := models.UpdateProjectBoard(board); err != nil {
ctx.ServerError("UpdateProjectBoard", err)
return
diff --git a/routers/routes/web.go b/routers/routes/web.go
index 1f860a6239..9e3e690fb9 100644
--- a/routers/routes/web.go
+++ b/routers/routes/web.go
@@ -853,7 +853,7 @@ func RegisterRoutes(m *web.Route) {
m.Get("/new", repo.NewProject)
m.Post("/new", bindIgnErr(auth.CreateProjectForm{}), repo.NewProjectPost)
m.Group("/{id}", func() {
- m.Post("", bindIgnErr(auth.EditProjectBoardTitleForm{}), repo.AddBoardToProjectPost)
+ m.Post("", bindIgnErr(auth.EditProjectBoardForm{}), repo.AddBoardToProjectPost)
m.Post("/delete", repo.DeleteProject)
m.Get("/edit", repo.EditProject)
@@ -861,7 +861,7 @@ func RegisterRoutes(m *web.Route) {
m.Post("/{action:open|close}", repo.ChangeProjectStatus)
m.Group("/{boardID}", func() {
- m.Put("", bindIgnErr(auth.EditProjectBoardTitleForm{}), repo.EditProjectBoardTitle)
+ m.Put("", bindIgnErr(auth.EditProjectBoardForm{}), repo.EditProjectBoard)
m.Delete("", repo.DeleteProjectBoard)
m.Post("/default", repo.SetDefaultProjectBoard)
diff --git a/templates/repo/projects/view.tmpl b/templates/repo/projects/view.tmpl
index 9b2aa4bc7d..de1fc37b03 100644
--- a/templates/repo/projects/view.tmpl
+++ b/templates/repo/projects/view.tmpl
@@ -72,7 +72,7 @@
<div class="board">
{{ 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="ui large label board-label">{{.Title}}</div>
{{if and $.CanWriteProjects (not $.Repository.IsArchived) $.PageIsProjects (ne .ID 0)}}
diff --git a/web_src/js/features/projects.js b/web_src/js/features/projects.js
index b5f52f7443..254079b769 100644
--- a/web_src/js/features/projects.js
+++ b/web_src/js/features/projects.js
@@ -8,6 +8,34 @@ export default async function initProject() {
const {Sortable} = await import(/* webpackChunkName: "sortable" */'sortablejs');
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) {
new Sortable(
column.getElementsByClassName('board')[0],
@@ -74,6 +102,7 @@ export default async function initProject() {
window.location.reload();
});
+
$('.delete-project-board').each(function () {
$(this).click(function (e) {
e.preventDefault();