Add config options to hide issue events (#17414)
* Add config option to hide issue events Adds a config option `HIDE_ISSUE_EVENTS` to hide most issue events (changed labels, milestones, projects...) on the issue detail page. If this is true, only the following events (comment types) are shown: * plain comments * closed/reopned/merged * reviews * Make configurable using a list * Add docs * Add missing newline * Fix merge issues * Allow changes per user settings * Fix lint * Rm old docs * Apply suggestions from code review * Use bitsets * Rm comment * fmt * Fix lint * Use variable/constant to provide key * fmt * fix lint * refactor * Add a prefix for user setting key * Add license comment * Add license comment * Update services/forms/user_form_hidden_comments.go Co-authored-by: Gusted <williamzijl7@hotmail.com> * check len == 0 Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: Gusted <williamzijl7@hotmail.com> Co-authored-by: 6543 <6543@obermui.de>
This commit is contained in:
parent
108f1aab5c
commit
1f40933d38
16 changed files with 1125 additions and 808 deletions
|
@ -99,7 +99,7 @@ const (
|
|||
// 28 merge pull request
|
||||
CommentTypeMergePull
|
||||
// 29 push to PR head branch
|
||||
CommentTypePullPush
|
||||
CommentTypePullRequestPush
|
||||
// 30 Project changed
|
||||
CommentTypeProject
|
||||
// 31 Project board changed
|
||||
|
@ -725,7 +725,7 @@ func (c *Comment) CodeCommentURL() string {
|
|||
|
||||
// LoadPushCommits Load push commits
|
||||
func (c *Comment) LoadPushCommits(ctx context.Context) (err error) {
|
||||
if c.Content == "" || c.Commits != nil || c.Type != CommentTypePullPush {
|
||||
if c.Content == "" || c.Commits != nil || c.Type != CommentTypePullRequestPush {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1325,7 +1325,7 @@ func CreatePushPullComment(ctx context.Context, pusher *user_model.User, pr *Pul
|
|||
}
|
||||
|
||||
ops := &CreateCommentOptions{
|
||||
Type: CommentTypePullPush,
|
||||
Type: CommentTypePullRequestPush,
|
||||
Doer: pusher,
|
||||
Repo: pr.BaseRepo,
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ func init() {
|
|||
db.RegisterModel(new(Setting))
|
||||
}
|
||||
|
||||
// GetSettings returns specific settings from user
|
||||
func GetSettings(uid int64, keys []string) (map[string]*Setting, error) {
|
||||
// GetUserSettings returns specific settings from user
|
||||
func GetUserSettings(uid int64, keys []string) (map[string]*Setting, error) {
|
||||
settings := make([]*Setting, 0, len(keys))
|
||||
if err := db.GetEngine(db.DefaultContext).
|
||||
Where("user_id=?", uid).
|
||||
|
@ -62,21 +62,53 @@ func GetUserAllSettings(uid int64) (map[string]*Setting, error) {
|
|||
return settingsMap, nil
|
||||
}
|
||||
|
||||
// DeleteSetting deletes a specific setting for a user
|
||||
func DeleteSetting(setting *Setting) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Delete(setting)
|
||||
func validateUserSettingKey(key string) error {
|
||||
if len(key) == 0 {
|
||||
return fmt.Errorf("setting key must be set")
|
||||
}
|
||||
if strings.ToLower(key) != key {
|
||||
return fmt.Errorf("setting key should be lowercase")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUserSetting gets a specific setting for a user
|
||||
func GetUserSetting(userID int64, key string, def ...string) (string, error) {
|
||||
if err := validateUserSettingKey(key); err != nil {
|
||||
return "", err
|
||||
}
|
||||
setting := &Setting{UserID: userID, SettingKey: key}
|
||||
has, err := db.GetEngine(db.DefaultContext).Get(setting)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !has {
|
||||
if len(def) == 1 {
|
||||
return def[0], nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
return setting.SettingValue, nil
|
||||
}
|
||||
|
||||
// DeleteUserSetting deletes a specific setting for a user
|
||||
func DeleteUserSetting(userID int64, key string) error {
|
||||
if err := validateUserSettingKey(key); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := db.GetEngine(db.DefaultContext).Delete(&Setting{UserID: userID, SettingKey: key})
|
||||
return err
|
||||
}
|
||||
|
||||
// SetSetting updates a users' setting for a specific key
|
||||
func SetSetting(setting *Setting) error {
|
||||
if strings.ToLower(setting.SettingKey) != setting.SettingKey {
|
||||
return fmt.Errorf("setting key should be lowercase")
|
||||
// SetUserSetting updates a users' setting for a specific key
|
||||
func SetUserSetting(userID int64, key, value string) error {
|
||||
if err := validateUserSettingKey(key); err != nil {
|
||||
return err
|
||||
}
|
||||
return upsertSettingValue(setting.UserID, setting.SettingKey, setting.SettingValue)
|
||||
return upsertUserSettingValue(userID, key, value)
|
||||
}
|
||||
|
||||
func upsertSettingValue(userID int64, key, value string) error {
|
||||
func upsertUserSettingValue(userID int64, key, value string) error {
|
||||
return db.WithTx(func(ctx context.Context) error {
|
||||
e := db.GetEngine(ctx)
|
||||
|
||||
|
|
10
models/user/setting_keys.go
Normal file
10
models/user/setting_keys.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package user
|
||||
|
||||
const (
|
||||
// SettingsKeyHiddenCommentTypes is the settings key for hidden comment types
|
||||
SettingsKeyHiddenCommentTypes = "issue.hidden_comment_types"
|
||||
)
|
|
@ -19,21 +19,29 @@ func TestSettings(t *testing.T) {
|
|||
newSetting := &Setting{UserID: 99, SettingKey: keyName, SettingValue: "Gitea User Setting Test"}
|
||||
|
||||
// create setting
|
||||
err := SetSetting(newSetting)
|
||||
err := SetUserSetting(newSetting.UserID, newSetting.SettingKey, newSetting.SettingValue)
|
||||
assert.NoError(t, err)
|
||||
// test about saving unchanged values
|
||||
err = SetSetting(newSetting)
|
||||
err = SetUserSetting(newSetting.UserID, newSetting.SettingKey, newSetting.SettingValue)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// get specific setting
|
||||
settings, err := GetSettings(99, []string{keyName})
|
||||
settings, err := GetUserSettings(99, []string{keyName})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, settings, 1)
|
||||
assert.EqualValues(t, newSetting.SettingValue, settings[keyName].SettingValue)
|
||||
|
||||
settingValue, err := GetUserSetting(99, keyName)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, newSetting.SettingValue, settingValue)
|
||||
|
||||
settingValue, err = GetUserSetting(99, "no_such")
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "", settingValue)
|
||||
|
||||
// updated setting
|
||||
updatedSetting := &Setting{UserID: 99, SettingKey: keyName, SettingValue: "Updated"}
|
||||
err = SetSetting(updatedSetting)
|
||||
err = SetUserSetting(updatedSetting.UserID, updatedSetting.SettingKey, updatedSetting.SettingValue)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// get all settings
|
||||
|
@ -43,7 +51,7 @@ func TestSettings(t *testing.T) {
|
|||
assert.EqualValues(t, updatedSetting.SettingValue, settings[updatedSetting.SettingKey].SettingValue)
|
||||
|
||||
// delete setting
|
||||
err = DeleteSetting(&Setting{UserID: 99, SettingKey: keyName})
|
||||
err = DeleteUserSetting(99, keyName)
|
||||
assert.NoError(t, err)
|
||||
settings, err = GetUserAllSettings(99)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
@ -46,9 +46,11 @@ func (ctx *Context) FormInt64(key string) int64 {
|
|||
return v
|
||||
}
|
||||
|
||||
// FormBool returns true if the value for the provided key in the form is "1" or "true"
|
||||
// FormBool returns true if the value for the provided key in the form is "1", "true" or "on"
|
||||
func (ctx *Context) FormBool(key string) bool {
|
||||
v, _ := strconv.ParseBool(ctx.Req.FormValue(key))
|
||||
s := ctx.Req.FormValue(key)
|
||||
v, _ := strconv.ParseBool(s)
|
||||
v = v || strings.EqualFold(s, "on")
|
||||
return v
|
||||
}
|
||||
|
||||
|
@ -59,6 +61,8 @@ func (ctx *Context) FormOptionalBool(key string) util.OptionalBool {
|
|||
if len(value) == 0 {
|
||||
return util.OptionalBoolNone
|
||||
}
|
||||
v, _ := strconv.ParseBool(ctx.Req.FormValue(key))
|
||||
s := ctx.Req.FormValue(key)
|
||||
v, _ := strconv.ParseBool(s)
|
||||
v = v || strings.EqualFold(s, "on")
|
||||
return util.OptionalBoolOf(v)
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ func (m *mailNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *rep
|
|||
act = models.ActionCommentIssue
|
||||
} else if comment.Type == models.CommentTypeCode {
|
||||
act = models.ActionCommentIssue
|
||||
} else if comment.Type == models.CommentTypePullPush {
|
||||
} else if comment.Type == models.CommentTypePullRequestPush {
|
||||
act = 0
|
||||
}
|
||||
|
||||
|
|
|
@ -549,6 +549,22 @@ continue = Continue
|
|||
cancel = Cancel
|
||||
language = Language
|
||||
ui = Theme
|
||||
hidden_comment_types = Hidden comment types
|
||||
comment_type_group_reference = Reference
|
||||
comment_type_group_label = Label
|
||||
comment_type_group_milestone = Milestone
|
||||
comment_type_group_assignee = Assignee
|
||||
comment_type_group_title = Title
|
||||
comment_type_group_branch = Branch
|
||||
comment_type_group_time_tracking = Time Tracking
|
||||
comment_type_group_deadline = Deadline
|
||||
comment_type_group_dependency = Dependency
|
||||
comment_type_group_lock = Lock Status
|
||||
comment_type_group_review_request = Review request
|
||||
comment_type_group_pull_request_push = Added commits
|
||||
comment_type_group_project = Project
|
||||
comment_type_group_issue_ref = Issue reference
|
||||
saved_successfully = Your settings were saved successfully.
|
||||
privacy = Privacy
|
||||
keep_activity_private = Hide the activity from the profile page
|
||||
keep_activity_private_popup = Makes the activity visible only for you and the admins
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
|
@ -1465,7 +1466,7 @@ func ViewIssue(ctx *context.Context) {
|
|||
ctx.ServerError("LoadResolveDoer", err)
|
||||
return
|
||||
}
|
||||
} else if comment.Type == models.CommentTypePullPush {
|
||||
} else if comment.Type == models.CommentTypePullRequestPush {
|
||||
participants = addParticipant(comment.Poster, participants)
|
||||
if err = comment.LoadPushCommits(ctx); err != nil {
|
||||
ctx.ServerError("LoadPushCommits", err)
|
||||
|
@ -1650,6 +1651,20 @@ func ViewIssue(ctx *context.Context) {
|
|||
ctx.Data["IsRepoAdmin"] = ctx.IsSigned && (ctx.Repo.IsAdmin() || ctx.User.IsAdmin)
|
||||
ctx.Data["LockReasons"] = setting.Repository.Issue.LockReasons
|
||||
ctx.Data["RefEndName"] = git.RefEndName(issue.Ref)
|
||||
|
||||
var hiddenCommentTypes *big.Int
|
||||
if ctx.IsSigned {
|
||||
val, err := user_model.GetUserSetting(ctx.User.ID, user_model.SettingsKeyHiddenCommentTypes)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetUserSetting", err)
|
||||
return
|
||||
}
|
||||
hiddenCommentTypes, _ = new(big.Int).SetString(val, 10) // we can safely ignore the failed conversion here
|
||||
}
|
||||
ctx.Data["ShouldShowCommentType"] = func(commentType models.CommentType) bool {
|
||||
return hiddenCommentTypes == nil || hiddenCommentTypes.Bit(int(commentType)) == 0
|
||||
}
|
||||
|
||||
ctx.HTML(http.StatusOK, tplIssueView)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -358,6 +359,18 @@ func Appearance(ctx *context.Context) {
|
|||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["PageIsSettingsAppearance"] = true
|
||||
|
||||
var hiddenCommentTypes *big.Int
|
||||
val, err := user_model.GetUserSetting(ctx.User.ID, user_model.SettingsKeyHiddenCommentTypes)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetUserSetting", err)
|
||||
return
|
||||
}
|
||||
hiddenCommentTypes, _ = new(big.Int).SetString(val, 10) // we can safely ignore the failed conversion here
|
||||
|
||||
ctx.Data["IsCommentTypeGroupChecked"] = func(commentTypeGroup string) bool {
|
||||
return forms.IsUserHiddenCommentTypeGroupChecked(commentTypeGroup, hiddenCommentTypes)
|
||||
}
|
||||
|
||||
ctx.HTML(http.StatusOK, tplSettingsAppearance)
|
||||
}
|
||||
|
||||
|
@ -416,3 +429,16 @@ func UpdateUserLang(ctx *context.Context) {
|
|||
ctx.Flash.Success(i18n.Tr(ctx.User.Language, "settings.update_language_success"))
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
|
||||
}
|
||||
|
||||
// UpdateUserHiddenComments update a user's shown comment types
|
||||
func UpdateUserHiddenComments(ctx *context.Context) {
|
||||
err := user_model.SetUserSetting(ctx.User.ID, user_model.SettingsKeyHiddenCommentTypes, forms.UserHiddenCommentTypesFromRequest(ctx).String())
|
||||
if err != nil {
|
||||
ctx.ServerError("SetUserSetting", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("User settings updated: %s", ctx.User.Name)
|
||||
ctx.Flash.Success(ctx.Tr("settings.saved_successfully"))
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
|
||||
}
|
||||
|
|
|
@ -323,6 +323,7 @@ func RegisterRoutes(m *web.Route) {
|
|||
m.Group("/appearance", func() {
|
||||
m.Get("", user_setting.Appearance)
|
||||
m.Post("/language", bindIgnErr(forms.UpdateLanguageForm{}), user_setting.UpdateUserLang)
|
||||
m.Post("/hidden_comments", user_setting.UpdateUserHiddenComments)
|
||||
m.Post("/theme", bindIgnErr(forms.UpdateThemeForm{}), user_setting.UpdateUIThemePost)
|
||||
})
|
||||
m.Group("/security", func() {
|
||||
|
|
105
services/forms/user_form_hidden_comments.go
Normal file
105
services/forms/user_form_hidden_comments.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package forms
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
type hiddenCommentTypeGroupsType map[string][]models.CommentType
|
||||
|
||||
// hiddenCommentTypeGroups maps the group names to comment types, these group names comes from the Web UI (appearance.tmpl)
|
||||
var hiddenCommentTypeGroups = hiddenCommentTypeGroupsType{
|
||||
"reference": {
|
||||
/*3*/ models.CommentTypeIssueRef,
|
||||
/*4*/ models.CommentTypeCommitRef,
|
||||
/*5*/ models.CommentTypeCommentRef,
|
||||
/*6*/ models.CommentTypePullRef,
|
||||
},
|
||||
"label": {
|
||||
/*7*/ models.CommentTypeLabel,
|
||||
},
|
||||
"milestone": {
|
||||
/*8*/ models.CommentTypeMilestone,
|
||||
},
|
||||
"assignee": {
|
||||
/*9*/ models.CommentTypeAssignees,
|
||||
},
|
||||
"title": {
|
||||
/*10*/ models.CommentTypeChangeTitle,
|
||||
},
|
||||
"branch": {
|
||||
/*11*/ models.CommentTypeDeleteBranch,
|
||||
/*25*/ models.CommentTypeChangeTargetBranch,
|
||||
},
|
||||
"time_tracking": {
|
||||
/*12*/ models.CommentTypeStartTracking,
|
||||
/*13*/ models.CommentTypeStopTracking,
|
||||
/*14*/ models.CommentTypeAddTimeManual,
|
||||
/*15*/ models.CommentTypeCancelTracking,
|
||||
/*26*/ models.CommentTypeDeleteTimeManual,
|
||||
},
|
||||
"deadline": {
|
||||
/*16*/ models.CommentTypeAddedDeadline,
|
||||
/*17*/ models.CommentTypeModifiedDeadline,
|
||||
/*18*/ models.CommentTypeRemovedDeadline,
|
||||
},
|
||||
"dependency": {
|
||||
/*19*/ models.CommentTypeAddDependency,
|
||||
/*20*/ models.CommentTypeRemoveDependency,
|
||||
},
|
||||
"lock": {
|
||||
/*23*/ models.CommentTypeLock,
|
||||
/*24*/ models.CommentTypeUnlock,
|
||||
},
|
||||
"review_request": {
|
||||
/*27*/ models.CommentTypeReviewRequest,
|
||||
},
|
||||
"pull_request_push": {
|
||||
/*29*/ models.CommentTypePullRequestPush,
|
||||
},
|
||||
"project": {
|
||||
/*30*/ models.CommentTypeProject,
|
||||
/*31*/ models.CommentTypeProjectBoard,
|
||||
},
|
||||
"issue_ref": {
|
||||
/*33*/ models.CommentTypeChangeIssueRef,
|
||||
},
|
||||
}
|
||||
|
||||
// UserHiddenCommentTypesFromRequest parse the form to hidden comment types bitset
|
||||
func UserHiddenCommentTypesFromRequest(ctx *context.Context) *big.Int {
|
||||
bitset := new(big.Int)
|
||||
for group, commentTypes := range hiddenCommentTypeGroups {
|
||||
if ctx.FormBool(group) {
|
||||
for _, commentType := range commentTypes {
|
||||
bitset = bitset.SetBit(bitset, int(commentType), 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
return bitset
|
||||
}
|
||||
|
||||
// IsUserHiddenCommentTypeGroupChecked check whether a hidden comment type group is "enabled" (checked on UI)
|
||||
func IsUserHiddenCommentTypeGroupChecked(group string, hiddenCommentTypes *big.Int) (ret bool) {
|
||||
commentTypes, ok := hiddenCommentTypeGroups[group]
|
||||
if !ok {
|
||||
log.Critical("the group map for hidden comment types is out of sync, unknown group: %v", group)
|
||||
return
|
||||
}
|
||||
if hiddenCommentTypes == nil {
|
||||
return false
|
||||
}
|
||||
for _, commentType := range commentTypes {
|
||||
if hiddenCommentTypes.Bit(int(commentType)) == 1 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -449,7 +449,7 @@ func actionToTemplate(issue *models.Issue, actionType models.ActionType,
|
|||
name = "code"
|
||||
case models.CommentTypeAssignees:
|
||||
name = "assigned"
|
||||
case models.CommentTypePullPush:
|
||||
case models.CommentTypePullRequestPush:
|
||||
name = "push"
|
||||
default:
|
||||
name = "default"
|
||||
|
|
|
@ -21,7 +21,7 @@ func MailParticipantsComment(ctx context.Context, c *models.Comment, opType mode
|
|||
}
|
||||
|
||||
content := c.Content
|
||||
if c.Type == models.CommentTypePullPush {
|
||||
if c.Type == models.CommentTypePullRequestPush {
|
||||
content = ""
|
||||
}
|
||||
if err := mailIssueCommentToParticipants(
|
||||
|
|
|
@ -108,7 +108,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, pull *mode
|
|||
}
|
||||
|
||||
ops := &models.CreateCommentOptions{
|
||||
Type: models.CommentTypePullPush,
|
||||
Type: models.CommentTypePullRequestPush,
|
||||
Doer: pull.Poster,
|
||||
Repo: repo,
|
||||
Issue: pr.Issue,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{{ template "base/alert" }}
|
||||
{{range .Issue.Comments}}
|
||||
{{if call $.ShouldShowCommentType .Type}}
|
||||
{{ $createdStr:= TimeSinceUnix .CreatedUnix $.Lang }}
|
||||
|
||||
<!-- 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE_REF, 4 = COMMIT_REF,
|
||||
|
@ -832,4 +833,5 @@
|
|||
</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
@ -68,6 +68,104 @@
|
|||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Shown comment event types -->
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "settings.hidden_comment_types"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<form class="ui form" action="{{.Link}}/hidden_comments" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="reference" type="checkbox" {{if(call .IsCommentTypeGroupChecked "reference")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_reference"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="label" type="checkbox" {{if (call .IsCommentTypeGroupChecked "label")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_label"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="milestone" type="checkbox" {{if (call .IsCommentTypeGroupChecked "milestone")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_milestone"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="assignee" type="checkbox" {{if (call .IsCommentTypeGroupChecked "assignee")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_assignee"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="title" type="checkbox" {{if (call .IsCommentTypeGroupChecked "title")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_title"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="branch" type="checkbox" {{if (call .IsCommentTypeGroupChecked "branch")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_branch"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="time_tracking" type="checkbox" {{if (call .IsCommentTypeGroupChecked "time_tracking")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_time_tracking"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="deadline" type="checkbox" {{if (call .IsCommentTypeGroupChecked "deadline")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_deadline"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="dependency" type="checkbox" {{if (call .IsCommentTypeGroupChecked "dependency")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_dependency"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="lock" type="checkbox" {{if (call .IsCommentTypeGroupChecked "lock")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_lock"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="review_request" type="checkbox" {{if (call .IsCommentTypeGroupChecked "review_request")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_review_request"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="pull_request_push" type="checkbox" {{if (call .IsCommentTypeGroupChecked "pull_request_push")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_pull_request_push"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="project" type="checkbox" {{if (call .IsCommentTypeGroupChecked "project")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_project"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<input name="issue_ref" type="checkbox" {{if (call .IsCommentTypeGroupChecked "issue_ref")}}checked{{end}}>
|
||||
<label>{{.i18n.Tr "settings.comment_type_group_issue_ref"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<button class="ui green button">{{$.i18n.Tr "save"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
Reference in a new issue