Release (#440)
* Feat: Enable sorting discussions by original comment (#422) * Feat: Improve popup UX (#426) * Feat: Automatically update MR summary details (#427) * Feat: Show update progress in winbar (#432) * Feat: Abbreviate winbar (#439) * Fix: Note Creation Bug (#441) * Fix: Checking whether comment can be created (#434) * Fix: Syntax in discussion tree (#433) * fix: improve indication of resolved threads and drafts (#442) * Docs: Various minor improvements (#445) --------- Co-authored-by: Jakub F. Bortlík <jakub.bortlik@proton.me>
This commit is contained in:
committed by
GitHub
parent
be027331e1
commit
495e64c8bc
@@ -4,6 +4,7 @@ import (
|
||||
"net/http"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"encoding/json"
|
||||
|
||||
@@ -19,8 +20,16 @@ func Contains[T comparable](elems []T, v T) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type SortBy string
|
||||
|
||||
const (
|
||||
SortByLatestReply SortBy = "latest_reply"
|
||||
SortByOriginalComment SortBy = "original_comment"
|
||||
)
|
||||
|
||||
type DiscussionsRequest struct {
|
||||
Blacklist []string `json:"blacklist" validate:"required"`
|
||||
SortBy SortBy `json:"sort_by"`
|
||||
}
|
||||
|
||||
type DiscussionsResponse struct {
|
||||
@@ -30,20 +39,30 @@ type DiscussionsResponse struct {
|
||||
Emojis map[int][]*gitlab.AwardEmoji `json:"emojis"`
|
||||
}
|
||||
|
||||
type SortableDiscussions []*gitlab.Discussion
|
||||
|
||||
func (n SortableDiscussions) Len() int {
|
||||
return len(n)
|
||||
type SortableDiscussions struct {
|
||||
Discussions []*gitlab.Discussion
|
||||
SortBy SortBy
|
||||
}
|
||||
|
||||
func (d SortableDiscussions) Less(i int, j int) bool {
|
||||
iTime := d[i].Notes[len(d[i].Notes)-1].CreatedAt
|
||||
jTime := d[j].Notes[len(d[j].Notes)-1].CreatedAt
|
||||
return iTime.After(*jTime)
|
||||
func (d SortableDiscussions) Len() int {
|
||||
return len(d.Discussions)
|
||||
}
|
||||
|
||||
func (n SortableDiscussions) Swap(i, j int) {
|
||||
n[i], n[j] = n[j], n[i]
|
||||
func (d SortableDiscussions) Less(i, j int) bool {
|
||||
var iTime, jTime *time.Time
|
||||
if d.SortBy == SortByOriginalComment {
|
||||
iTime = d.Discussions[i].Notes[0].CreatedAt
|
||||
jTime = d.Discussions[j].Notes[0].CreatedAt
|
||||
return iTime.Before(*jTime)
|
||||
} else { // SortByLatestReply
|
||||
iTime = d.Discussions[i].Notes[len(d.Discussions[i].Notes)-1].CreatedAt
|
||||
jTime = d.Discussions[j].Notes[len(d.Discussions[j].Notes)-1].CreatedAt
|
||||
return iTime.After(*jTime)
|
||||
}
|
||||
}
|
||||
|
||||
func (d SortableDiscussions) Swap(i, j int) {
|
||||
d.Discussions[i], d.Discussions[j] = d.Discussions[j], d.Discussions[i]
|
||||
}
|
||||
|
||||
type DiscussionsLister interface {
|
||||
@@ -115,8 +134,14 @@ func (a discussionsListerService) ServeHTTP(w http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
|
||||
sortedLinkedDiscussions := SortableDiscussions(linkedDiscussions)
|
||||
sortedUnlinkedDiscussions := SortableDiscussions(unlinkedDiscussions)
|
||||
sortedLinkedDiscussions := SortableDiscussions{
|
||||
Discussions: linkedDiscussions,
|
||||
SortBy: request.SortBy,
|
||||
}
|
||||
sortedUnlinkedDiscussions := SortableDiscussions{
|
||||
Discussions: unlinkedDiscussions,
|
||||
SortBy: request.SortBy,
|
||||
}
|
||||
|
||||
sort.Sort(sortedLinkedDiscussions)
|
||||
sort.Sort(sortedUnlinkedDiscussions)
|
||||
|
||||
@@ -21,8 +21,14 @@ func (f fakeDiscussionsLister) ListMergeRequestDiscussions(pid interface{}, merg
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
now := time.Now()
|
||||
newer := now.Add(time.Second * 100)
|
||||
|
||||
timePointers := make([]*time.Time, 6)
|
||||
timePointers[0] = new(time.Time)
|
||||
*timePointers[0] = time.Now()
|
||||
for i := 1; i < len(timePointers); i++ {
|
||||
timePointers[i] = new(time.Time)
|
||||
*timePointers[i] = timePointers[i-1].Add(time.Second * 100)
|
||||
}
|
||||
|
||||
type Author struct {
|
||||
ID int `json:"id"`
|
||||
@@ -35,8 +41,18 @@ func (f fakeDiscussionsLister) ListMergeRequestDiscussions(pid interface{}, merg
|
||||
}
|
||||
|
||||
testListDiscussionsResponse := []*gitlab.Discussion{
|
||||
{Notes: []*gitlab.Note{{CreatedAt: &now, Type: "DiffNote", Author: Author{Username: "hcramer"}}}},
|
||||
{Notes: []*gitlab.Note{{CreatedAt: &newer, Type: "DiffNote", Author: Author{Username: "hcramer2"}}}},
|
||||
{Notes: []*gitlab.Note{
|
||||
{CreatedAt: timePointers[0], Type: "DiffNote", Author: Author{Username: "hcramer0"}},
|
||||
{CreatedAt: timePointers[4], Type: "DiffNote", Author: Author{Username: "hcramer1"}},
|
||||
}},
|
||||
{Notes: []*gitlab.Note{
|
||||
{CreatedAt: timePointers[2], Type: "DiffNote", Author: Author{Username: "hcramer2"}},
|
||||
{CreatedAt: timePointers[3], Type: "DiffNote", Author: Author{Username: "hcramer3"}},
|
||||
}},
|
||||
{Notes: []*gitlab.Note{
|
||||
{CreatedAt: timePointers[1], Type: "DiffNote", Author: Author{Username: "hcramer4"}},
|
||||
{CreatedAt: timePointers[5], Type: "DiffNote", Author: Author{Username: "hcramer5"}},
|
||||
}},
|
||||
}
|
||||
return testListDiscussionsResponse, resp, err
|
||||
}
|
||||
@@ -66,8 +82,8 @@ func getDiscussionsList(t *testing.T, svc http.Handler, request *http.Request) D
|
||||
}
|
||||
|
||||
func TestListDiscussions(t *testing.T) {
|
||||
t.Run("Returns sorted discussions", func(t *testing.T) {
|
||||
request := makeRequest(t, http.MethodPost, "/mr/discussions/list", DiscussionsRequest{Blacklist: []string{}})
|
||||
t.Run("Returns discussions sorted by latest reply", func(t *testing.T) {
|
||||
request := makeRequest(t, http.MethodPost, "/mr/discussions/list", DiscussionsRequest{Blacklist: []string{}, SortBy: "latest_reply"})
|
||||
svc := middleware(
|
||||
discussionsListerService{testProjectData, fakeDiscussionsLister{}},
|
||||
withMr(testProjectData, fakeMergeRequestLister{}),
|
||||
@@ -76,12 +92,28 @@ func TestListDiscussions(t *testing.T) {
|
||||
)
|
||||
data := getDiscussionsList(t, svc, request)
|
||||
assert(t, data.Message, "Discussions retrieved")
|
||||
assert(t, data.Discussions[0].Notes[0].Author.Username, "hcramer2") /* Sorting applied */
|
||||
assert(t, data.Discussions[1].Notes[0].Author.Username, "hcramer")
|
||||
assert(t, data.Discussions[0].Notes[0].Author.Username, "hcramer4") /* Sorting applied */
|
||||
assert(t, data.Discussions[1].Notes[0].Author.Username, "hcramer0")
|
||||
assert(t, data.Discussions[2].Notes[0].Author.Username, "hcramer2")
|
||||
})
|
||||
|
||||
t.Run("Returns discussions sorted by original comment", func(t *testing.T) {
|
||||
request := makeRequest(t, http.MethodPost, "/mr/discussions/list", DiscussionsRequest{Blacklist: []string{}, SortBy: "original_comment"})
|
||||
svc := middleware(
|
||||
discussionsListerService{testProjectData, fakeDiscussionsLister{}},
|
||||
withMr(testProjectData, fakeMergeRequestLister{}),
|
||||
withPayloadValidation(methodToPayload{http.MethodPost: newPayload[DiscussionsRequest]}),
|
||||
withMethodCheck(http.MethodPost),
|
||||
)
|
||||
data := getDiscussionsList(t, svc, request)
|
||||
assert(t, data.Message, "Discussions retrieved")
|
||||
assert(t, data.Discussions[0].Notes[0].Author.Username, "hcramer0") /* Sorting applied */
|
||||
assert(t, data.Discussions[1].Notes[0].Author.Username, "hcramer4")
|
||||
assert(t, data.Discussions[2].Notes[0].Author.Username, "hcramer2")
|
||||
})
|
||||
|
||||
t.Run("Uses blacklist to filter unwanted authors", func(t *testing.T) {
|
||||
request := makeRequest(t, http.MethodPost, "/mr/discussions/list", DiscussionsRequest{Blacklist: []string{"hcramer"}})
|
||||
request := makeRequest(t, http.MethodPost, "/mr/discussions/list", DiscussionsRequest{Blacklist: []string{"hcramer0"}, SortBy: "latest_reply"})
|
||||
svc := middleware(
|
||||
discussionsListerService{testProjectData, fakeDiscussionsLister{}},
|
||||
withMr(testProjectData, fakeMergeRequestLister{}),
|
||||
@@ -90,8 +122,9 @@ func TestListDiscussions(t *testing.T) {
|
||||
)
|
||||
data := getDiscussionsList(t, svc, request)
|
||||
assert(t, data.SuccessResponse.Message, "Discussions retrieved")
|
||||
assert(t, len(data.Discussions), 1)
|
||||
assert(t, data.Discussions[0].Notes[0].Author.Username, "hcramer2")
|
||||
assert(t, len(data.Discussions), 2)
|
||||
assert(t, data.Discussions[0].Notes[0].Author.Username, "hcramer4")
|
||||
assert(t, data.Discussions[1].Notes[0].Author.Username, "hcramer2")
|
||||
})
|
||||
t.Run("Handles errors from Gitlab client", func(t *testing.T) {
|
||||
request := makeRequest(t, http.MethodPost, "/mr/discussions/list", DiscussionsRequest{Blacklist: []string{}})
|
||||
|
||||
Reference in New Issue
Block a user