mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	@@ -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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//    _____  .__.__                   __
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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)}}
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user