This commit is contained in:
+74
-4
@@ -95,6 +95,7 @@ type PageData struct {
|
||||
ReportSummary []PersonReportSummary
|
||||
ReportTotals ReportTotals
|
||||
Board []BoardColumn
|
||||
BoardTags []BoardTag
|
||||
}
|
||||
|
||||
type Stats struct{ Present, Remote, Leave int }
|
||||
@@ -207,6 +208,14 @@ func New(cfg Config) (*Server, error) {
|
||||
r, _ := utf8.DecodeRuneInString(v)
|
||||
return string(r)
|
||||
},
|
||||
"hasTag": func(tags []BoardTag, id int64) bool {
|
||||
for _, tag := range tags {
|
||||
if tag.ID == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
}
|
||||
tmpl, err := template.New("root").Funcs(funcs).ParseFS(assets, "templates/*.html")
|
||||
if err != nil {
|
||||
@@ -262,6 +271,9 @@ func (s *Server) routes(mux *http.ServeMux) {
|
||||
mux.HandleFunc("POST /board/tasks", s.requireAuth(s.csrf(s.createBoardTask)))
|
||||
mux.HandleFunc("POST /board/tasks/{id}/move", s.requireAuth(s.csrf(s.moveBoardTask)))
|
||||
mux.HandleFunc("POST /board/tasks/{id}/delete", s.requireAuth(s.csrf(s.deleteBoardTask)))
|
||||
mux.HandleFunc("POST /board/tasks/{id}/tags", s.requireAuth(s.csrf(s.setBoardTaskTags)))
|
||||
mux.HandleFunc("POST /board/tags", s.requireAuth(s.csrf(s.createBoardTag)))
|
||||
mux.HandleFunc("POST /board/tags/{id}/delete", s.requireAuth(s.csrf(s.deleteBoardTag)))
|
||||
mux.HandleFunc("GET /admin/requests", s.requireAdmin(s.adminPage))
|
||||
mux.HandleFunc("POST /admin/requests/{id}/review", s.requireAdmin(s.csrf(s.reviewRequest)))
|
||||
mux.HandleFunc("GET /admin/users", s.requireAdmin(s.usersPage))
|
||||
@@ -285,8 +297,8 @@ func (s *Server) dayPage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
selected, _ := time.Parse("2006-01-02", day)
|
||||
view := r.URL.Query().Get("view")
|
||||
if view != "week" {
|
||||
view = "day"
|
||||
if view != "day" {
|
||||
view = "week"
|
||||
}
|
||||
var detail DayDetail
|
||||
var week WeekDetail
|
||||
@@ -737,6 +749,11 @@ func (s *Server) boardPage(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "could not load teammates", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
tags, err := s.store.BoardTags()
|
||||
if err != nil {
|
||||
http.Error(w, "could not load board tags", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
columns := []BoardColumn{
|
||||
{Status: "backlog", Title: "Backlog", Hint: "Ready to pick up"},
|
||||
{Status: "in_progress", Title: "In progress", Hint: "Actively being worked"},
|
||||
@@ -752,13 +769,17 @@ func (s *Server) boardPage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
s.render(w, "board.html", PageData{
|
||||
Title: "Team board", User: currentUser(r), CSRF: csrfToken(r), Users: users, Board: columns,
|
||||
Title: "Team board", User: currentUser(r), CSRF: csrfToken(r), Users: users, Board: columns, BoardTags: tags,
|
||||
TodayJalali: jalali.FromTime(time.Now()).String(), Error: r.URL.Query().Get("error"),
|
||||
Flash: r.URL.Query().Get("flash"), SelectedSection: "board",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) createBoardTask(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.TrimSpace(r.FormValue("title")) == "" {
|
||||
http.Redirect(w, r, "/board?error=Task+title+is+required", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
var assigneeID *int64
|
||||
if raw := r.FormValue("assignee_id"); raw != "" {
|
||||
id, err := strconv.ParseInt(raw, 10, 64)
|
||||
@@ -777,7 +798,16 @@ func (s *Server) createBoardTask(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
dueDate = parsed
|
||||
}
|
||||
err := s.store.CreateBoardTask(
|
||||
tagIDs := parseIDList(r.Form["tag_ids"])
|
||||
if newTagName := strings.TrimSpace(r.FormValue("new_tag_name")); newTagName != "" {
|
||||
tag, err := s.store.FindOrCreateBoardTag(newTagName, r.FormValue("new_tag_color"))
|
||||
if err != nil {
|
||||
http.Redirect(w, r, "/board?error="+url.QueryEscape(err.Error()), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
tagIDs = append(tagIDs, tag.ID)
|
||||
}
|
||||
taskID, err := s.store.CreateBoardTask(
|
||||
currentUser(r).ID, r.FormValue("title"), r.FormValue("description"),
|
||||
r.FormValue("status"), assigneeID, dueDate,
|
||||
)
|
||||
@@ -785,9 +815,23 @@ func (s *Server) createBoardTask(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/board?error="+url.QueryEscape(err.Error()), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
if err := s.store.SetBoardTaskTags(taskID, tagIDs); err != nil {
|
||||
http.Redirect(w, r, "/board?error="+url.QueryEscape(err.Error()), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/board?flash=Task+added+to+the+team+board", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func parseIDList(values []string) []int64 {
|
||||
ids := make([]int64, 0, len(values))
|
||||
for _, raw := range values {
|
||||
if id, err := strconv.ParseInt(raw, 10, 64); err == nil && id > 0 {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func (s *Server) moveBoardTask(w http.ResponseWriter, r *http.Request) {
|
||||
id, _ := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err := s.store.MoveBoardTask(id, r.FormValue("status")); err != nil {
|
||||
@@ -807,6 +851,32 @@ func (s *Server) deleteBoardTask(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/board?flash=Task+removed", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func (s *Server) setBoardTaskTags(w http.ResponseWriter, r *http.Request) {
|
||||
id, _ := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err := s.store.SetBoardTaskTags(id, parseIDList(r.Form["tag_ids"])); err != nil {
|
||||
http.Redirect(w, r, "/board?error="+url.QueryEscape(err.Error()), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/board?flash=Task+labels+updated", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func (s *Server) createBoardTag(w http.ResponseWriter, r *http.Request) {
|
||||
if err := s.store.CreateBoardTag(r.FormValue("name"), r.FormValue("color")); err != nil {
|
||||
http.Redirect(w, r, "/board?error="+url.QueryEscape(err.Error()), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/board?flash=Tag+created", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func (s *Server) deleteBoardTag(w http.ResponseWriter, r *http.Request) {
|
||||
id, _ := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||||
if err := s.store.DeleteBoardTag(id); err != nil {
|
||||
http.Redirect(w, r, "/board?error="+url.QueryEscape(err.Error()), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/board?flash=Tag+deleted", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func (s *Server) adminPage(w http.ResponseWriter, r *http.Request) {
|
||||
requests, err := s.store.Requests(currentUser(r).ID, true, r.URL.Query().Get("status"))
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user