aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--graphql/connections/connections.go1
-rw-r--r--graphql/connections/gen_timeline.go111
-rw-r--r--graphql/gqlgen.yml6
-rw-r--r--graphql/graph/gen_graph.go981
-rw-r--r--graphql/models/edges.go5
-rw-r--r--graphql/models/gen_models.go12
-rw-r--r--graphql/resolvers/bug.go27
-rw-r--r--graphql/schema.graphql49
8 files changed, 1173 insertions, 19 deletions
diff --git a/graphql/connections/connections.go b/graphql/connections/connections.go
index de5b8f1a..68608116 100644
--- a/graphql/connections/connections.go
+++ b/graphql/connections/connections.go
@@ -1,6 +1,7 @@
//go:generate genny -in=connection_template.go -out=gen_bug.go gen "NodeType=string EdgeType=LazyBugEdge ConnectionType=models.BugConnection"
//go:generate genny -in=connection_template.go -out=gen_operation.go gen "NodeType=bug.Operation EdgeType=models.OperationEdge ConnectionType=models.OperationConnection"
//go:generate genny -in=connection_template.go -out=gen_comment.go gen "NodeType=bug.Comment EdgeType=models.CommentEdge ConnectionType=models.CommentConnection"
+//go:generate genny -in=connection_template.go -out=gen_timeline.go gen "NodeType=bug.TimelineItem EdgeType=models.TimelineItemEdge ConnectionType=models.TimelineItemConnection"
// Package connections implement a generic GraphQL relay connection
package connections
diff --git a/graphql/connections/gen_timeline.go b/graphql/connections/gen_timeline.go
new file mode 100644
index 00000000..4d417a45
--- /dev/null
+++ b/graphql/connections/gen_timeline.go
@@ -0,0 +1,111 @@
+// This file was automatically generated by genny.
+// Any changes will be lost if this file is regenerated.
+// see https://github.com/cheekybits/genny
+
+package connections
+
+import (
+ "fmt"
+
+ "github.com/MichaelMure/git-bug/bug"
+ "github.com/MichaelMure/git-bug/graphql/models"
+)
+
+// BugTimelineItemEdgeMaker define a function that take a bug.TimelineItem and an offset and
+// create an Edge.
+type BugTimelineItemEdgeMaker func(value bug.TimelineItem, offset int) Edge
+
+// BugTimelineItemConMaker define a function that create a models.TimelineItemConnection
+type BugTimelineItemConMaker func(
+ edges []models.TimelineItemEdge,
+ nodes []bug.TimelineItem,
+ info models.PageInfo,
+ totalCount int) (models.TimelineItemConnection, error)
+
+// BugTimelineItemCon will paginate a source according to the input of a relay connection
+func BugTimelineItemCon(source []bug.TimelineItem, edgeMaker BugTimelineItemEdgeMaker, conMaker BugTimelineItemConMaker, input models.ConnectionInput) (models.TimelineItemConnection, error) {
+ var nodes []bug.TimelineItem
+ var edges []models.TimelineItemEdge
+ var cursors []string
+ var pageInfo models.PageInfo
+ var totalCount = len(source)
+
+ emptyCon, _ := conMaker(edges, nodes, pageInfo, 0)
+
+ offset := 0
+
+ if input.After != nil {
+ for i, value := range source {
+ edge := edgeMaker(value, i)
+ if edge.GetCursor() == *input.After {
+ // remove all previous element including the "after" one
+ source = source[i+1:]
+ offset = i + 1
+ pageInfo.HasPreviousPage = true
+ break
+ }
+ }
+ }
+
+ if input.Before != nil {
+ for i, value := range source {
+ edge := edgeMaker(value, i+offset)
+
+ if edge.GetCursor() == *input.Before {
+ // remove all after element including the "before" one
+ pageInfo.HasNextPage = true
+ break
+ }
+
+ edges = append(edges, edge.(models.TimelineItemEdge))
+ cursors = append(cursors, edge.GetCursor())
+ nodes = append(nodes, value)
+ }
+ } else {
+ edges = make([]models.TimelineItemEdge, len(source))
+ cursors = make([]string, len(source))
+ nodes = source
+
+ for i, value := range source {
+ edge := edgeMaker(value, i+offset)
+ edges[i] = edge.(models.TimelineItemEdge)
+ cursors[i] = edge.GetCursor()
+ }
+ }
+
+ if input.First != nil {
+ if *input.First < 0 {
+ return emptyCon, fmt.Errorf("first less than zero")
+ }
+
+ if len(edges) > *input.First {
+ // Slice result to be of length first by removing edges from the end
+ edges = edges[:*input.First]
+ cursors = cursors[:*input.First]
+ nodes = nodes[:*input.First]
+ pageInfo.HasNextPage = true
+ }
+ }
+
+ if input.Last != nil {
+ if *input.Last < 0 {
+ return emptyCon, fmt.Errorf("last less than zero")
+ }
+
+ if len(edges) > *input.Last {
+ // Slice result to be of length last by removing edges from the start
+ edges = edges[len(edges)-*input.Last:]
+ cursors = cursors[len(cursors)-*input.Last:]
+ nodes = nodes[len(nodes)-*input.Last:]
+ pageInfo.HasPreviousPage = true
+ }
+ }
+
+ // Fill up pageInfo cursors
+ if len(cursors) > 0 {
+ pageInfo.StartCursor = cursors[0]
+ pageInfo.EndCursor = cursors[len(cursors)-1]
+ }
+
+ return conMaker(edges, nodes, pageInfo, totalCount)
+}
diff --git a/graphql/gqlgen.yml b/graphql/gqlgen.yml
index 516f335f..4ff24f4e 100644
--- a/graphql/gqlgen.yml
+++ b/graphql/gqlgen.yml
@@ -31,3 +31,9 @@ models:
model: github.com/MichaelMure/git-bug/bug.SetStatusOperation
LabelChangeOperation:
model: github.com/MichaelMure/git-bug/bug.LabelChangeOperation
+ TimelineItem:
+ model: github.com/MichaelMure/git-bug/bug.TimelineItem
+ CreateTimelineItem:
+ model: github.com/MichaelMure/git-bug/bug.CreateTimelineItem
+ CommentTimelineItem:
+ model: github.com/MichaelMure/git-bug/bug.CommentTimelineItem \ No newline at end of file
diff --git a/graphql/graph/gen_graph.go b/graphql/graph/gen_graph.go
index 1425032a..032cf5cb 100644
--- a/graphql/graph/gen_graph.go
+++ b/graphql/graph/gen_graph.go
@@ -67,6 +67,7 @@ type ComplexityRoot struct {
CreatedAt func(childComplexity int) int
LastEdit func(childComplexity int) int
Comments func(childComplexity int, after *string, before *string, first *int, last *int) int
+ Timeline func(childComplexity int, after *string, before *string, first *int, last *int) int
Operations func(childComplexity int, after *string, before *string, first *int, last *int) int
}
@@ -100,6 +101,12 @@ type ComplexityRoot struct {
Node func(childComplexity int) int
}
+ CommentTimelineItem struct {
+ Hash func(childComplexity int) int
+ LastState func(childComplexity int) int
+ History func(childComplexity int) int
+ }
+
CreateOperation struct {
Author func(childComplexity int) int
Date func(childComplexity int) int
@@ -108,7 +115,14 @@ type ComplexityRoot struct {
Files func(childComplexity int) int
}
+ CreateTimelineItem struct {
+ Hash func(childComplexity int) int
+ LastState func(childComplexity int) int
+ History func(childComplexity int) int
+ }
+
LabelChangeOperation struct {
+ Hash func(childComplexity int) int
Author func(childComplexity int) int
Date func(childComplexity int) int
Added func(childComplexity int) int
@@ -161,17 +175,31 @@ type ComplexityRoot struct {
}
SetStatusOperation struct {
+ Hash func(childComplexity int) int
Author func(childComplexity int) int
Date func(childComplexity int) int
Status func(childComplexity int) int
}
SetTitleOperation struct {
+ Hash func(childComplexity int) int
Author func(childComplexity int) int
Date func(childComplexity int) int
Title func(childComplexity int) int
Was func(childComplexity int) int
}
+
+ TimelineItemConnection struct {
+ Edges func(childComplexity int) int
+ Nodes func(childComplexity int) int
+ PageInfo func(childComplexity int) int
+ TotalCount func(childComplexity int) int
+ }
+
+ TimelineItemEdge struct {
+ Cursor func(childComplexity int) int
+ Node func(childComplexity int) int
+ }
}
type AddCommentOperationResolver interface {
@@ -183,6 +211,7 @@ type BugResolver interface {
LastEdit(ctx context.Context, obj *bug.Snapshot) (time.Time, error)
Comments(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (models.CommentConnection, error)
+ Timeline(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (models.TimelineItemConnection, error)
Operations(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (models.OperationConnection, error)
}
type CreateOperationResolver interface {
@@ -282,6 +311,68 @@ func field_Bug_comments_args(rawArgs map[string]interface{}) (map[string]interfa
}
+func field_Bug_timeline_args(rawArgs map[string]interface{}) (map[string]interface{}, error) {
+ args := map[string]interface{}{}
+ var arg0 *string
+ if tmp, ok := rawArgs["after"]; ok {
+ var err error
+ var ptr1 string
+ if tmp != nil {
+ ptr1, err = graphql.UnmarshalString(tmp)
+ arg0 = &ptr1
+ }
+
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["after"] = arg0
+ var arg1 *string
+ if tmp, ok := rawArgs["before"]; ok {
+ var err error
+ var ptr1 string
+ if tmp != nil {
+ ptr1, err = graphql.UnmarshalString(tmp)
+ arg1 = &ptr1
+ }
+
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["before"] = arg1
+ var arg2 *int
+ if tmp, ok := rawArgs["first"]; ok {
+ var err error
+ var ptr1 int
+ if tmp != nil {
+ ptr1, err = graphql.UnmarshalInt(tmp)
+ arg2 = &ptr1
+ }
+
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["first"] = arg2
+ var arg3 *int
+ if tmp, ok := rawArgs["last"]; ok {
+ var err error
+ var ptr1 int
+ if tmp != nil {
+ ptr1, err = graphql.UnmarshalInt(tmp)
+ arg3 = &ptr1
+ }
+
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["last"] = arg3
+ return args, nil
+
+}
+
func field_Bug_operations_args(rawArgs map[string]interface{}) (map[string]interface{}, error) {
args := map[string]interface{}{}
var arg0 *string
@@ -914,6 +1005,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Bug.Comments(childComplexity, args["after"].(*string), args["before"].(*string), args["first"].(*int), args["last"].(*int)), true
+ case "Bug.timeline":
+ if e.complexity.Bug.Timeline == nil {
+ break
+ }
+
+ args, err := field_Bug_timeline_args(rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Bug.Timeline(childComplexity, args["after"].(*string), args["before"].(*string), args["first"].(*int), args["last"].(*int)), true
+
case "Bug.operations":
if e.complexity.Bug.Operations == nil {
break
@@ -1031,6 +1134,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.CommentEdge.Node(childComplexity), true
+ case "CommentTimelineItem.hash":
+ if e.complexity.CommentTimelineItem.Hash == nil {
+ break
+ }
+
+ return e.complexity.CommentTimelineItem.Hash(childComplexity), true
+
+ case "CommentTimelineItem.lastState":
+ if e.complexity.CommentTimelineItem.LastState == nil {
+ break
+ }
+
+ return e.complexity.CommentTimelineItem.LastState(childComplexity), true
+
+ case "CommentTimelineItem.history":
+ if e.complexity.CommentTimelineItem.History == nil {
+ break
+ }
+
+ return e.complexity.CommentTimelineItem.History(childComplexity), true
+
case "CreateOperation.author":
if e.complexity.CreateOperation.Author == nil {
break
@@ -1066,6 +1190,34 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.CreateOperation.Files(childComplexity), true
+ case "CreateTimelineItem.hash":
+ if e.complexity.CreateTimelineItem.Hash == nil {
+ break
+ }
+
+ return e.complexity.CreateTimelineItem.Hash(childComplexity), true
+
+ case "CreateTimelineItem.lastState":
+ if e.complexity.CreateTimelineItem.LastState == nil {
+ break
+ }
+
+ return e.complexity.CreateTimelineItem.LastState(childComplexity), true
+
+ case "CreateTimelineItem.history":
+ if e.complexity.CreateTimelineItem.History == nil {
+ break
+ }
+
+ return e.complexity.CreateTimelineItem.History(childComplexity), true
+
+ case "LabelChangeOperation.hash":
+ if e.complexity.LabelChangeOperation.Hash == nil {
+ break
+ }
+
+ return e.complexity.LabelChangeOperation.Hash(childComplexity), true
+
case "LabelChangeOperation.author":
if e.complexity.LabelChangeOperation.Author == nil {
break
@@ -1312,6 +1464,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Repository.Bug(childComplexity, args["prefix"].(string)), true
+ case "SetStatusOperation.hash":
+ if e.complexity.SetStatusOperation.Hash == nil {
+ break
+ }
+
+ return e.complexity.SetStatusOperation.Hash(childComplexity), true
+
case "SetStatusOperation.author":
if e.complexity.SetStatusOperation.Author == nil {
break
@@ -1333,6 +1492,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.SetStatusOperation.Status(childComplexity), true
+ case "SetTitleOperation.hash":
+ if e.complexity.SetTitleOperation.Hash == nil {
+ break
+ }
+
+ return e.complexity.SetTitleOperation.Hash(childComplexity), true
+
case "SetTitleOperation.author":
if e.complexity.SetTitleOperation.Author == nil {
break
@@ -1361,6 +1527,48 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.SetTitleOperation.Was(childComplexity), true
+ case "TimelineItemConnection.edges":
+ if e.complexity.TimelineItemConnection.Edges == nil {
+ break
+ }
+
+ return e.complexity.TimelineItemConnection.Edges(childComplexity), true
+
+ case "TimelineItemConnection.nodes":
+ if e.complexity.TimelineItemConnection.Nodes == nil {
+ break
+ }
+
+ return e.complexity.TimelineItemConnection.Nodes(childComplexity), true
+
+ case "TimelineItemConnection.pageInfo":
+ if e.complexity.TimelineItemConnection.PageInfo == nil {
+ break
+ }
+
+ return e.complexity.TimelineItemConnection.PageInfo(childComplexity), true
+
+ case "TimelineItemConnection.totalCount":
+ if e.complexity.TimelineItemConnection.TotalCount == nil {
+ break
+ }
+
+ return e.complexity.TimelineItemConnection.TotalCount(childComplexity), true
+
+ case "TimelineItemEdge.cursor":
+ if e.complexity.TimelineItemEdge.Cursor == nil {
+ break
+ }
+
+ return e.complexity.TimelineItemEdge.Cursor(childComplexity), true
+
+ case "TimelineItemEdge.node":
+ if e.complexity.TimelineItemEdge.Node == nil {
+ break
+ }
+
+ return e.complexity.TimelineItemEdge.Node(childComplexity), true
+
}
return 0, false
}
@@ -1630,6 +1838,15 @@ func (ec *executionContext) _Bug(ctx context.Context, sel ast.SelectionSet, obj
}
wg.Done()
}(i, field)
+ case "timeline":
+ wg.Add(1)
+ go func(i int, field graphql.CollectedField) {
+ out.Values[i] = ec._Bug_timeline(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ wg.Done()
+ }(i, field)
case "operations":
wg.Add(1)
go func(i int, field graphql.CollectedField) {
@@ -1866,6 +2083,35 @@ func (ec *executionContext) _Bug_comments(ctx context.Context, field graphql.Col
}
// nolint: vetshadow
+func (ec *executionContext) _Bug_timeline(ctx context.Context, field graphql.CollectedField, obj *bug.Snapshot) graphql.Marshaler {
+ rawArgs := field.ArgumentMap(ec.Variables)
+ args, err := field_Bug_timeline_args(rawArgs)
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ rctx := &graphql.ResolverContext{
+ Object: "Bug",
+ Args: args,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return ec.resolvers.Bug().Timeline(ctx, obj, args["after"].(*string), args["before"].(*string), args["first"].(*int), args["last"].(*int))
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(models.TimelineItemConnection)
+ rctx.Result = res
+
+ return ec._TimelineItemConnection(ctx, field.Selections, &res)
+}
+
+// nolint: vetshadow
func (ec *executionContext) _Bug_operations(ctx context.Context, field graphql.CollectedField, obj *bug.Snapshot) graphql.Marshaler {
rawArgs := field.ArgumentMap(ec.Variables)
args, err := field_Bug_operations_args(rawArgs)
@@ -2570,6 +2816,146 @@ func (ec *executionContext) _CommentEdge_node(ctx context.Context, field graphql
return ec._Comment(ctx, field.Selections, &res)
}
+var commentTimelineItemImplementors = []string{"CommentTimelineItem", "TimelineItem"}
+
+// nolint: gocyclo, errcheck, gas, goconst
+func (ec *executionContext) _CommentTimelineItem(ctx context.Context, sel ast.SelectionSet, obj *bug.CommentTimelineItem) graphql.Marshaler {
+ fields := graphql.CollectFields(ctx, sel, commentTimelineItemImplementors)
+
+ out := graphql.NewOrderedMap(len(fields))
+ invalid := false
+ for i, field := range fields {
+ out.Keys[i] = field.Alias
+
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("CommentTimelineItem")
+ case "hash":
+ out.Values[i] = ec._CommentTimelineItem_hash(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ case "lastState":
+ out.Values[i] = ec._CommentTimelineItem_lastState(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ case "history":
+ out.Values[i] = ec._CommentTimelineItem_history(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+
+ if invalid {
+ return graphql.Null
+ }
+ return out
+}
+
+// nolint: vetshadow
+func (ec *executionContext) _CommentTimelineItem_hash(ctx context.Context, field graphql.CollectedField, obj *bug.CommentTimelineItem) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "CommentTimelineItem",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.Hash()
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(git.Hash)
+ rctx.Result = res
+ return res
+}
+
+// nolint: vetshadow
+func (ec *executionContext) _CommentTimelineItem_lastState(ctx context.Context, field graphql.CollectedField, obj *bug.CommentTimelineItem) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "CommentTimelineItem",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.LastState(), nil
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(bug.Comment)
+ rctx.Result = res
+
+ return ec._Comment(ctx, field.Selections, &res)
+}
+
+// nolint: vetshadow
+func (ec *executionContext) _CommentTimelineItem_history(ctx context.Context, field graphql.CollectedField, obj *bug.CommentTimelineItem) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "CommentTimelineItem",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.History, nil
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.([]bug.Comment)
+ rctx.Result = res
+
+ arr1 := make(graphql.Array, len(res))
+ var wg sync.WaitGroup
+
+ isLen1 := len(res) == 1
+ if !isLen1 {
+ wg.Add(len(res))
+ }
+
+ for idx1 := range res {
+ idx1 := idx1
+ rctx := &graphql.ResolverContext{
+ Index: &idx1,
+ Result: &res[idx1],
+ }
+ ctx := graphql.WithResolverContext(ctx, rctx)
+ f := func(idx1 int) {
+ if !isLen1 {
+ defer wg.Done()
+ }
+ arr1[idx1] = func() graphql.Marshaler {
+
+ return ec._Comment(ctx, field.Selections, &res[idx1])
+ }()
+ }
+ if isLen1 {
+ f(idx1)
+ } else {
+ go f(idx1)
+ }
+
+ }
+ wg.Wait()
+ return arr1
+}
+
var createOperationImplementors = []string{"CreateOperation", "Operation", "Authored"}
// nolint: gocyclo, errcheck, gas, goconst
@@ -2749,7 +3135,147 @@ func (ec *executionContext) _CreateOperation_files(ctx context.Context, field gr
return arr1
}
-var labelChangeOperationImplementors = []string{"LabelChangeOperation", "Operation", "Authored"}
+var createTimelineItemImplementors = []string{"CreateTimelineItem", "TimelineItem"}
+
+// nolint: gocyclo, errcheck, gas, goconst
+func (ec *executionContext) _CreateTimelineItem(ctx context.Context, sel ast.SelectionSet, obj *bug.CreateTimelineItem) graphql.Marshaler {
+ fields := graphql.CollectFields(ctx, sel, createTimelineItemImplementors)
+
+ out := graphql.NewOrderedMap(len(fields))
+ invalid := false
+ for i, field := range fields {
+ out.Keys[i] = field.Alias
+
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("CreateTimelineItem")
+ case "hash":
+ out.Values[i] = ec._CreateTimelineItem_hash(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ case "lastState":
+ out.Values[i] = ec._CreateTimelineItem_lastState(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ case "history":
+ out.Values[i] = ec._CreateTimelineItem_history(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+
+ if invalid {
+ return graphql.Null
+ }
+ return out
+}
+
+// nolint: vetshadow
+func (ec *executionContext) _CreateTimelineItem_hash(ctx context.Context, field graphql.CollectedField, obj *bug.CreateTimelineItem) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "CreateTimelineItem",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.Hash()
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(git.Hash)
+ rctx.Result = res
+ return res
+}
+
+// nolint: vetshadow
+func (ec *executionContext) _CreateTimelineItem_lastState(ctx context.Context, field graphql.CollectedField, obj *bug.CreateTimelineItem) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "CreateTimelineItem",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.LastState(), nil
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(bug.Comment)
+ rctx.Result = res
+
+ return ec._Comment(ctx, field.Selections, &res)
+}
+
+// nolint: vetshadow
+func (ec *executionContext) _CreateTimelineItem_history(ctx context.Context, field graphql.CollectedField, obj *bug.CreateTimelineItem) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "CreateTimelineItem",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.History, nil
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.([]bug.Comment)
+ rctx.Result = res
+
+ arr1 := make(graphql.Array, len(res))
+ var wg sync.WaitGroup
+
+ isLen1 := len(res) == 1
+ if !isLen1 {
+ wg.Add(len(res))
+ }
+
+ for idx1 := range res {
+ idx1 := idx1
+ rctx := &graphql.ResolverContext{
+ Index: &idx1,
+ Result: &res[idx1],
+ }
+ ctx := graphql.WithResolverContext(ctx, rctx)
+ f := func(idx1 int) {
+ if !isLen1 {
+ defer wg.Done()
+ }
+ arr1[idx1] = func() graphql.Marshaler {
+
+ return ec._Comment(ctx, field.Selections, &res[idx1])
+ }()
+ }
+ if isLen1 {
+ f(idx1)
+ } else {
+ go f(idx1)
+ }
+
+ }
+ wg.Wait()
+ return arr1
+}
+
+var labelChangeOperationImplementors = []string{"LabelChangeOperation", "Operation", "Authored", "TimelineItem"}
// nolint: gocyclo, errcheck, gas, goconst
func (ec *executionContext) _LabelChangeOperation(ctx context.Context, sel ast.SelectionSet, obj *bug.LabelChangeOperation) graphql.Marshaler {
@@ -2764,6 +3290,11 @@ func (ec *executionContext) _LabelChangeOperation(ctx context.Context, sel ast.S
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("LabelChangeOperation")
+ case "hash":
+ out.Values[i] = ec._LabelChangeOperation_hash(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
case "author":
wg.Add(1)
go func(i int, field graphql.CollectedField) {
@@ -2804,6 +3335,28 @@ func (ec *executionContext) _LabelChangeOperation(ctx context.Context, sel ast.S
}
// nolint: vetshadow
+func (ec *executionContext) _LabelChangeOperation_hash(ctx context.Context, field graphql.CollectedField, obj *bug.LabelChangeOperation) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "LabelChangeOperation",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.Hash()
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(git.Hash)
+ rctx.Result = res
+ return res
+}
+
+// nolint: vetshadow
func (ec *executionContext) _LabelChangeOperation_author(ctx context.Context, field graphql.CollectedField, obj *bug.LabelChangeOperation) graphql.Marshaler {
rctx := &graphql.ResolverContext{
Object: "LabelChangeOperation",
@@ -3938,7 +4491,7 @@ func (ec *executionContext) _Repository_bug(ctx context.Context, field graphql.C
return ec._Bug(ctx, field.Selections, res)
}
-var setStatusOperationImplementors = []string{"SetStatusOperation", "Operation", "Authored"}
+var setStatusOperationImplementors = []string{"SetStatusOperation", "Operation", "Authored", "TimelineItem"}
// nolint: gocyclo, errcheck, gas, goconst
func (ec *executionContext) _SetStatusOperation(ctx context.Context, sel ast.SelectionSet, obj *bug.SetStatusOperation) graphql.Marshaler {
@@ -3953,6 +4506,11 @@ func (ec *executionContext) _SetStatusOperation(ctx context.Context, sel ast.Sel
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("SetStatusOperation")
+ case "hash":
+ out.Values[i] = ec._SetStatusOperation_hash(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
case "author":
wg.Add(1)
go func(i int, field graphql.CollectedField) {
@@ -3992,6 +4550,28 @@ func (ec *executionContext) _SetStatusOperation(ctx context.Context, sel ast.Sel
}
// nolint: vetshadow
+func (ec *executionContext) _SetStatusOperation_hash(ctx context.Context, field graphql.CollectedField, obj *bug.SetStatusOperation) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "SetStatusOperation",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.Hash()
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(git.Hash)
+ rctx.Result = res
+ return res
+}
+
+// nolint: vetshadow
func (ec *executionContext) _SetStatusOperation_author(ctx context.Context, field graphql.CollectedField, obj *bug.SetStatusOperation) graphql.Marshaler {
rctx := &graphql.ResolverContext{
Object: "SetStatusOperation",
@@ -4058,7 +4638,7 @@ func (ec *executionContext) _SetStatusOperation_status(ctx context.Context, fiel
return res
}
-var setTitleOperationImplementors = []string{"SetTitleOperation", "Operation", "Authored"}
+var setTitleOperationImplementors = []string{"SetTitleOperation", "Operation", "Authored", "TimelineItem"}
// nolint: gocyclo, errcheck, gas, goconst
func (ec *executionContext) _SetTitleOperation(ctx context.Context, sel ast.SelectionSet, obj *bug.SetTitleOperation) graphql.Marshaler {
@@ -4073,6 +4653,11 @@ func (ec *executionContext) _SetTitleOperation(ctx context.Context, sel ast.Sele
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("SetTitleOperation")
+ case "hash":
+ out.Values[i] = ec._SetTitleOperation_hash(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
case "author":
wg.Add(1)
go func(i int, field graphql.CollectedField) {
@@ -4113,6 +4698,28 @@ func (ec *executionContext) _SetTitleOperation(ctx context.Context, sel ast.Sele
}
// nolint: vetshadow
+func (ec *executionContext) _SetTitleOperation_hash(ctx context.Context, field graphql.CollectedField, obj *bug.SetTitleOperation) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "SetTitleOperation",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.Hash()
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(git.Hash)
+ rctx.Result = res
+ return res
+}
+
+// nolint: vetshadow
func (ec *executionContext) _SetTitleOperation_author(ctx context.Context, field graphql.CollectedField, obj *bug.SetTitleOperation) graphql.Marshaler {
rctx := &graphql.ResolverContext{
Object: "SetTitleOperation",
@@ -4201,6 +4808,286 @@ func (ec *executionContext) _SetTitleOperation_was(ctx context.Context, field gr
return graphql.MarshalString(res)
}
+var timelineItemConnectionImplementors = []string{"TimelineItemConnection"}
+
+// nolint: gocyclo, errcheck, gas, goconst
+func (ec *executionContext) _TimelineItemConnection(ctx context.Context, sel ast.SelectionSet, obj *models.TimelineItemConnection) graphql.Marshaler {
+ fields := graphql.CollectFields(ctx, sel, timelineItemConnectionImplementors)
+
+ out := graphql.NewOrderedMap(len(fields))
+ invalid := false
+ for i, field := range fields {
+ out.Keys[i] = field.Alias
+
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("TimelineItemConnection")
+ case "edges":
+ out.Values[i] = ec._TimelineItemConnection_edges(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ case "nodes":
+ out.Values[i] = ec._TimelineItemConnection_nodes(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ case "pageInfo":
+ out.Values[i] = ec._TimelineItemConnection_pageInfo(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ case "totalCount":
+ out.Values[i] = ec._TimelineItemConnection_totalCount(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+
+ if invalid {
+ return graphql.Null
+ }
+ return out
+}
+
+// nolint: vetshadow
+func (ec *executionContext) _TimelineItemConnection_edges(ctx context.Context, field graphql.CollectedField, obj *models.TimelineItemConnection) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "TimelineItemConnection",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.Edges, nil
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.([]models.TimelineItemEdge)
+ rctx.Result = res
+
+ arr1 := make(graphql.Array, len(res))
+ var wg sync.WaitGroup
+
+ isLen1 := len(res) == 1
+ if !isLen1 {
+ wg.Add(len(res))
+ }
+
+ for idx1 := range res {
+ idx1 := idx1
+ rctx := &graphql.ResolverContext{
+ Index: &idx1,
+ Result: &res[idx1],
+ }
+ ctx := graphql.WithResolverContext(ctx, rctx)
+ f := func(idx1 int) {
+ if !isLen1 {
+ defer wg.Done()
+ }
+ arr1[idx1] = func() graphql.Marshaler {
+
+ return ec._TimelineItemEdge(ctx, field.Selections, &res[idx1])
+ }()
+ }
+ if isLen1 {
+ f(idx1)
+ } else {
+ go f(idx1)
+ }
+
+ }
+ wg.Wait()
+ return arr1
+}
+
+// nolint: vetshadow
+func (ec *executionContext) _TimelineItemConnection_nodes(ctx context.Context, field graphql.CollectedField, obj *models.TimelineItemConnection) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "TimelineItemConnection",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.Nodes, nil
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.([]bug.TimelineItem)
+ rctx.Result = res
+
+ arr1 := make(graphql.Array, len(res))
+ var wg sync.WaitGroup
+
+ isLen1 := len(res) == 1
+ if !isLen1 {
+ wg.Add(len(res))
+ }
+
+ for idx1 := range res {
+ idx1 := idx1
+ rctx := &graphql.ResolverContext{
+ Index: &idx1,
+ Result: &res[idx1],
+ }
+ ctx := graphql.WithResolverContext(ctx, rctx)
+ f := func(idx1 int) {
+ if !isLen1 {
+ defer wg.Done()
+ }
+ arr1[idx1] = func() graphql.Marshaler {
+
+ return ec._TimelineItem(ctx, field.Selections, &res[idx1])
+ }()
+ }
+ if isLen1 {
+ f(idx1)
+ } else {
+ go f(idx1)
+ }
+
+ }
+ wg.Wait()
+ return arr1
+}
+
+// nolint: vetshadow
+func (ec *executionContext) _TimelineItemConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *models.TimelineItemConnection) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "TimelineItemConnection",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.PageInfo, nil
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(models.PageInfo)
+ rctx.Result = res
+
+ return ec._PageInfo(ctx, field.Selections, &res)
+}
+
+// nolint: vetshadow
+func (ec *executionContext) _TimelineItemConnection_totalCount(ctx context.Context, field graphql.CollectedField, obj *models.TimelineItemConnection) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "TimelineItemConnection",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.TotalCount, nil
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(int)
+ rctx.Result = res
+ return graphql.MarshalInt(res)
+}
+
+var timelineItemEdgeImplementors = []string{"TimelineItemEdge"}
+
+// nolint: gocyclo, errcheck, gas, goconst
+func (ec *executionContext) _TimelineItemEdge(ctx context.Context, sel ast.SelectionSet, obj *models.TimelineItemEdge) graphql.Marshaler {
+ fields := graphql.CollectFields(ctx, sel, timelineItemEdgeImplementors)
+
+ out := graphql.NewOrderedMap(len(fields))
+ invalid := false
+ for i, field := range fields {
+ out.Keys[i] = field.Alias
+
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("TimelineItemEdge")
+ case "cursor":
+ out.Values[i] = ec._TimelineItemEdge_cursor(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ case "node":
+ out.Values[i] = ec._TimelineItemEdge_node(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+
+ if invalid {
+ return graphql.Null
+ }
+ return out
+}
+
+// nolint: vetshadow
+func (ec *executionContext) _TimelineItemEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *models.TimelineItemEdge) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "TimelineItemEdge",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.Cursor, nil
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(string)
+ rctx.Result = res
+ return graphql.MarshalString(res)
+}
+
+// nolint: vetshadow
+func (ec *executionContext) _TimelineItemEdge_node(ctx context.Context, field graphql.CollectedField, obj *models.TimelineItemEdge) graphql.Marshaler {
+ rctx := &graphql.ResolverContext{
+ Object: "TimelineItemEdge",
+ Args: nil,
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, obj, func(ctx context.Context) (interface{}, error) {
+ return obj.Node, nil
+ })
+ if resTmp == nil {
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(bug.TimelineItem)
+ rctx.Result = res
+
+ return ec._TimelineItem(ctx, field.Selections, &res)
+}
+
var __DirectiveImplementors = []string{"__Directive"}
// nolint: gocyclo, errcheck, gas, goconst
@@ -5515,16 +6402,35 @@ func (ec *executionContext) _Operation(ctx context.Context, sel ast.SelectionSet
switch obj := (*obj).(type) {
case nil:
return graphql.Null
- case bug.CreateOperation:
- return ec._CreateOperation(ctx, sel, &obj)
- case bug.SetTitleOperation:
- return ec._SetTitleOperation(ctx, sel, &obj)
- case bug.AddCommentOperation:
- return ec._AddCommentOperation(ctx, sel, &obj)
- case bug.SetStatusOperation:
- return ec._SetStatusOperation(ctx, sel, &obj)
- case bug.LabelChangeOperation:
- return ec._LabelChangeOperation(ctx, sel, &obj)
+ case *bug.CreateOperation:
+ return ec._CreateOperation(ctx, sel, obj)
+ case *bug.SetTitleOperation:
+ return ec._SetTitleOperation(ctx, sel, obj)
+ case *bug.AddCommentOperation:
+ return ec._AddCommentOperation(ctx, sel, obj)
+ case *bug.SetStatusOperation:
+ return ec._SetStatusOperation(ctx, sel, obj)
+ case *bug.LabelChangeOperation:
+ return ec._LabelChangeOperation(ctx, sel, obj)
+ default:
+ panic(fmt.Errorf("unexpected type %T", obj))
+ }
+}
+
+func (ec *executionContext) _TimelineItem(ctx context.Context, sel ast.SelectionSet, obj *bug.TimelineItem) graphql.Marshaler {
+ switch obj := (*obj).(type) {
+ case nil:
+ return graphql.Null
+ case *bug.SetTitleOperation:
+ return ec._SetTitleOperation(ctx, sel, obj)
+ case *bug.SetStatusOperation:
+ return ec._SetStatusOperation(ctx, sel, obj)
+ case *bug.LabelChangeOperation:
+ return ec._LabelChangeOperation(ctx, sel, obj)
+ case *bug.CreateTimelineItem:
+ return ec._CreateTimelineItem(ctx, sel, obj)
+ case *bug.CommentTimelineItem:
+ return ec._CommentTimelineItem(ctx, sel, obj)
default:
panic(fmt.Errorf("unexpected type %T", obj))
}
@@ -5629,6 +6535,11 @@ type OperationEdge {
node: Operation!
}
+"""An item in the timeline of events"""
+interface TimelineItem {
+ hash: Hash!
+}
+
"""An operation applied to a bug."""
interface Operation {
"""The operations author."""
@@ -5646,7 +6557,8 @@ type CreateOperation implements Operation & Authored {
files: [Hash!]!
}
-type SetTitleOperation implements Operation & Authored {
+type SetTitleOperation implements Operation & Authored & TimelineItem {
+ hash: Hash!
author: Person!
date: Time!
@@ -5662,14 +6574,16 @@ type AddCommentOperation implements Operation & Authored {
files: [Hash!]!
}
-type SetStatusOperation implements Operation & Authored {
+type SetStatusOperation implements Operation & Authored & TimelineItem {
+ hash: Hash!
author: Person!
date: Time!
status: Status!
}
-type LabelChangeOperation implements Operation & Authored {
+type LabelChangeOperation implements Operation & Authored & TimelineItem {
+ hash: Hash!
author: Person!
date: Time!
@@ -5677,6 +6591,30 @@ type LabelChangeOperation implements Operation & Authored {
removed: [Label!]!
}
+type TimelineItemConnection {
+ edges: [TimelineItemEdge!]!
+ nodes: [TimelineItem!]!
+ pageInfo: PageInfo!
+ totalCount: Int!
+}
+
+type TimelineItemEdge {
+ cursor: String!
+ node: TimelineItem!
+}
+
+type CreateTimelineItem implements TimelineItem {
+ hash: Hash!
+ lastState: Comment!
+ history: [Comment!]!
+}
+
+type CommentTimelineItem implements TimelineItem {
+ hash: Hash!
+ lastState: Comment!
+ history: [Comment!]!
+}
+
"""The connection type for Bug."""
type BugConnection {
"""A list of edges."""
@@ -5717,6 +6655,17 @@ type Bug {
last: Int
): CommentConnection!
+ timeline(
+ """Returns the elements in the list that come after the specified cursor."""
+ after: String
+ """Returns the elements in the list that come before the specified cursor."""
+ before: String
+ """Returns the first _n_ elements from the list."""
+ first: Int
+ """Returns the last _n_ elements from the list."""
+ last: Int
+ ): TimelineItemConnection!
+
operations(
"""Returns the elements in the list that come after the specified cursor."""
after: String
diff --git a/graphql/models/edges.go b/graphql/models/edges.go
index 7de76edf..1dc42583 100644
--- a/graphql/models/edges.go
+++ b/graphql/models/edges.go
@@ -14,3 +14,8 @@ func (e BugEdge) GetCursor() string {
func (e CommentEdge) GetCursor() string {
return e.Cursor
}
+
+// GetCursor return the cursor entry of an edge
+func (e TimelineItemEdge) GetCursor() string {
+ return e.Cursor
+}
diff --git a/graphql/models/gen_models.go b/graphql/models/gen_models.go
index 23a25814..849b1842 100644
--- a/graphql/models/gen_models.go
+++ b/graphql/models/gen_models.go
@@ -59,6 +59,18 @@ type PageInfo struct {
EndCursor string `json:"endCursor"`
}
+type TimelineItemConnection struct {
+ Edges []TimelineItemEdge `json:"edges"`
+ Nodes []bug.TimelineItem `json:"nodes"`
+ PageInfo PageInfo `json:"pageInfo"`
+ TotalCount int `json:"totalCount"`
+}
+
+type TimelineItemEdge struct {
+ Cursor string `json:"cursor"`
+ Node bug.TimelineItem `json:"node"`
+}
+
type Status string
const (
diff --git a/graphql/resolvers/bug.go b/graphql/resolvers/bug.go
index 858feb16..76eed55d 100644
--- a/graphql/resolvers/bug.go
+++ b/graphql/resolvers/bug.go
@@ -69,6 +69,33 @@ func (bugResolver) Operations(ctx context.Context, obj *bug.Snapshot, after *str
return connections.BugOperationCon(obj.Operations, edger, conMaker, input)
}
+func (bugResolver) Timeline(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (models.TimelineItemConnection, error) {
+ input := models.ConnectionInput{
+ Before: before,
+ After: after,
+ First: first,
+ Last: last,
+ }
+
+ edger := func(op bug.TimelineItem, offset int) connections.Edge {
+ return models.TimelineItemEdge{
+ Node: op,
+ Cursor: connections.OffsetToCursor(offset),
+ }
+ }
+
+ conMaker := func(edges []models.TimelineItemEdge, nodes []bug.TimelineItem, info models.PageInfo, totalCount int) (models.TimelineItemConnection, error) {
+ return models.TimelineItemConnection{
+ Edges: edges,
+ Nodes: nodes,
+ PageInfo: info,
+ TotalCount: totalCount,
+ }, nil
+ }
+
+ return connections.BugTimelineItemCon(obj.Timeline, edger, conMaker, input)
+}
+
func (bugResolver) LastEdit(ctx context.Context, obj *bug.Snapshot) (time.Time, error) {
return obj.LastEditTime(), nil
}
diff --git a/graphql/schema.graphql b/graphql/schema.graphql
index c083ac4f..2e685779 100644
--- a/graphql/schema.graphql
+++ b/graphql/schema.graphql
@@ -73,6 +73,11 @@ type OperationEdge {
node: Operation!
}
+"""An item in the timeline of events"""
+interface TimelineItem {
+ hash: Hash!
+}
+
"""An operation applied to a bug."""
interface Operation {
"""The operations author."""
@@ -90,7 +95,8 @@ type CreateOperation implements Operation & Authored {
files: [Hash!]!
}
-type SetTitleOperation implements Operation & Authored {
+type SetTitleOperation implements Operation & Authored & TimelineItem {
+ hash: Hash!
author: Person!
date: Time!
@@ -106,14 +112,16 @@ type AddCommentOperation implements Operation & Authored {
files: [Hash!]!
}
-type SetStatusOperation implements Operation & Authored {
+type SetStatusOperation implements Operation & Authored & TimelineItem {
+ hash: Hash!
author: Person!
date: Time!
status: Status!
}
-type LabelChangeOperation implements Operation & Authored {
+type LabelChangeOperation implements Operation & Authored & TimelineItem {
+ hash: Hash!
author: Person!
date: Time!
@@ -121,6 +129,30 @@ type LabelChangeOperation implements Operation & Authored {
removed: [Label!]!
}
+type TimelineItemConnection {
+ edges: [TimelineItemEdge!]!
+ nodes: [TimelineItem!]!
+ pageInfo: PageInfo!
+ totalCount: Int!
+}
+
+type TimelineItemEdge {
+ cursor: String!
+ node: TimelineItem!
+}
+
+type CreateTimelineItem implements TimelineItem {
+ hash: Hash!
+ lastState: Comment!
+ history: [Comment!]!
+}
+
+type CommentTimelineItem implements TimelineItem {
+ hash: Hash!
+ lastState: Comment!
+ history: [Comment!]!
+}
+
"""The connection type for Bug."""
type BugConnection {
"""A list of edges."""
@@ -161,6 +193,17 @@ type Bug {
last: Int
): CommentConnection!
+ timeline(
+ """Returns the elements in the list that come after the specified cursor."""
+ after: String
+ """Returns the elements in the list that come before the specified cursor."""
+ before: String
+ """Returns the first _n_ elements from the list."""
+ first: Int
+ """Returns the last _n_ elements from the list."""
+ last: Int
+ ): TimelineItemConnection!
+
operations(
"""Returns the elements in the list that come after the specified cursor."""
after: String