mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-05 18:32:41 +09:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77af0a23c4 | ||
|
|
87bfe02b5b | ||
|
|
9bac656b7d | ||
|
|
ad68c9ccb2 | ||
|
|
8d1cd4d252 | ||
|
|
64eaa2a942 | ||
|
|
489e9162fc |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -4,6 +4,17 @@ This changelog goes through all the changes that have been made in each release
|
|||||||
without substantial changes to our git log; to see the highlights of what has
|
without substantial changes to our git log; to see the highlights of what has
|
||||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||||
|
|
||||||
|
## [1.12.3](https://github.com/go-gitea/gitea/releases/tag/v1.12.3) - 2020-07-28
|
||||||
|
|
||||||
|
* BUGFIXES
|
||||||
|
* Don't change creation date when updating Release (#12343) (#12351)
|
||||||
|
* Show 404 page when release not found (#12328) (#12332)
|
||||||
|
* Fix emoji detection in certain cases (#12320) (#12327)
|
||||||
|
* Reduce emoji size (#12317) (#12327)
|
||||||
|
* Fix double-indirection bug in logging IDs (#12294) (#12308)
|
||||||
|
* Link to pull list page on sidebar when view pr (#12256) (#12263)
|
||||||
|
* Extend Notifications API and return pinned notifications by default (#12164) (#12232)
|
||||||
|
|
||||||
## [1.12.2](https://github.com/go-gitea/gitea/releases/tag/v1.12.2) - 2020-07-11
|
## [1.12.2](https://github.com/go-gitea/gitea/releases/tag/v1.12.2) - 2020-07-11
|
||||||
|
|
||||||
* BUGFIXES
|
* BUGFIXES
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func TestAPINotification(t *testing.T) {
|
|||||||
assert.EqualValues(t, false, apiNL[2].Pinned)
|
assert.EqualValues(t, false, apiNL[2].Pinned)
|
||||||
|
|
||||||
// -- GET /repos/{owner}/{repo}/notifications --
|
// -- GET /repos/{owner}/{repo}/notifications --
|
||||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?token=%s", user2.Name, repo1.Name, token))
|
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?status-types=unread&token=%s", user2.Name, repo1.Name, token))
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiNL)
|
DecodeJSON(t, resp, &apiNL)
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ func TestAPINotification(t *testing.T) {
|
|||||||
assert.True(t, new.New > 0)
|
assert.True(t, new.New > 0)
|
||||||
|
|
||||||
// -- mark notifications as read --
|
// -- mark notifications as read --
|
||||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s", token))
|
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?status-types=unread&token=%s", token))
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiNL)
|
DecodeJSON(t, resp, &apiNL)
|
||||||
assert.Len(t, apiNL, 2)
|
assert.Len(t, apiNL, 2)
|
||||||
@@ -101,7 +101,7 @@ func TestAPINotification(t *testing.T) {
|
|||||||
req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?last_read_at=%s&token=%s", user2.Name, repo1.Name, lastReadAt, token))
|
req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?last_read_at=%s&token=%s", user2.Name, repo1.Name, lastReadAt, token))
|
||||||
resp = session.MakeRequest(t, req, http.StatusResetContent)
|
resp = session.MakeRequest(t, req, http.StatusResetContent)
|
||||||
|
|
||||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s", token))
|
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?status-types=unread&token=%s", token))
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiNL)
|
DecodeJSON(t, resp, &apiNL)
|
||||||
assert.Len(t, apiNL, 1)
|
assert.Len(t, apiNL, 1)
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func TestEventSourceManagerRun(t *testing.T) {
|
|||||||
var apiNL []api.NotificationThread
|
var apiNL []api.NotificationThread
|
||||||
|
|
||||||
// -- mark notifications as read --
|
// -- mark notifications as read --
|
||||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s", token))
|
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?status-types=unread&token=%s", token))
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
DecodeJSON(t, resp, &apiNL)
|
DecodeJSON(t, resp, &apiNL)
|
||||||
@@ -69,7 +69,7 @@ func TestEventSourceManagerRun(t *testing.T) {
|
|||||||
req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?last_read_at=%s&token=%s", user2.Name, repo1.Name, lastReadAt, token))
|
req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?last_read_at=%s&token=%s", user2.Name, repo1.Name, lastReadAt, token))
|
||||||
resp = session.MakeRequest(t, req, http.StatusResetContent)
|
resp = session.MakeRequest(t, req, http.StatusResetContent)
|
||||||
|
|
||||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s", token))
|
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s&status-types=unread", token))
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiNL)
|
DecodeJSON(t, resp, &apiNL)
|
||||||
assert.Len(t, apiNL, 1)
|
assert.Len(t, apiNL, 1)
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ type FindNotificationOptions struct {
|
|||||||
UserID int64
|
UserID int64
|
||||||
RepoID int64
|
RepoID int64
|
||||||
IssueID int64
|
IssueID int64
|
||||||
Status NotificationStatus
|
Status []NotificationStatus
|
||||||
UpdatedAfterUnix int64
|
UpdatedAfterUnix int64
|
||||||
UpdatedBeforeUnix int64
|
UpdatedBeforeUnix int64
|
||||||
}
|
}
|
||||||
@@ -89,8 +89,8 @@ func (opts *FindNotificationOptions) ToCond() builder.Cond {
|
|||||||
if opts.IssueID != 0 {
|
if opts.IssueID != 0 {
|
||||||
cond = cond.And(builder.Eq{"notification.issue_id": opts.IssueID})
|
cond = cond.And(builder.Eq{"notification.issue_id": opts.IssueID})
|
||||||
}
|
}
|
||||||
if opts.Status != 0 {
|
if len(opts.Status) > 0 {
|
||||||
cond = cond.And(builder.Eq{"notification.status": opts.Status})
|
cond = cond.And(builder.In("notification.status", opts.Status))
|
||||||
}
|
}
|
||||||
if opts.UpdatedAfterUnix != 0 {
|
if opts.UpdatedAfterUnix != 0 {
|
||||||
cond = cond.And(builder.Gte{"notification.updated_unix": opts.UpdatedAfterUnix})
|
cond = cond.And(builder.Gte{"notification.updated_unix": opts.UpdatedAfterUnix})
|
||||||
|
|||||||
@@ -130,6 +130,8 @@ func ReplaceAliases(s string) string {
|
|||||||
// FindEmojiSubmatchIndex returns index pair of longest emoji in a string
|
// FindEmojiSubmatchIndex returns index pair of longest emoji in a string
|
||||||
func FindEmojiSubmatchIndex(s string) []int {
|
func FindEmojiSubmatchIndex(s string) []int {
|
||||||
loadMap()
|
loadMap()
|
||||||
|
found := make(map[int]int)
|
||||||
|
keys := make([]int, 0)
|
||||||
|
|
||||||
//see if there are any emoji in string before looking for position of specific ones
|
//see if there are any emoji in string before looking for position of specific ones
|
||||||
//no performance difference when there is a match but 10x faster when there are not
|
//no performance difference when there is a match but 10x faster when there are not
|
||||||
@@ -137,11 +139,26 @@ func FindEmojiSubmatchIndex(s string) []int {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get index of first emoji occurrence while also checking for longest combination
|
||||||
for j := range GemojiData {
|
for j := range GemojiData {
|
||||||
i := strings.Index(s, GemojiData[j].Emoji)
|
i := strings.Index(s, GemojiData[j].Emoji)
|
||||||
if i != -1 {
|
if i != -1 {
|
||||||
return []int{i, i + len(GemojiData[j].Emoji)}
|
if _, ok := found[i]; !ok {
|
||||||
|
if len(keys) == 0 || i < keys[0] {
|
||||||
|
found[i] = j
|
||||||
|
keys = []int{i}
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(keys) > 0 {
|
||||||
|
index := keys[0]
|
||||||
|
return []int{index, index + len(GemojiData[found[index]].Emoji)}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ func NewColoredValueBytes(value interface{}, colorBytes *[]byte) *ColoredValue {
|
|||||||
// The Value will be colored with FgCyan
|
// The Value will be colored with FgCyan
|
||||||
// If a ColoredValue is provided it is not changed
|
// If a ColoredValue is provided it is not changed
|
||||||
func NewColoredIDValue(value interface{}) *ColoredValue {
|
func NewColoredIDValue(value interface{}) *ColoredValue {
|
||||||
return NewColoredValueBytes(&value, &fgCyanBytes)
|
return NewColoredValueBytes(value, &fgCyanBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format will format the provided value and protect against ANSI color spoofing within the value
|
// Format will format the provided value and protect against ANSI color spoofing within the value
|
||||||
|
|||||||
@@ -266,6 +266,10 @@ func TestRender_emoji(t *testing.T) {
|
|||||||
test(
|
test(
|
||||||
"Some text with 😄😄 2 emoji next to each other",
|
"Some text with 😄😄 2 emoji next to each other",
|
||||||
`<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span><span class="emoji" aria-label="grinning face with smiling eyes">😄</span> 2 emoji next to each other</p>`)
|
`<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span><span class="emoji" aria-label="grinning face with smiling eyes">😄</span> 2 emoji next to each other</p>`)
|
||||||
|
test(
|
||||||
|
"😎🤪🔐🤑❓",
|
||||||
|
`<p><span class="emoji" aria-label="smiling face with sunglasses">😎</span><span class="emoji" aria-label="zany face">🤪</span><span class="emoji" aria-label="locked with key">🔐</span><span class="emoji" aria-label="money-mouth face">🤑</span><span class="emoji" aria-label="question mark">❓</span></p>`)
|
||||||
|
|
||||||
// should match nothing
|
// should match nothing
|
||||||
test(
|
test(
|
||||||
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
|
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
|
||||||
|
|||||||
@@ -11,9 +11,37 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func statusStringToNotificationStatus(status string) models.NotificationStatus {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(status)) {
|
||||||
|
case "unread":
|
||||||
|
return models.NotificationStatusUnread
|
||||||
|
case "read":
|
||||||
|
return models.NotificationStatusRead
|
||||||
|
case "pinned":
|
||||||
|
return models.NotificationStatusPinned
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func statusStringsToNotificationStatuses(statuses []string, defaultStatuses []string) []models.NotificationStatus {
|
||||||
|
if len(statuses) == 0 {
|
||||||
|
statuses = defaultStatuses
|
||||||
|
}
|
||||||
|
results := make([]models.NotificationStatus, 0, len(statuses))
|
||||||
|
for _, status := range statuses {
|
||||||
|
notificationStatus := statusStringToNotificationStatus(status)
|
||||||
|
if notificationStatus > 0 {
|
||||||
|
results = append(results, notificationStatus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
// ListRepoNotifications list users's notification threads on a specific repo
|
// ListRepoNotifications list users's notification threads on a specific repo
|
||||||
func ListRepoNotifications(ctx *context.APIContext) {
|
func ListRepoNotifications(ctx *context.APIContext) {
|
||||||
// swagger:operation GET /repos/{owner}/{repo}/notifications notification notifyGetRepoList
|
// swagger:operation GET /repos/{owner}/{repo}/notifications notification notifyGetRepoList
|
||||||
@@ -39,6 +67,14 @@ func ListRepoNotifications(ctx *context.APIContext) {
|
|||||||
// description: If true, show notifications marked as read. Default value is false
|
// description: If true, show notifications marked as read. Default value is false
|
||||||
// type: string
|
// type: string
|
||||||
// required: false
|
// required: false
|
||||||
|
// - name: status-types
|
||||||
|
// in: query
|
||||||
|
// description: "Show notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread & pinned"
|
||||||
|
// type: array
|
||||||
|
// collectionFormat: multi
|
||||||
|
// items:
|
||||||
|
// type: string
|
||||||
|
// required: false
|
||||||
// - name: since
|
// - name: since
|
||||||
// in: query
|
// in: query
|
||||||
// description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format
|
// description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format
|
||||||
@@ -75,9 +111,10 @@ func ListRepoNotifications(ctx *context.APIContext) {
|
|||||||
UpdatedBeforeUnix: before,
|
UpdatedBeforeUnix: before,
|
||||||
UpdatedAfterUnix: since,
|
UpdatedAfterUnix: since,
|
||||||
}
|
}
|
||||||
qAll := strings.Trim(ctx.Query("all"), " ")
|
|
||||||
if qAll != "true" {
|
if !ctx.QueryBool("all") {
|
||||||
opts.Status = models.NotificationStatusUnread
|
statuses := ctx.QueryStrings("status-types")
|
||||||
|
opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread", "pinned"})
|
||||||
}
|
}
|
||||||
nl, err := models.GetNotifications(opts)
|
nl, err := models.GetNotifications(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -97,7 +134,7 @@ func ListRepoNotifications(ctx *context.APIContext) {
|
|||||||
func ReadRepoNotifications(ctx *context.APIContext) {
|
func ReadRepoNotifications(ctx *context.APIContext) {
|
||||||
// swagger:operation PUT /repos/{owner}/{repo}/notifications notification notifyReadRepoList
|
// swagger:operation PUT /repos/{owner}/{repo}/notifications notification notifyReadRepoList
|
||||||
// ---
|
// ---
|
||||||
// summary: Mark notification threads as read on a specific repo
|
// summary: Mark notification threads as read, pinned or unread on a specific repo
|
||||||
// consumes:
|
// consumes:
|
||||||
// - application/json
|
// - application/json
|
||||||
// produces:
|
// produces:
|
||||||
@@ -113,6 +150,24 @@ func ReadRepoNotifications(ctx *context.APIContext) {
|
|||||||
// description: name of the repo
|
// description: name of the repo
|
||||||
// type: string
|
// type: string
|
||||||
// required: true
|
// required: true
|
||||||
|
// - name: all
|
||||||
|
// in: query
|
||||||
|
// description: If true, mark all notifications on this repo. Default value is false
|
||||||
|
// type: string
|
||||||
|
// required: false
|
||||||
|
// - name: status-types
|
||||||
|
// in: query
|
||||||
|
// description: "Mark notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread."
|
||||||
|
// type: array
|
||||||
|
// collectionFormat: multi
|
||||||
|
// items:
|
||||||
|
// type: string
|
||||||
|
// required: false
|
||||||
|
// - name: to-status
|
||||||
|
// in: query
|
||||||
|
// description: Status to mark notifications as. Defaults to read.
|
||||||
|
// type: string
|
||||||
|
// required: false
|
||||||
// - name: last_read_at
|
// - name: last_read_at
|
||||||
// in: query
|
// in: query
|
||||||
// description: Describes the last point that notifications were checked. Anything updated since this time will not be updated.
|
// description: Describes the last point that notifications were checked. Anything updated since this time will not be updated.
|
||||||
@@ -135,11 +190,17 @@ func ReadRepoNotifications(ctx *context.APIContext) {
|
|||||||
lastRead = tmpLastRead.Unix()
|
lastRead = tmpLastRead.Unix()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := models.FindNotificationOptions{
|
opts := models.FindNotificationOptions{
|
||||||
UserID: ctx.User.ID,
|
UserID: ctx.User.ID,
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
UpdatedBeforeUnix: lastRead,
|
UpdatedBeforeUnix: lastRead,
|
||||||
Status: models.NotificationStatusUnread,
|
}
|
||||||
|
|
||||||
|
if !ctx.QueryBool("all") {
|
||||||
|
statuses := ctx.QueryStrings("status-types")
|
||||||
|
opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread"})
|
||||||
|
log.Error("%v", opts.Status)
|
||||||
}
|
}
|
||||||
nl, err := models.GetNotifications(opts)
|
nl, err := models.GetNotifications(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -147,8 +208,13 @@ func ReadRepoNotifications(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
targetStatus := statusStringToNotificationStatus(ctx.Query("to-status"))
|
||||||
|
if targetStatus == 0 {
|
||||||
|
targetStatus = models.NotificationStatusRead
|
||||||
|
}
|
||||||
|
|
||||||
for _, n := range nl {
|
for _, n := range nl {
|
||||||
err := models.SetNotificationStatus(n.ID, ctx.User, models.NotificationStatusRead)
|
err := models.SetNotificationStatus(n.ID, ctx.User, targetStatus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.InternalServerError(err)
|
ctx.InternalServerError(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -62,6 +62,12 @@ func ReadThread(ctx *context.APIContext) {
|
|||||||
// description: id of notification thread
|
// description: id of notification thread
|
||||||
// type: string
|
// type: string
|
||||||
// required: true
|
// required: true
|
||||||
|
// - name: to-status
|
||||||
|
// in: query
|
||||||
|
// description: Status to mark notifications as
|
||||||
|
// type: string
|
||||||
|
// default: read
|
||||||
|
// required: false
|
||||||
// responses:
|
// responses:
|
||||||
// "205":
|
// "205":
|
||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
@@ -75,7 +81,12 @@ func ReadThread(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := models.SetNotificationStatus(n.ID, ctx.User, models.NotificationStatusRead)
|
targetStatus := statusStringToNotificationStatus(ctx.Query("to-status"))
|
||||||
|
if targetStatus == 0 {
|
||||||
|
targetStatus = models.NotificationStatusRead
|
||||||
|
}
|
||||||
|
|
||||||
|
err := models.SetNotificationStatus(n.ID, ctx.User, targetStatus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.InternalServerError(err)
|
ctx.InternalServerError(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -29,6 +29,14 @@ func ListNotifications(ctx *context.APIContext) {
|
|||||||
// description: If true, show notifications marked as read. Default value is false
|
// description: If true, show notifications marked as read. Default value is false
|
||||||
// type: string
|
// type: string
|
||||||
// required: false
|
// required: false
|
||||||
|
// - name: status-types
|
||||||
|
// in: query
|
||||||
|
// description: "Show notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread & pinned."
|
||||||
|
// type: array
|
||||||
|
// collectionFormat: multi
|
||||||
|
// items:
|
||||||
|
// type: string
|
||||||
|
// required: false
|
||||||
// - name: since
|
// - name: since
|
||||||
// in: query
|
// in: query
|
||||||
// description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format
|
// description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format
|
||||||
@@ -64,9 +72,9 @@ func ListNotifications(ctx *context.APIContext) {
|
|||||||
UpdatedBeforeUnix: before,
|
UpdatedBeforeUnix: before,
|
||||||
UpdatedAfterUnix: since,
|
UpdatedAfterUnix: since,
|
||||||
}
|
}
|
||||||
qAll := strings.Trim(ctx.Query("all"), " ")
|
if !ctx.QueryBool("all") {
|
||||||
if qAll != "true" {
|
statuses := ctx.QueryStrings("status-types")
|
||||||
opts.Status = models.NotificationStatusUnread
|
opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread", "pinned"})
|
||||||
}
|
}
|
||||||
nl, err := models.GetNotifications(opts)
|
nl, err := models.GetNotifications(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -82,11 +90,11 @@ func ListNotifications(ctx *context.APIContext) {
|
|||||||
ctx.JSON(http.StatusOK, nl.APIFormat())
|
ctx.JSON(http.StatusOK, nl.APIFormat())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadNotifications mark notification threads as read
|
// ReadNotifications mark notification threads as read, unread, or pinned
|
||||||
func ReadNotifications(ctx *context.APIContext) {
|
func ReadNotifications(ctx *context.APIContext) {
|
||||||
// swagger:operation PUT /notifications notification notifyReadList
|
// swagger:operation PUT /notifications notification notifyReadList
|
||||||
// ---
|
// ---
|
||||||
// summary: Mark notification threads as read
|
// summary: Mark notification threads as read, pinned or unread
|
||||||
// consumes:
|
// consumes:
|
||||||
// - application/json
|
// - application/json
|
||||||
// produces:
|
// produces:
|
||||||
@@ -98,6 +106,24 @@ func ReadNotifications(ctx *context.APIContext) {
|
|||||||
// type: string
|
// type: string
|
||||||
// format: date-time
|
// format: date-time
|
||||||
// required: false
|
// required: false
|
||||||
|
// - name: all
|
||||||
|
// in: query
|
||||||
|
// description: If true, mark all notifications on this repo. Default value is false
|
||||||
|
// type: string
|
||||||
|
// required: false
|
||||||
|
// - name: status-types
|
||||||
|
// in: query
|
||||||
|
// description: "Mark notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread."
|
||||||
|
// type: array
|
||||||
|
// collectionFormat: multi
|
||||||
|
// items:
|
||||||
|
// type: string
|
||||||
|
// required: false
|
||||||
|
// - name: to-status
|
||||||
|
// in: query
|
||||||
|
// description: Status to mark notifications as, Defaults to read.
|
||||||
|
// type: string
|
||||||
|
// required: false
|
||||||
// responses:
|
// responses:
|
||||||
// "205":
|
// "205":
|
||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
@@ -117,7 +143,10 @@ func ReadNotifications(ctx *context.APIContext) {
|
|||||||
opts := models.FindNotificationOptions{
|
opts := models.FindNotificationOptions{
|
||||||
UserID: ctx.User.ID,
|
UserID: ctx.User.ID,
|
||||||
UpdatedBeforeUnix: lastRead,
|
UpdatedBeforeUnix: lastRead,
|
||||||
Status: models.NotificationStatusUnread,
|
}
|
||||||
|
if !ctx.QueryBool("all") {
|
||||||
|
statuses := ctx.QueryStrings("status-types")
|
||||||
|
opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread"})
|
||||||
}
|
}
|
||||||
nl, err := models.GetNotifications(opts)
|
nl, err := models.GetNotifications(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -125,8 +154,13 @@ func ReadNotifications(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
targetStatus := statusStringToNotificationStatus(ctx.Query("to-status"))
|
||||||
|
if targetStatus == 0 {
|
||||||
|
targetStatus = models.NotificationStatusRead
|
||||||
|
}
|
||||||
|
|
||||||
for _, n := range nl {
|
for _, n := range nl {
|
||||||
err := models.SetNotificationStatus(n.ID, ctx.User, models.NotificationStatusRead)
|
err := models.SetNotificationStatus(n.ID, ctx.User, targetStatus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.InternalServerError(err)
|
ctx.InternalServerError(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -134,6 +134,10 @@ func SingleRelease(ctx *context.Context) {
|
|||||||
|
|
||||||
release, err := models.GetRelease(ctx.Repo.Repository.ID, ctx.Params("tag"))
|
release, err := models.GetRelease(ctx.Repo.Repository.ID, ctx.Params("tag"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if models.IsErrReleaseNotExist(err) {
|
||||||
|
ctx.NotFound("GetRelease", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
ctx.ServerError("GetReleasesByRepoID", err)
|
ctx.ServerError("GetReleasesByRepoID", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ func createTag(gitRepo *git.Repository, rel *models.Release) error {
|
|||||||
rel.Publisher, rel.Repo, git.TagPrefix+rel.TagName,
|
rel.Publisher, rel.Repo, git.TagPrefix+rel.TagName,
|
||||||
git.EmptySHA, commit.ID.String(), repository.NewPushCommits())
|
git.EmptySHA, commit.ID.String(), repository.NewPushCommits())
|
||||||
notification.NotifyCreateRef(rel.Publisher, rel.Repo, "tag", git.TagPrefix+rel.TagName)
|
notification.NotifyCreateRef(rel.Publisher, rel.Repo, "tag", git.TagPrefix+rel.TagName)
|
||||||
|
rel.CreatedUnix = timeutil.TimeStampNow()
|
||||||
}
|
}
|
||||||
commit, err := gitRepo.GetTagCommit(rel.TagName)
|
commit, err := gitRepo.GetTagCommit(rel.TagName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -53,7 +54,6 @@ func createTag(gitRepo *git.Repository, rel *models.Release) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rel.Sha1 = commit.ID.String()
|
rel.Sha1 = commit.ID.String()
|
||||||
rel.CreatedUnix = timeutil.TimeStampNow()
|
|
||||||
rel.NumCommits, err = commit.CommitsCount()
|
rel.NumCommits, err = commit.CommitsCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("CommitsCount: %v", err)
|
return fmt.Errorf("CommitsCount: %v", err)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package release
|
|||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
@@ -101,3 +102,153 @@ func TestRelease_Create(t *testing.T) {
|
|||||||
IsTag: true,
|
IsTag: true,
|
||||||
}, nil))
|
}, nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRelease_Update(t *testing.T) {
|
||||||
|
assert.NoError(t, models.PrepareTestDatabase())
|
||||||
|
|
||||||
|
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
|
||||||
|
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
|
||||||
|
repoPath := models.RepoPath(user.Name, repo.Name)
|
||||||
|
|
||||||
|
gitRepo, err := git.OpenRepository(repoPath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer gitRepo.Close()
|
||||||
|
|
||||||
|
// Test a changed release
|
||||||
|
assert.NoError(t, CreateRelease(gitRepo, &models.Release{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
PublisherID: user.ID,
|
||||||
|
TagName: "v1.1.1",
|
||||||
|
Target: "master",
|
||||||
|
Title: "v1.1.1 is released",
|
||||||
|
Note: "v1.1.1 is released",
|
||||||
|
IsDraft: false,
|
||||||
|
IsPrerelease: false,
|
||||||
|
IsTag: false,
|
||||||
|
}, nil))
|
||||||
|
release, err := models.GetRelease(repo.ID, "v1.1.1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
releaseCreatedUnix := release.CreatedUnix
|
||||||
|
time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp
|
||||||
|
release.Note = "Changed note"
|
||||||
|
assert.NoError(t, UpdateRelease(user, gitRepo, release, nil))
|
||||||
|
release, err = models.GetReleaseByID(release.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, int64(releaseCreatedUnix), int64(release.CreatedUnix))
|
||||||
|
|
||||||
|
// Test a changed draft
|
||||||
|
assert.NoError(t, CreateRelease(gitRepo, &models.Release{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
PublisherID: user.ID,
|
||||||
|
TagName: "v1.2.1",
|
||||||
|
Target: "65f1bf2",
|
||||||
|
Title: "v1.2.1 is draft",
|
||||||
|
Note: "v1.2.1 is draft",
|
||||||
|
IsDraft: true,
|
||||||
|
IsPrerelease: false,
|
||||||
|
IsTag: false,
|
||||||
|
}, nil))
|
||||||
|
release, err = models.GetRelease(repo.ID, "v1.2.1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
releaseCreatedUnix = release.CreatedUnix
|
||||||
|
time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp
|
||||||
|
release.Title = "Changed title"
|
||||||
|
assert.NoError(t, UpdateRelease(user, gitRepo, release, nil))
|
||||||
|
release, err = models.GetReleaseByID(release.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Less(t, int64(releaseCreatedUnix), int64(release.CreatedUnix))
|
||||||
|
|
||||||
|
// Test a changed pre-release
|
||||||
|
assert.NoError(t, CreateRelease(gitRepo, &models.Release{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
PublisherID: user.ID,
|
||||||
|
TagName: "v1.3.1",
|
||||||
|
Target: "65f1bf2",
|
||||||
|
Title: "v1.3.1 is pre-released",
|
||||||
|
Note: "v1.3.1 is pre-released",
|
||||||
|
IsDraft: false,
|
||||||
|
IsPrerelease: true,
|
||||||
|
IsTag: false,
|
||||||
|
}, nil))
|
||||||
|
release, err = models.GetRelease(repo.ID, "v1.3.1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
releaseCreatedUnix = release.CreatedUnix
|
||||||
|
time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp
|
||||||
|
release.Title = "Changed title"
|
||||||
|
release.Note = "Changed note"
|
||||||
|
assert.NoError(t, UpdateRelease(user, gitRepo, release, nil))
|
||||||
|
release, err = models.GetReleaseByID(release.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, int64(releaseCreatedUnix), int64(release.CreatedUnix))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRelease_createTag(t *testing.T) {
|
||||||
|
assert.NoError(t, models.PrepareTestDatabase())
|
||||||
|
|
||||||
|
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
|
||||||
|
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
|
||||||
|
repoPath := models.RepoPath(user.Name, repo.Name)
|
||||||
|
|
||||||
|
gitRepo, err := git.OpenRepository(repoPath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer gitRepo.Close()
|
||||||
|
|
||||||
|
// Test a changed release
|
||||||
|
release := &models.Release{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
PublisherID: user.ID,
|
||||||
|
TagName: "v2.1.1",
|
||||||
|
Target: "master",
|
||||||
|
Title: "v2.1.1 is released",
|
||||||
|
Note: "v2.1.1 is released",
|
||||||
|
IsDraft: false,
|
||||||
|
IsPrerelease: false,
|
||||||
|
IsTag: false,
|
||||||
|
}
|
||||||
|
assert.NoError(t, createTag(gitRepo, release))
|
||||||
|
assert.NotEmpty(t, release.CreatedUnix)
|
||||||
|
releaseCreatedUnix := release.CreatedUnix
|
||||||
|
time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp
|
||||||
|
release.Note = "Changed note"
|
||||||
|
assert.NoError(t, createTag(gitRepo, release))
|
||||||
|
assert.Equal(t, int64(releaseCreatedUnix), int64(release.CreatedUnix))
|
||||||
|
|
||||||
|
// Test a changed draft
|
||||||
|
release = &models.Release{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
PublisherID: user.ID,
|
||||||
|
TagName: "v2.2.1",
|
||||||
|
Target: "65f1bf2",
|
||||||
|
Title: "v2.2.1 is draft",
|
||||||
|
Note: "v2.2.1 is draft",
|
||||||
|
IsDraft: true,
|
||||||
|
IsPrerelease: false,
|
||||||
|
IsTag: false,
|
||||||
|
}
|
||||||
|
assert.NoError(t, createTag(gitRepo, release))
|
||||||
|
releaseCreatedUnix = release.CreatedUnix
|
||||||
|
time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp
|
||||||
|
release.Title = "Changed title"
|
||||||
|
assert.NoError(t, createTag(gitRepo, release))
|
||||||
|
assert.Less(t, int64(releaseCreatedUnix), int64(release.CreatedUnix))
|
||||||
|
|
||||||
|
// Test a changed pre-release
|
||||||
|
release = &models.Release{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
PublisherID: user.ID,
|
||||||
|
TagName: "v2.3.1",
|
||||||
|
Target: "65f1bf2",
|
||||||
|
Title: "v2.3.1 is pre-released",
|
||||||
|
Note: "v2.3.1 is pre-released",
|
||||||
|
IsDraft: false,
|
||||||
|
IsPrerelease: true,
|
||||||
|
IsTag: false,
|
||||||
|
}
|
||||||
|
assert.NoError(t, createTag(gitRepo, release))
|
||||||
|
releaseCreatedUnix = release.CreatedUnix
|
||||||
|
time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp
|
||||||
|
release.Title = "Changed title"
|
||||||
|
release.Note = "Changed note"
|
||||||
|
assert.NoError(t, createTag(gitRepo, release))
|
||||||
|
assert.Equal(t, int64(releaseCreatedUnix), int64(release.CreatedUnix))
|
||||||
|
}
|
||||||
|
|||||||
@@ -128,12 +128,12 @@
|
|||||||
<span class="no-select item {{if .HasSelectedLabel}}hide{{end}}">{{.i18n.Tr "repo.issues.new.no_label"}}</span>
|
<span class="no-select item {{if .HasSelectedLabel}}hide{{end}}">{{.i18n.Tr "repo.issues.new.no_label"}}</span>
|
||||||
{{range .Labels}}
|
{{range .Labels}}
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<a class="ui label {{if not .IsChecked}}hide{{end}}" id="label_{{.ID}}" href="{{$.RepoLink}}/issues?labels={{.ID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}" title="{{.Description | RenderEmojiPlain}}">{{.Name | RenderEmoji}}</a>
|
<a class="ui label {{if not .IsChecked}}hide{{end}}" id="label_{{.ID}}" href="{{$.RepoLink}}/{{if $.Issue.IsPull}}pulls{{else}}issues{{end}}?labels={{.ID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}" title="{{.Description | RenderEmojiPlain}}">{{.Name | RenderEmoji}}</a>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{range .OrgLabels}}
|
{{range .OrgLabels}}
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<a class="ui label {{if not .IsChecked}}hide{{end}}" id="label_{{.ID}}" href="{{$.RepoLink}}/issues?labels={{.ID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}" title="{{.Description | RenderEmojiPlain}}">{{.Name | RenderEmoji}}</a>
|
<a class="ui label {{if not .IsChecked}}hide{{end}}" id="label_{{.ID}}" href="{{$.RepoLink}}/{{if $.Issue.IsPull}}pulls{{else}}issues{{end}}?labels={{.ID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}" title="{{.Description | RenderEmojiPlain}}">{{.Name | RenderEmoji}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -238,7 +238,7 @@
|
|||||||
<div class="selected">
|
<div class="selected">
|
||||||
{{range .Issue.Assignees}}
|
{{range .Issue.Assignees}}
|
||||||
<div class="item" style="margin-bottom: 10px;">
|
<div class="item" style="margin-bottom: 10px;">
|
||||||
<a href="{{$.RepoLink}}/issues?assignee={{.ID}}"><img class="ui avatar image" src="{{.RelAvatarLink}}"> {{.GetDisplayName}}</a>
|
<a href="{{$.RepoLink}}/{{if $.Issue.IsPull}}pulls{{else}}issues{{end}}?assignee={{.ID}}"><img class="ui avatar image" src="{{.RelAvatarLink}}"> {{.GetDisplayName}}</a>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -459,6 +459,16 @@
|
|||||||
"name": "all",
|
"name": "all",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"collectionFormat": "multi",
|
||||||
|
"description": "Show notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread \u0026 pinned.",
|
||||||
|
"name": "status-types",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
@@ -502,7 +512,7 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"notification"
|
"notification"
|
||||||
],
|
],
|
||||||
"summary": "Mark notification threads as read",
|
"summary": "Mark notification threads as read, pinned or unread",
|
||||||
"operationId": "notifyReadList",
|
"operationId": "notifyReadList",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -511,6 +521,28 @@
|
|||||||
"description": "Describes the last point that notifications were checked. Anything updated since this time will not be updated.",
|
"description": "Describes the last point that notifications were checked. Anything updated since this time will not be updated.",
|
||||||
"name": "last_read_at",
|
"name": "last_read_at",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "If true, mark all notifications on this repo. Default value is false",
|
||||||
|
"name": "all",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"collectionFormat": "multi",
|
||||||
|
"description": "Mark notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread.",
|
||||||
|
"name": "status-types",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Status to mark notifications as, Defaults to read.",
|
||||||
|
"name": "to-status",
|
||||||
|
"in": "query"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@@ -587,6 +619,13 @@
|
|||||||
"name": "id",
|
"name": "id",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"default": "read",
|
||||||
|
"description": "Status to mark notifications as",
|
||||||
|
"name": "to-status",
|
||||||
|
"in": "query"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@@ -6290,6 +6329,16 @@
|
|||||||
"name": "all",
|
"name": "all",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"collectionFormat": "multi",
|
||||||
|
"description": "Show notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread \u0026 pinned",
|
||||||
|
"name": "status-types",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
@@ -6333,7 +6382,7 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"notification"
|
"notification"
|
||||||
],
|
],
|
||||||
"summary": "Mark notification threads as read on a specific repo",
|
"summary": "Mark notification threads as read, pinned or unread on a specific repo",
|
||||||
"operationId": "notifyReadRepoList",
|
"operationId": "notifyReadRepoList",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -6350,6 +6399,28 @@
|
|||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "If true, mark all notifications on this repo. Default value is false",
|
||||||
|
"name": "all",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"collectionFormat": "multi",
|
||||||
|
"description": "Mark notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread.",
|
||||||
|
"name": "status-types",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Status to mark notifications as. Defaults to read.",
|
||||||
|
"name": "to-status",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
|
|||||||
@@ -1271,33 +1271,18 @@ i.icon.centerlock {
|
|||||||
|
|
||||||
.emoji,
|
.emoji,
|
||||||
.reaction {
|
.reaction {
|
||||||
font-size: 1.5em;
|
font-size: 1.25em;
|
||||||
line-height: 1.2;
|
line-height: 1;
|
||||||
font-style: normal !important;
|
font-style: normal !important;
|
||||||
font-weight: normal !important;
|
font-weight: normal !important;
|
||||||
vertical-align: middle;
|
vertical-align: -.075em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#issue-title > .emoji {
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.commit-summary > .emoji {
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label > .emoji {
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown .emoji {
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
.emoji img,
|
.emoji img,
|
||||||
.reaction img {
|
.reaction img {
|
||||||
border-width: 0 !important;
|
border-width: 0 !important;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
width: 1em !important;
|
width: 1em !important;
|
||||||
height: 1em !important;
|
height: 1em !important;
|
||||||
vertical-align: middle !important;
|
vertical-align: -.15em;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2246,7 +2246,7 @@
|
|||||||
.select-reaction {
|
.select-reaction {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: .5rem;
|
padding: 0 .5rem;
|
||||||
|
|
||||||
&:not(.active) a {
|
&:not(.active) a {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
Reference in New Issue
Block a user