Skip to content

Commit c69c01d

Browse files
authored
Sort / Move project boards (#14634)
Sort Project board (#14533)
1 parent ac97ea5 commit c69c01d

File tree

6 files changed

+73
-16
lines changed

6 files changed

+73
-16
lines changed

models/project_board.go

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type ProjectBoard struct {
3636
ID int64 `xorm:"pk autoincr"`
3737
Title string
3838
Default bool `xorm:"NOT NULL DEFAULT false"` // issues not assigned to a specific board will be assigned to this board
39+
Sorting int8 `xorm:"DEFAULT 0"`
3940

4041
ProjectID int64 `xorm:"INDEX NOT NULL"`
4142
CreatorID int64 `xorm:"NOT NULL"`
@@ -157,15 +158,24 @@ func getProjectBoard(e Engine, boardID int64) (*ProjectBoard, error) {
157158
return board, nil
158159
}
159160

160-
// UpdateProjectBoard updates the title of a project board
161+
// UpdateProjectBoard updates a project board
161162
func UpdateProjectBoard(board *ProjectBoard) error {
162163
return updateProjectBoard(x, board)
163164
}
164165

165166
func updateProjectBoard(e Engine, board *ProjectBoard) error {
166-
_, err := e.ID(board.ID).Cols(
167-
"title",
168-
).Update(board)
167+
var fieldToUpdate []string
168+
169+
if board.Sorting != 0 {
170+
fieldToUpdate = append(fieldToUpdate, "sorting")
171+
}
172+
173+
if board.Title != "" {
174+
fieldToUpdate = append(fieldToUpdate, "title")
175+
}
176+
177+
_, err := e.ID(board.ID).Cols(fieldToUpdate...).Update(board)
178+
169179
return err
170180
}
171181

@@ -178,7 +188,7 @@ func GetProjectBoards(projectID int64) (ProjectBoardList, error) {
178188
func getProjectBoards(e Engine, projectID int64) ([]*ProjectBoard, error) {
179189
var boards = make([]*ProjectBoard, 0, 5)
180190

181-
if err := e.Where("project_id=? AND `default`=?", projectID, false).Find(&boards); err != nil {
191+
if err := e.Where("project_id=? AND `default`=?", projectID, false).OrderBy("Sorting").Find(&boards); err != nil {
182192
return nil, err
183193
}
184194

@@ -277,3 +287,17 @@ func (bs ProjectBoardList) LoadIssues() (IssueList, error) {
277287
}
278288
return issues, nil
279289
}
290+
291+
// UpdateProjectBoardSorting update project board sorting
292+
func UpdateProjectBoardSorting(bs ProjectBoardList) error {
293+
for i := range bs {
294+
_, err := x.ID(bs[i].ID).Cols(
295+
"sorting",
296+
).Update(bs[i])
297+
298+
if err != nil {
299+
return err
300+
}
301+
}
302+
return nil
303+
}

modules/forms/repo_form.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -487,10 +487,10 @@ type UserCreateProjectForm struct {
487487
UID int64 `binding:"Required"`
488488
}
489489

490-
// EditProjectBoardTitleForm is a form for editing the title of a project's
491-
// board
492-
type EditProjectBoardTitleForm struct {
493-
Title string `binding:"Required;MaxSize(100)"`
490+
// EditProjectBoardForm is a form for editing a project board
491+
type EditProjectBoardForm struct {
492+
Title string `binding:"Required;MaxSize(100)"`
493+
Sorting int8
494494
}
495495

496496
// _____ .__.__ __

routers/repo/projects.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ func DeleteProjectBoard(ctx *context.Context) {
403403

404404
// AddBoardToProjectPost allows a new board to be added to a project.
405405
func AddBoardToProjectPost(ctx *context.Context) {
406-
form := web.GetForm(ctx).(*auth.EditProjectBoardTitleForm)
406+
form := web.GetForm(ctx).(*auth.EditProjectBoardForm)
407407
if !ctx.Repo.IsOwner() && !ctx.Repo.IsAdmin() && !ctx.Repo.CanAccess(models.AccessModeWrite, models.UnitTypeProjects) {
408408
ctx.JSON(403, map[string]string{
409409
"message": "Only authorized users are allowed to perform this action.",
@@ -481,9 +481,9 @@ func checkProjectBoardChangePermissions(ctx *context.Context) (*models.Project,
481481
return project, board
482482
}
483483

484-
// EditProjectBoardTitle allows a project board's title to be updated
485-
func EditProjectBoardTitle(ctx *context.Context) {
486-
form := web.GetForm(ctx).(*auth.EditProjectBoardTitleForm)
484+
// EditProjectBoard allows a project board's to be updated
485+
func EditProjectBoard(ctx *context.Context) {
486+
form := web.GetForm(ctx).(*auth.EditProjectBoardForm)
487487
_, board := checkProjectBoardChangePermissions(ctx)
488488
if ctx.Written() {
489489
return
@@ -493,6 +493,10 @@ func EditProjectBoardTitle(ctx *context.Context) {
493493
board.Title = form.Title
494494
}
495495

496+
if form.Sorting != 0 {
497+
board.Sorting = form.Sorting
498+
}
499+
496500
if err := models.UpdateProjectBoard(board); err != nil {
497501
ctx.ServerError("UpdateProjectBoard", err)
498502
return

routers/routes/web.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -853,15 +853,15 @@ func RegisterRoutes(m *web.Route) {
853853
m.Get("/new", repo.NewProject)
854854
m.Post("/new", bindIgnErr(auth.CreateProjectForm{}), repo.NewProjectPost)
855855
m.Group("/{id}", func() {
856-
m.Post("", bindIgnErr(auth.EditProjectBoardTitleForm{}), repo.AddBoardToProjectPost)
856+
m.Post("", bindIgnErr(auth.EditProjectBoardForm{}), repo.AddBoardToProjectPost)
857857
m.Post("/delete", repo.DeleteProject)
858858

859859
m.Get("/edit", repo.EditProject)
860860
m.Post("/edit", bindIgnErr(auth.CreateProjectForm{}), repo.EditProjectPost)
861861
m.Post("/{action:open|close}", repo.ChangeProjectStatus)
862862

863863
m.Group("/{boardID}", func() {
864-
m.Put("", bindIgnErr(auth.EditProjectBoardTitleForm{}), repo.EditProjectBoardTitle)
864+
m.Put("", bindIgnErr(auth.EditProjectBoardForm{}), repo.EditProjectBoard)
865865
m.Delete("", repo.DeleteProjectBoard)
866866
m.Post("/default", repo.SetDefaultProjectBoard)
867867

templates/repo/projects/view.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
<div class="board">
7373
{{ range $board := .Boards }}
7474

75-
<div class="ui segment board-column">
75+
<div class="ui segment board-column" data-id="{{.ID}}" data-sorting="{{.Sorting}}" data-url="{{$.RepoLink}}/projects/{{$.Project.ID}}/{{.ID}}">
7676
<div class="board-column-header">
7777
<div class="ui large label board-label">{{.Title}}</div>
7878
{{if and $.CanWriteProjects (not $.Repository.IsArchived) $.PageIsProjects (ne .ID 0)}}

web_src/js/features/projects.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,34 @@ export default async function initProject() {
88
const {Sortable} = await import(/* webpackChunkName: "sortable" */'sortablejs');
99
const boardColumns = document.getElementsByClassName('board-column');
1010

11+
new Sortable(
12+
document.getElementsByClassName('board')[0],
13+
{
14+
group: 'board-column',
15+
draggable: '.board-column',
16+
animation: 150,
17+
onSort: () => {
18+
const board = document.getElementsByClassName('board')[0];
19+
const boardColumns = board.getElementsByClassName('board-column');
20+
21+
boardColumns.forEach((column, i) => {
22+
if (parseInt($(column).data('sorting')) !== i) {
23+
$.ajax({
24+
url: $(column).data('url'),
25+
data: JSON.stringify({sorting: i}),
26+
headers: {
27+
'X-Csrf-Token': csrf,
28+
'X-Remote': true,
29+
},
30+
contentType: 'application/json',
31+
method: 'PUT',
32+
});
33+
}
34+
});
35+
},
36+
},
37+
);
38+
1139
for (const column of boardColumns) {
1240
new Sortable(
1341
column.getElementsByClassName('board')[0],
@@ -74,6 +102,7 @@ export default async function initProject() {
74102

75103
window.location.reload();
76104
});
105+
77106
$('.delete-project-board').each(function () {
78107
$(this).click(function (e) {
79108
e.preventDefault();

0 commit comments

Comments
 (0)