[Feature] Custom Reactions (#8886)
* add [ui] Reactions * move contend check from form to go functions * use else if * check if reaction is allowed only on react (so previous custom reaction can be still removed) * use $.AllowedReactions in templates * use ctx.Flash.Error * use it there too * add redirection * back to server error because a wrong reaction is a template issue ... * add emoji list link * add docs entry * small wording nit suggestions from @jolheiser - thx * same reactions as github * fix PR reactions * handle error so template JS could check * Add Integrations Test * add REACTIONS setting to cheat-sheet doc pagerelease/v1.15
parent
674bc772fb
commit
668eaf95d5
|
@ -149,6 +149,9 @@ SHOW_USER_EMAIL = true
|
||||||
DEFAULT_THEME = gitea
|
DEFAULT_THEME = gitea
|
||||||
; All available themes. Allow users select personalized themes regardless of the value of `DEFAULT_THEME`.
|
; All available themes. Allow users select personalized themes regardless of the value of `DEFAULT_THEME`.
|
||||||
THEMES = gitea,arc-green
|
THEMES = gitea,arc-green
|
||||||
|
; All available reactions. Allow users react with different emoji's
|
||||||
|
: For the whole list look at https://gitea.com/gitea/gitea.com/issues/8
|
||||||
|
REACTIONS = +1, -1, laugh, hooray, confused, heart, rocket, eyes
|
||||||
; Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
|
; Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
|
||||||
DEFAULT_SHOW_FULL_NAME = false
|
DEFAULT_SHOW_FULL_NAME = false
|
||||||
; Whether to search within description at repository search on explore page.
|
; Whether to search within description at repository search on explore page.
|
||||||
|
|
|
@ -118,6 +118,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
||||||
- `DEFAULT_THEME`: **gitea**: \[gitea, arc-green\]: Set the default theme for the Gitea install.
|
- `DEFAULT_THEME`: **gitea**: \[gitea, arc-green\]: Set the default theme for the Gitea install.
|
||||||
- `THEMES`: **gitea,arc-green**: All available themes. Allow users select personalized themes
|
- `THEMES`: **gitea,arc-green**: All available themes. Allow users select personalized themes
|
||||||
regardless of the value of `DEFAULT_THEME`.
|
regardless of the value of `DEFAULT_THEME`.
|
||||||
|
- `REACTIONS`: All available reactions. Allow users react with different emoji's.
|
||||||
- `DEFAULT_SHOW_FULL_NAME`: **false**: Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
|
- `DEFAULT_SHOW_FULL_NAME`: **false**: Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
|
||||||
- `SEARCH_REPO_DESCRIPTION`: **true**: Whether to search within description at repository search on explore page.
|
- `SEARCH_REPO_DESCRIPTION`: **true**: Whether to search within description at repository search on explore page.
|
||||||
- `USE_SERVICE_WORKER`: **true**: Whether to enable a Service Worker to cache frontend assets.
|
- `USE_SERVICE_WORKER`: **true**: Whether to enable a Service Worker to cache frontend assets.
|
||||||
|
|
|
@ -161,6 +161,15 @@ Locales may change between versions, so keeping track of your customized locales
|
||||||
|
|
||||||
To add a custom Readme, add a markdown formatted file (without an `.md` extension) to `custom/options/readme`
|
To add a custom Readme, add a markdown formatted file (without an `.md` extension) to `custom/options/readme`
|
||||||
|
|
||||||
|
### Reactions
|
||||||
|
|
||||||
|
To change reaction emoji's you can set allowed reactions at app.ini
|
||||||
|
```
|
||||||
|
[ui]
|
||||||
|
REACTIONS = +1, -1, laugh, confused, heart, hooray, eyes
|
||||||
|
```
|
||||||
|
A full list of supported emoji's is at [emoji list](https://gitea.com/gitea/gitea.com/issues/8)
|
||||||
|
|
||||||
## Customizing the look of Gitea
|
## Customizing the look of Gitea
|
||||||
|
|
||||||
As of version 1.6.0 Gitea has built-in themes. The two built-in themes are, the default theme `gitea`, and a dark theme `arc-green`. To change the look of your Gitea install change the value of `DEFAULT_THEME` in the [ui](https://docs.gitea.io/en-us/config-cheat-sheet/#ui-ui) section of `app.ini` to another one of the available options.
|
As of version 1.6.0 Gitea has built-in themes. The two built-in themes are, the default theme `gitea`, and a dark theme `arc-green`. To change the look of your Gitea install change the value of `DEFAULT_THEME` in the [ui](https://docs.gitea.io/en-us/config-cheat-sheet/#ui-ui) section of `app.ini` to another one of the available options.
|
||||||
|
|
|
@ -194,6 +194,32 @@ func TestIssueCommentClose(t *testing.T) {
|
||||||
assert.Equal(t, "Description", val)
|
assert.Equal(t, "Description", val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIssueReaction(t *testing.T) {
|
||||||
|
defer prepareTestEnv(t)()
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
issueURL := testNewIssue(t, session, "user2", "repo1", "Title", "Description")
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", issueURL)
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
|
|
||||||
|
req = NewRequestWithValues(t, "POST", path.Join(issueURL, "/reactions/react"), map[string]string{
|
||||||
|
"_csrf": htmlDoc.GetCSRF(),
|
||||||
|
"content": "8ball",
|
||||||
|
})
|
||||||
|
session.MakeRequest(t, req, http.StatusInternalServerError)
|
||||||
|
req = NewRequestWithValues(t, "POST", path.Join(issueURL, "/reactions/react"), map[string]string{
|
||||||
|
"_csrf": htmlDoc.GetCSRF(),
|
||||||
|
"content": "eyes",
|
||||||
|
})
|
||||||
|
session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
req = NewRequestWithValues(t, "POST", path.Join(issueURL, "/reactions/unreact"), map[string]string{
|
||||||
|
"_csrf": htmlDoc.GetCSRF(),
|
||||||
|
"content": "eyes",
|
||||||
|
})
|
||||||
|
session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
func TestIssueCrossReference(t *testing.T) {
|
func TestIssueCrossReference(t *testing.T) {
|
||||||
defer prepareTestEnv(t)()
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
|
|
|
@ -347,7 +347,7 @@ func (f *CreateCommentForm) Validate(ctx *macaron.Context, errs binding.Errors)
|
||||||
|
|
||||||
// ReactionForm form for adding and removing reaction
|
// ReactionForm form for adding and removing reaction
|
||||||
type ReactionForm struct {
|
type ReactionForm struct {
|
||||||
Content string `binding:"Required;In(+1,-1,laugh,confused,heart,hooray)"`
|
Content string `binding:"Required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
|
|
|
@ -169,6 +169,7 @@ var (
|
||||||
DefaultShowFullName bool
|
DefaultShowFullName bool
|
||||||
DefaultTheme string
|
DefaultTheme string
|
||||||
Themes []string
|
Themes []string
|
||||||
|
Reactions []string
|
||||||
SearchRepoDescription bool
|
SearchRepoDescription bool
|
||||||
UseServiceWorker bool
|
UseServiceWorker bool
|
||||||
|
|
||||||
|
@ -198,6 +199,7 @@ var (
|
||||||
MaxDisplayFileSize: 8388608,
|
MaxDisplayFileSize: 8388608,
|
||||||
DefaultTheme: `gitea`,
|
DefaultTheme: `gitea`,
|
||||||
Themes: []string{`gitea`, `arc-green`},
|
Themes: []string{`gitea`, `arc-green`},
|
||||||
|
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
|
||||||
Admin: struct {
|
Admin: struct {
|
||||||
UserPagingNum int
|
UserPagingNum int
|
||||||
RepoPagingNum int
|
RepoPagingNum int
|
||||||
|
|
|
@ -673,6 +673,7 @@ func ViewIssue(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.Data["IssueWatch"] = iw
|
ctx.Data["IssueWatch"] = iw
|
||||||
|
ctx.Data["AllowedReactions"] = setting.UI.Reactions
|
||||||
|
|
||||||
issue.RenderedContent = string(markdown.Render([]byte(issue.Content), ctx.Repo.RepoLink,
|
issue.RenderedContent = string(markdown.Render([]byte(issue.Content), ctx.Repo.RepoLink,
|
||||||
ctx.Repo.Repository.ComposeMetas()))
|
ctx.Repo.Repository.ComposeMetas()))
|
||||||
|
@ -1447,6 +1448,12 @@ func ChangeIssueReaction(ctx *context.Context, form auth.ReactionForm) {
|
||||||
|
|
||||||
switch ctx.Params(":action") {
|
switch ctx.Params(":action") {
|
||||||
case "react":
|
case "react":
|
||||||
|
if !util.IsStringInSlice(form.Content, setting.UI.Reactions) {
|
||||||
|
err := fmt.Errorf("ChangeIssueReaction: '%s' is not an allowed reaction", form.Content)
|
||||||
|
ctx.ServerError(err.Error(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
reaction, err := models.CreateIssueReaction(ctx.User, issue, form.Content)
|
reaction, err := models.CreateIssueReaction(ctx.User, issue, form.Content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Info("CreateIssueReaction: %s", err)
|
log.Info("CreateIssueReaction: %s", err)
|
||||||
|
@ -1542,6 +1549,12 @@ func ChangeCommentReaction(ctx *context.Context, form auth.ReactionForm) {
|
||||||
|
|
||||||
switch ctx.Params(":action") {
|
switch ctx.Params(":action") {
|
||||||
case "react":
|
case "react":
|
||||||
|
if !util.IsStringInSlice(form.Content, setting.UI.Reactions) {
|
||||||
|
err := fmt.Errorf("ChangeIssueReaction: '%s' is not an allowed reaction", form.Content)
|
||||||
|
ctx.ServerError(err.Error(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
reaction, err := models.CreateCommentReaction(ctx.User, comment.Issue, comment, form.Content)
|
reaction, err := models.CreateCommentReaction(ctx.User, comment.Issue, comment, form.Content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Info("CreateCommentReaction: %s", err)
|
log.Info("CreateCommentReaction: %s", err)
|
||||||
|
|
|
@ -422,6 +422,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
|
||||||
|
|
||||||
ctx.Data["NumCommits"] = compareInfo.Commits.Len()
|
ctx.Data["NumCommits"] = compareInfo.Commits.Len()
|
||||||
ctx.Data["NumFiles"] = compareInfo.NumFiles
|
ctx.Data["NumFiles"] = compareInfo.NumFiles
|
||||||
|
ctx.Data["AllowedReactions"] = setting.UI.Reactions
|
||||||
return compareInfo
|
return compareInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
{{$reactions := .Reactions.GroupByType}}
|
{{$reactions := .Reactions.GroupByType}}
|
||||||
{{if $reactions}}
|
{{if $reactions}}
|
||||||
<div class="ui attached segment reactions">
|
<div class="ui attached segment reactions">
|
||||||
{{template "repo/issue/view_content/reactions" Dict "ctx" $ "ActionURL" (Printf "%s/comments/%d/reactions" $.root.RepoLink .ID) "Reactions" $reactions }}
|
{{template "repo/issue/view_content/reactions" Dict "ctx" $ "ActionURL" (Printf "%s/comments/%d/reactions" $.root.RepoLink .ID) "Reactions" $reactions "AllowedReactions" $.AllowedReactions }}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if not $.Repository.IsArchived}}
|
{{if not $.Repository.IsArchived}}
|
||||||
<div class="ui right actions">
|
<div class="ui right actions">
|
||||||
{{template "repo/issue/view_content/add_reaction" Dict "ctx" $ "ActionURL" (Printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index) }}
|
{{template "repo/issue/view_content/add_reaction" Dict "ctx" $ "ActionURL" (Printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index) "AllowedReactions" $.AllowedReactions}}
|
||||||
{{template "repo/issue/view_content/context_menu" Dict "ctx" $ "item" .Issue "delete" false "diff" false }}
|
{{template "repo/issue/view_content/context_menu" Dict "ctx" $ "item" .Issue "delete" false "diff" false }}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
{{$reactions := .Issue.Reactions.GroupByType}}
|
{{$reactions := .Issue.Reactions.GroupByType}}
|
||||||
{{if $reactions}}
|
{{if $reactions}}
|
||||||
<div class="ui attached segment reactions">
|
<div class="ui attached segment reactions">
|
||||||
{{template "repo/issue/view_content/reactions" Dict "ctx" $ "ActionURL" (Printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index) "Reactions" $reactions }}
|
{{template "repo/issue/view_content/reactions" Dict "ctx" $ "ActionURL" (Printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index) "Reactions" $reactions "AllowedReactions" $.AllowedReactions}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Issue.Attachments}}
|
{{if .Issue.Attachments}}
|
||||||
|
|
|
@ -7,12 +7,15 @@
|
||||||
<div class="menu has-emoji">
|
<div class="menu has-emoji">
|
||||||
<div class="header">{{ .ctx.i18n.Tr "repo.pick_reaction"}}</div>
|
<div class="header">{{ .ctx.i18n.Tr "repo.pick_reaction"}}</div>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<div class="item" data-content="+1">:+1:</div>
|
{{range $value := .AllowedReactions}}
|
||||||
<div class="item" data-content="-1">:-1:</div>
|
{{if eq $value "hooray"}}
|
||||||
<div class="item" data-content="laugh">:laughing:</div>
|
<div class="item" data-content="hooray">:tada:</div>
|
||||||
<div class="item" data-content="confused">:confused:</div>
|
{{else if eq $value "laugh"}}
|
||||||
<div class="item" data-content="heart">:heart:</div>
|
<div class="item" data-content="laugh">:laughing:</div>
|
||||||
<div class="item" data-content="hooray">:tada:</div>
|
{{else}}
|
||||||
|
<div class="item" data-content="{{$value}}">:{{$value}}:</div>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{template "repo/issue/view_content/add_reaction" Dict "ctx" $ "ActionURL" (Printf "%s/comments/%d/reactions" $.RepoLink .ID) }}
|
{{template "repo/issue/view_content/add_reaction" Dict "ctx" $ "ActionURL" (Printf "%s/comments/%d/reactions" $.RepoLink .ID) "AllowedReactions" $.AllowedReactions}}
|
||||||
{{template "repo/issue/view_content/context_menu" Dict "ctx" $ "item" . "delete" true "diff" false }}
|
{{template "repo/issue/view_content/context_menu" Dict "ctx" $ "item" . "delete" true "diff" false }}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
{{$reactions := .Reactions.GroupByType}}
|
{{$reactions := .Reactions.GroupByType}}
|
||||||
{{if $reactions}}
|
{{if $reactions}}
|
||||||
<div class="ui attached segment reactions">
|
<div class="ui attached segment reactions">
|
||||||
{{template "repo/issue/view_content/reactions" Dict "ctx" $ "ActionURL" (Printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions }}
|
{{template "repo/issue/view_content/reactions" Dict "ctx" $ "ActionURL" (Printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions "AllowedReactions" $.AllowedReactions}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Attachments}}
|
{{if .Attachments}}
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
<a class="ui label basic{{if $value.HasUser $.ctx.SignedUserID}} blue{{end}}{{if not $.ctx.IsSigned}} disabled{{end}} has-emoji" data-title="{{$value.GetFirstUsers}}{{if gt ($value.GetMoreUserCount) 0}} {{ $.ctx.i18n.Tr "repo.reactions_more" $value.GetMoreUserCount}}{{end}}" data-content="{{ $key }}" data-action-url="{{ $.ActionURL }}">
|
<a class="ui label basic{{if $value.HasUser $.ctx.SignedUserID}} blue{{end}}{{if not $.ctx.IsSigned}} disabled{{end}} has-emoji" data-title="{{$value.GetFirstUsers}}{{if gt ($value.GetMoreUserCount) 0}} {{ $.ctx.i18n.Tr "repo.reactions_more" $value.GetMoreUserCount}}{{end}}" data-content="{{ $key }}" data-action-url="{{ $.ActionURL }}">
|
||||||
{{if eq $key "hooray"}}
|
{{if eq $key "hooray"}}
|
||||||
:tada:
|
:tada:
|
||||||
|
{{else if eq $key "laugh"}}
|
||||||
|
:laughing:
|
||||||
{{else}}
|
{{else}}
|
||||||
{{if eq $key "laugh"}}
|
:{{$key}}:
|
||||||
:laughing:
|
|
||||||
{{else}}
|
|
||||||
:{{$key}}:
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
{{end}}
|
||||||
{{len $value}}
|
{{len $value}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{template "repo/issue/view_content/add_reaction" Dict "ctx" $.ctx "ActionURL" .ActionURL }}
|
{{if $.AllowedReactions}}
|
||||||
|
{{template "repo/issue/view_content/add_reaction" Dict "ctx" $.ctx "ActionURL" .ActionURL "AllowedReactions" $.AllowedReactions}}
|
||||||
|
{{end}}
|
||||||
|
|
Loading…
Reference in New Issue