Merge pull request 'Allow users to hide all "Add more units..." hints' (#2533) from algernon/forgejo:less-is-more into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/2533 Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
This commit is contained in:
commit
0bfd4ca532
15 changed files with 233 additions and 24 deletions
|
@ -50,6 +50,8 @@ var migrations = []*Migration{
|
|||
NewMigration("create the forgejo_repo_flag table", forgejo_v1_22.CreateRepoFlagTable),
|
||||
// v5 -> v6
|
||||
NewMigration("Add wiki_branch to repository", forgejo_v1_22.AddWikiBranchToRepository),
|
||||
// v6 -> v7
|
||||
NewMigration("Add enable_repo_unit_hints to the user table", forgejo_v1_22.AddUserRepoUnitHintsSetting),
|
||||
}
|
||||
|
||||
// GetCurrentDBVersion returns the current Forgejo database version.
|
||||
|
|
17
models/forgejo_migrations/v1_22/v7.go
Normal file
17
models/forgejo_migrations/v1_22/v7.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2024 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package v1_22 //nolint
|
||||
|
||||
import (
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func AddUserRepoUnitHintsSetting(x *xorm.Engine) error {
|
||||
type User struct {
|
||||
ID int64
|
||||
EnableRepoUnitHints bool `xorm:"NOT NULL DEFAULT true"`
|
||||
}
|
||||
|
||||
return x.Sync(&User{})
|
||||
}
|
|
@ -146,6 +146,7 @@ type User struct {
|
|||
DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"`
|
||||
Theme string `xorm:"NOT NULL DEFAULT ''"`
|
||||
KeepActivityPrivate bool `xorm:"NOT NULL DEFAULT false"`
|
||||
EnableRepoUnitHints bool `xorm:"NOT NULL DEFAULT true"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -67,13 +67,14 @@ func (u User) MarshalJSON() ([]byte, error) {
|
|||
// UserSettings represents user settings
|
||||
// swagger:model
|
||||
type UserSettings struct {
|
||||
FullName string `json:"full_name"`
|
||||
Website string `json:"website"`
|
||||
Description string `json:"description"`
|
||||
Location string `json:"location"`
|
||||
Language string `json:"language"`
|
||||
Theme string `json:"theme"`
|
||||
DiffViewStyle string `json:"diff_view_style"`
|
||||
FullName string `json:"full_name"`
|
||||
Website string `json:"website"`
|
||||
Description string `json:"description"`
|
||||
Location string `json:"location"`
|
||||
Language string `json:"language"`
|
||||
Theme string `json:"theme"`
|
||||
DiffViewStyle string `json:"diff_view_style"`
|
||||
EnableRepoUnitHints bool `json:"enable_repo_unit_hints"`
|
||||
// Privacy
|
||||
HideEmail bool `json:"hide_email"`
|
||||
HideActivity bool `json:"hide_activity"`
|
||||
|
@ -82,13 +83,14 @@ type UserSettings struct {
|
|||
// UserSettingsOptions represents options to change user settings
|
||||
// swagger:model
|
||||
type UserSettingsOptions struct {
|
||||
FullName *string `json:"full_name" binding:"MaxSize(100)"`
|
||||
Website *string `json:"website" binding:"OmitEmpty;ValidUrl;MaxSize(255)"`
|
||||
Description *string `json:"description" binding:"MaxSize(255)"`
|
||||
Location *string `json:"location" binding:"MaxSize(50)"`
|
||||
Language *string `json:"language"`
|
||||
Theme *string `json:"theme"`
|
||||
DiffViewStyle *string `json:"diff_view_style"`
|
||||
FullName *string `json:"full_name" binding:"MaxSize(100)"`
|
||||
Website *string `json:"website" binding:"OmitEmpty;ValidUrl;MaxSize(255)"`
|
||||
Description *string `json:"description" binding:"MaxSize(255)"`
|
||||
Location *string `json:"location" binding:"MaxSize(50)"`
|
||||
Language *string `json:"language"`
|
||||
Theme *string `json:"theme"`
|
||||
DiffViewStyle *string `json:"diff_view_style"`
|
||||
EnableRepoUnitHints *bool `json:"enable_repo_unit_hints"`
|
||||
// Privacy
|
||||
HideEmail *bool `json:"hide_email"`
|
||||
HideActivity *bool `json:"hide_activity"`
|
||||
|
|
|
@ -711,6 +711,11 @@ continue = Continue
|
|||
cancel = Cancel
|
||||
language = Language
|
||||
ui = Theme
|
||||
hints = Hints
|
||||
additional_repo_units_hint_description = Display an "Add more units..." button for repositories that do not have all available units enabled.
|
||||
additional_repo_units_hint = Encourage enabling additional repository units
|
||||
update_hints = Update hints
|
||||
update_hints_success = Hints have been updated.
|
||||
hidden_comment_types = Hidden comment types
|
||||
hidden_comment_types_description = Comment types checked here will not be shown inside issue pages. Checking "Label" for example removes all "<user> added/removed <label>" comments.
|
||||
hidden_comment_types.ref_tooltip = Comments where this issue was referenced from another issue/commit/…
|
||||
|
|
|
@ -55,6 +55,7 @@ func UpdateUserSettings(ctx *context.APIContext) {
|
|||
DiffViewStyle: optional.FromPtr(form.DiffViewStyle),
|
||||
KeepEmailPrivate: optional.FromPtr(form.HideEmail),
|
||||
KeepActivityPrivate: optional.FromPtr(form.HideActivity),
|
||||
EnableRepoUnitHints: optional.FromPtr(form.EnableRepoUnitHints),
|
||||
}
|
||||
if err := user_service.UpdateUser(ctx, ctx.Doer, opts); err != nil {
|
||||
ctx.InternalServerError(err)
|
||||
|
|
|
@ -393,6 +393,25 @@ func UpdateUserLang(ctx *context.Context) {
|
|||
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
|
||||
}
|
||||
|
||||
// UpdateUserHints updates a user's hints settings
|
||||
func UpdateUserHints(ctx *context.Context) {
|
||||
form := web.GetForm(ctx).(*forms.UpdateHintsForm)
|
||||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["PageIsSettingsAppearance"] = true
|
||||
|
||||
opts := &user_service.UpdateOptions{
|
||||
EnableRepoUnitHints: optional.Some(form.EnableRepoUnitHints),
|
||||
}
|
||||
if err := user_service.UpdateUser(ctx, ctx.Doer, opts); err != nil {
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("User settings updated: %s", ctx.Doer.Name)
|
||||
ctx.Flash.Success(translation.NewLocale(ctx.Doer.Language).TrString("settings.update_hints_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, ctx.Doer.ID, user_model.SettingsKeyHiddenCommentTypes, forms.UserHiddenCommentTypesFromRequest(ctx).String())
|
||||
|
|
|
@ -568,6 +568,7 @@ func registerRoutes(m *web.Route) {
|
|||
m.Group("/appearance", func() {
|
||||
m.Get("", user_setting.Appearance)
|
||||
m.Post("/language", web.Bind(forms.UpdateLanguageForm{}), user_setting.UpdateUserLang)
|
||||
m.Post("/hints", web.Bind(forms.UpdateHintsForm{}), user_setting.UpdateUserHints)
|
||||
m.Post("/hidden_comments", user_setting.UpdateUserHiddenComments)
|
||||
m.Post("/theme", web.Bind(forms.UpdateThemeForm{}), user_setting.UpdateUIThemePost)
|
||||
})
|
||||
|
|
|
@ -86,15 +86,16 @@ func toUser(ctx context.Context, user *user_model.User, signed, authed bool) *ap
|
|||
// User2UserSettings return UserSettings based on a user
|
||||
func User2UserSettings(user *user_model.User) api.UserSettings {
|
||||
return api.UserSettings{
|
||||
FullName: user.FullName,
|
||||
Website: user.Website,
|
||||
Location: user.Location,
|
||||
Language: user.Language,
|
||||
Description: user.Description,
|
||||
Theme: user.Theme,
|
||||
HideEmail: user.KeepEmailPrivate,
|
||||
HideActivity: user.KeepActivityPrivate,
|
||||
DiffViewStyle: user.DiffViewStyle,
|
||||
FullName: user.FullName,
|
||||
Website: user.Website,
|
||||
Location: user.Location,
|
||||
Language: user.Language,
|
||||
Description: user.Description,
|
||||
Theme: user.Theme,
|
||||
HideEmail: user.KeepEmailPrivate,
|
||||
HideActivity: user.KeepActivityPrivate,
|
||||
DiffViewStyle: user.DiffViewStyle,
|
||||
EnableRepoUnitHints: user.EnableRepoUnitHints,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -234,6 +234,11 @@ type UpdateLanguageForm struct {
|
|||
Language string
|
||||
}
|
||||
|
||||
// UpdateHintsForm form for updating user hint settings
|
||||
type UpdateHintsForm struct {
|
||||
EnableRepoUnitHints bool
|
||||
}
|
||||
|
||||
// Validate validates the fields
|
||||
func (f *UpdateLanguageForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||
ctx := context.GetValidateContext(req)
|
||||
|
|
|
@ -37,6 +37,7 @@ type UpdateOptions struct {
|
|||
EmailNotificationsPreference optional.Option[string]
|
||||
SetLastLogin bool
|
||||
RepoAdminChangeTeamAccess optional.Option[bool]
|
||||
EnableRepoUnitHints optional.Option[bool]
|
||||
}
|
||||
|
||||
func UpdateUser(ctx context.Context, u *user_model.User, opts *UpdateOptions) error {
|
||||
|
@ -83,6 +84,11 @@ func UpdateUser(ctx context.Context, u *user_model.User, opts *UpdateOptions) er
|
|||
|
||||
cols = append(cols, "diff_view_style")
|
||||
}
|
||||
if opts.EnableRepoUnitHints.Has() {
|
||||
u.EnableRepoUnitHints = opts.EnableRepoUnitHints.Value()
|
||||
|
||||
cols = append(cols, "enable_repo_unit_hints")
|
||||
}
|
||||
|
||||
if opts.AllowGitHook.Has() {
|
||||
u.AllowGitHook = opts.AllowGitHook.Value()
|
||||
|
|
|
@ -172,7 +172,7 @@
|
|||
{{end}}
|
||||
|
||||
{{if .Permission.IsAdmin}}
|
||||
{{if not (.Repository.AllUnitsEnabled ctx)}}
|
||||
{{if and .SignedUser.EnableRepoUnitHints (not (.Repository.AllUnitsEnabled ctx))}}
|
||||
<a class="{{if .PageIsRepoSettingsUnits}}active {{end}}item" href="{{.RepoLink}}/settings/units">
|
||||
{{svg "octicon-diff-added"}} {{ctx.Locale.Tr "repo.settings.units.add_more"}}
|
||||
</a>
|
||||
|
|
8
templates/swagger/v1_json.tmpl
generated
8
templates/swagger/v1_json.tmpl
generated
|
@ -23853,6 +23853,10 @@
|
|||
"type": "string",
|
||||
"x-go-name": "DiffViewStyle"
|
||||
},
|
||||
"enable_repo_unit_hints": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableRepoUnitHints"
|
||||
},
|
||||
"full_name": {
|
||||
"type": "string",
|
||||
"x-go-name": "FullName"
|
||||
|
@ -23897,6 +23901,10 @@
|
|||
"type": "string",
|
||||
"x-go-name": "DiffViewStyle"
|
||||
},
|
||||
"enable_repo_unit_hints": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnableRepoUnitHints"
|
||||
},
|
||||
"full_name": {
|
||||
"type": "string",
|
||||
"x-go-name": "FullName"
|
||||
|
|
|
@ -66,6 +66,25 @@
|
|||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Hints -->
|
||||
<h4 class="ui top attached header">
|
||||
{{ctx.Locale.Tr "settings.hints"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<form class="ui form" action="{{.Link}}/hints" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox" data-tooltip-content="{{ctx.Locale.Tr "settings.additional_repo_units_hint_description"}}">
|
||||
<input name="enable_repo_unit_hints" type="checkbox" {{if $.SignedUser.EnableRepoUnitHints}}checked{{end}}>
|
||||
<label>{{ctx.Locale.Tr "settings.additional_repo_units_hint"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<button class="ui primary button">{{ctx.Locale.Tr "settings.update_hints"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Shown comment event types -->
|
||||
<h4 class="ui top attached header">
|
||||
{{ctx.Locale.Tr "settings.hidden_comment_types"}}
|
||||
|
|
|
@ -4,12 +4,14 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
@ -306,3 +308,123 @@ func TestUserLocationMapLink(t *testing.T) {
|
|||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
htmlDoc.AssertElement(t, `a[href="https://example/foo/A%2Fb"]`, true)
|
||||
}
|
||||
|
||||
func TestUserHints(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"})
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteUser)
|
||||
|
||||
// Create a known-good repo, with only one unit enabled
|
||||
repo, _, f := CreateDeclarativeRepo(t, user, "", []unit_model.Type{
|
||||
unit_model.TypeCode,
|
||||
}, []unit_model.Type{
|
||||
unit_model.TypePullRequests,
|
||||
unit_model.TypeProjects,
|
||||
unit_model.TypePackages,
|
||||
unit_model.TypeActions,
|
||||
unit_model.TypeIssues,
|
||||
unit_model.TypeWiki,
|
||||
}, nil)
|
||||
defer f()
|
||||
|
||||
ensureRepoUnitHints := func(t *testing.T, hints bool) {
|
||||
t.Helper()
|
||||
|
||||
req := NewRequestWithJSON(t, "PATCH", "/api/v1/user/settings", &api.UserSettingsOptions{
|
||||
EnableRepoUnitHints: &hints,
|
||||
}).AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var userSettings api.UserSettings
|
||||
DecodeJSON(t, resp, &userSettings)
|
||||
assert.Equal(t, hints, userSettings.EnableRepoUnitHints)
|
||||
}
|
||||
|
||||
t.Run("API", func(t *testing.T) {
|
||||
t.Run("setting hints on and off", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
ensureRepoUnitHints(t, true)
|
||||
ensureRepoUnitHints(t, false)
|
||||
})
|
||||
|
||||
t.Run("retrieving settings", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
for _, v := range []bool{true, false} {
|
||||
ensureRepoUnitHints(t, v)
|
||||
|
||||
req := NewRequest(t, "GET", "/api/v1/user/settings").AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var userSettings api.UserSettings
|
||||
DecodeJSON(t, resp, &userSettings)
|
||||
assert.Equal(t, v, userSettings.EnableRepoUnitHints)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("user settings", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
// Set a known-good state, that isn't the default
|
||||
ensureRepoUnitHints(t, false)
|
||||
|
||||
assertHintState := func(t *testing.T, enabled bool) {
|
||||
t.Helper()
|
||||
|
||||
req := NewRequest(t, "GET", "/user/settings/appearance")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
_, hintChecked := htmlDoc.Find(`input[name="enable_repo_unit_hints"]`).Attr("checked")
|
||||
assert.Equal(t, enabled, hintChecked)
|
||||
}
|
||||
|
||||
t.Run("view", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
assertHintState(t, false)
|
||||
})
|
||||
|
||||
t.Run("change", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequestWithValues(t, "POST", "/user/settings/appearance/hints", map[string]string{
|
||||
"_csrf": GetCSRF(t, session, "/user/settings/appearance"),
|
||||
"enable_repo_unit_hints": "true",
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
|
||||
assertHintState(t, true)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("repo view", func(t *testing.T) {
|
||||
assertAddMore := func(t *testing.T, present bool) {
|
||||
t.Helper()
|
||||
|
||||
req := NewRequest(t, "GET", repo.Link())
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
htmlDoc.AssertElement(t, fmt.Sprintf("a[href='%s/settings/units']", repo.Link()), present)
|
||||
}
|
||||
|
||||
t.Run("hints enabled", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
ensureRepoUnitHints(t, true)
|
||||
assertAddMore(t, true)
|
||||
})
|
||||
|
||||
t.Run("hints disabled", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
ensureRepoUnitHints(t, false)
|
||||
assertAddMore(t, false)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue