Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
0100d939
Commit
0100d939
authored
Aug 03, 2020
by
Allison Browne
Committed by
Adam Hegyi
Aug 03, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support getting a todo for an alert in graphql api
parent
dc6fa046
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
337 additions
and
9 deletions
+337
-9
app/finders/todos_finder.rb
app/finders/todos_finder.rb
+9
-1
app/graphql/resolvers/todo_resolver.rb
app/graphql/resolvers/todo_resolver.rb
+13
-3
app/graphql/types/alert_management/alert_type.rb
app/graphql/types/alert_management/alert_type.rb
+6
-0
app/helpers/todos_helper.rb
app/helpers/todos_helper.rb
+2
-1
changelogs/unreleased/graphql-get-alert-todo.yml
changelogs/unreleased/graphql-get-alert-todo.yml
+5
-0
doc/api/graphql/reference/gitlab_schema.graphql
doc/api/graphql/reference/gitlab_schema.graphql
+55
-0
doc/api/graphql/reference/gitlab_schema.json
doc/api/graphql/reference/gitlab_schema.json
+161
-0
spec/finders/todos_finder_spec.rb
spec/finders/todos_finder_spec.rb
+22
-2
spec/graphql/resolvers/todo_resolver_spec.rb
spec/graphql/resolvers/todo_resolver_spec.rb
+12
-2
spec/graphql/types/alert_management/alert_type_spec.rb
spec/graphql/types/alert_management/alert_type_spec.rb
+1
-0
spec/requests/api/graphql/project/alert_management/alert/todos_spec.rb
.../api/graphql/project/alert_management/alert/todos_spec.rb
+51
-0
No files found.
app/finders/todos_finder.rb
View file @
0100d939
...
@@ -10,6 +10,7 @@
...
@@ -10,6 +10,7 @@
# action_id: integer
# action_id: integer
# author_id: integer
# author_id: integer
# project_id; integer
# project_id; integer
# target_id; integer
# state: 'pending' (default) or 'done'
# state: 'pending' (default) or 'done'
# type: 'Issue' or 'MergeRequest' or ['Issue', 'MergeRequest']
# type: 'Issue' or 'MergeRequest' or ['Issue', 'MergeRequest']
#
#
...
@@ -23,7 +24,7 @@ class TodosFinder
...
@@ -23,7 +24,7 @@ class TodosFinder
NONE
=
'0'
NONE
=
'0'
TODO_TYPES
=
Set
.
new
(
%w(Issue MergeRequest DesignManagement::Design)
).
freeze
TODO_TYPES
=
Set
.
new
(
%w(Issue MergeRequest DesignManagement::Design
AlertManagement::Alert
)
).
freeze
attr_accessor
:current_user
,
:params
attr_accessor
:current_user
,
:params
...
@@ -47,6 +48,7 @@ class TodosFinder
...
@@ -47,6 +48,7 @@ class TodosFinder
items
=
by_action
(
items
)
items
=
by_action
(
items
)
items
=
by_author
(
items
)
items
=
by_author
(
items
)
items
=
by_state
(
items
)
items
=
by_state
(
items
)
items
=
by_target_id
(
items
)
items
=
by_types
(
items
)
items
=
by_types
(
items
)
items
=
by_group
(
items
)
items
=
by_group
(
items
)
# Filtering by project HAS TO be the last because we use
# Filtering by project HAS TO be the last because we use
...
@@ -198,6 +200,12 @@ class TodosFinder
...
@@ -198,6 +200,12 @@ class TodosFinder
items
.
with_states
(
params
[
:state
])
items
.
with_states
(
params
[
:state
])
end
end
def
by_target_id
(
items
)
return
items
if
params
[
:target_id
].
blank?
items
.
for_target
(
params
[
:target_id
])
end
def
by_types
(
items
)
def
by_types
(
items
)
if
types
.
any?
if
types
.
any?
items
.
for_type
(
types
)
items
.
for_type
(
types
)
...
...
app/graphql/resolvers/todo_resolver.rb
View file @
0100d939
...
@@ -4,7 +4,7 @@ module Resolvers
...
@@ -4,7 +4,7 @@ module Resolvers
class
TodoResolver
<
BaseResolver
class
TodoResolver
<
BaseResolver
type
Types
::
TodoType
,
null:
true
type
Types
::
TodoType
,
null:
true
alias_method
:
user
,
:object
alias_method
:
target
,
:object
argument
:action
,
[
Types
::
TodoActionEnum
],
argument
:action
,
[
Types
::
TodoActionEnum
],
required:
false
,
required:
false
,
...
@@ -31,9 +31,10 @@ module Resolvers
...
@@ -31,9 +31,10 @@ module Resolvers
description:
'The type of the todo'
description:
'The type of the todo'
def
resolve
(
**
args
)
def
resolve
(
**
args
)
return
Todo
.
none
if
user
!=
context
[
:current_user
]
return
Todo
.
none
unless
current_user
.
present?
&&
target
.
present?
return
Todo
.
none
if
target
.
is_a?
(
User
)
&&
target
!=
current_user
TodosFinder
.
new
(
user
,
todo_finder_params
(
args
)).
execute
TodosFinder
.
new
(
current_
user
,
todo_finder_params
(
args
)).
execute
end
end
private
private
...
@@ -46,6 +47,15 @@ module Resolvers
...
@@ -46,6 +47,15 @@ module Resolvers
author_id:
args
[
:author_id
],
author_id:
args
[
:author_id
],
action_id:
args
[
:action
],
action_id:
args
[
:action
],
project_id:
args
[
:project_id
]
project_id:
args
[
:project_id
]
}.
merge
(
target_params
)
end
def
target_params
return
{}
unless
TodosFinder
::
TODO_TYPES
.
include?
(
target
.
class
.
name
)
{
type:
target
.
class
.
name
,
target_id:
target
.
id
}
}
end
end
end
end
...
...
app/graphql/types/alert_management/alert_type.rb
View file @
0100d939
...
@@ -97,6 +97,12 @@ module Types
...
@@ -97,6 +97,12 @@ module Types
description:
'URL for metrics embed for the alert'
,
description:
'URL for metrics embed for the alert'
,
resolve:
->
(
alert
,
_args
,
_context
)
{
alert
.
present
.
metrics_dashboard_url
}
resolve:
->
(
alert
,
_args
,
_context
)
{
alert
.
present
.
metrics_dashboard_url
}
field
:todos
,
Types
::
TodoType
.
connection_type
,
null:
true
,
description:
'Todos of the current user for the alert'
,
resolver:
Resolvers
::
TodoResolver
def
notes
def
notes
object
.
ordered_notes
object
.
ordered_notes
end
end
...
...
app/helpers/todos_helper.rb
View file @
0100d939
...
@@ -163,7 +163,8 @@ module TodosHelper
...
@@ -163,7 +163,8 @@ module TodosHelper
{
id:
''
,
text:
'Any Type'
},
{
id:
''
,
text:
'Any Type'
},
{
id:
'Issue'
,
text:
'Issue'
},
{
id:
'Issue'
,
text:
'Issue'
},
{
id:
'MergeRequest'
,
text:
'Merge Request'
},
{
id:
'MergeRequest'
,
text:
'Merge Request'
},
{
id:
'DesignManagement::Design'
,
text:
'Design'
}
{
id:
'DesignManagement::Design'
,
text:
'Design'
},
{
id:
'AlertManagement::Alert'
,
text:
'Alert'
}
]
]
end
end
...
...
changelogs/unreleased/graphql-get-alert-todo.yml
0 → 100644
View file @
0100d939
---
title
:
Support getting a todo for an alert in GraphQL API
merge_request
:
34789
author
:
type
:
added
doc/api/graphql/reference/gitlab_schema.graphql
View file @
0100d939
...
@@ -319,6 +319,61 @@ type AlertManagementAlert implements Noteable {
...
@@ -319,6 +319,61 @@ type AlertManagementAlert implements Noteable {
"""
"""
title
:
String
title
:
String
"""
Todos
of
the
current
user
for
the
alert
"""
todos
(
"""
The
action
to
be
filtered
"""
action
:
[
TodoActionEnum
!]
"""
Returns
the
elements
in
the
list
that
come
after
the
specified
cursor
.
"""
after
:
String
"""
The
ID
of
an
author
"""
authorId
:
[
ID
!]
"""
Returns
the
elements
in
the
list
that
come
before
the
specified
cursor
.
"""
before
:
String
"""
Returns
the
first
_n_
elements
from
the
list
.
"""
first
:
Int
"""
The
ID
of
a
group
"""
groupId
:
[
ID
!]
"""
Returns
the
last
_n_
elements
from
the
list
.
"""
last
:
Int
"""
The
ID
of
a
project
"""
projectId
:
[
ID
!]
"""
The
state
of
the
todo
"""
state
:
[
TodoStateEnum
!]
"""
The
type
of
the
todo
"""
type
:
[
TodoTargetEnum
!]
):
TodoConnection
"""
"""
Timestamp
the
alert
was
last
updated
Timestamp
the
alert
was
last
updated
"""
"""
...
...
doc/api/graphql/reference/gitlab_schema.json
View file @
0100d939
...
@@ -871,6 +871,167 @@
...
@@ -871,6 +871,167 @@
"isDeprecated": false,
"isDeprecated": false,
"deprecationReason": null
"deprecationReason": null
},
},
{
"name": "todos",
"description": "Todos of the current user for the alert",
"args": [
{
"name": "action",
"description": "The action to be filtered",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "ENUM",
"name": "TodoActionEnum",
"ofType": null
}
}
},
"defaultValue": null
},
{
"name": "authorId",
"description": "The ID of an author",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
}
},
"defaultValue": null
},
{
"name": "projectId",
"description": "The ID of a project",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
}
},
"defaultValue": null
},
{
"name": "groupId",
"description": "The ID of a group",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
}
},
"defaultValue": null
},
{
"name": "state",
"description": "The state of the todo",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "ENUM",
"name": "TodoStateEnum",
"ofType": null
}
}
},
"defaultValue": null
},
{
"name": "type",
"description": "The type of the todo",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "ENUM",
"name": "TodoTargetEnum",
"ofType": null
}
}
},
"defaultValue": null
},
{
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "before",
"description": "Returns the elements in the list that come before the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "first",
"description": "Returns the first _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
},
{
"name": "last",
"description": "Returns the last _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "TodoConnection",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
{
"name": "updatedAt",
"name": "updatedAt",
"description": "Timestamp the alert was last updated",
"description": "Timestamp the alert was last updated",
spec/finders/todos_finder_spec.rb
View file @
0100d939
...
@@ -232,6 +232,26 @@ RSpec.describe TodosFinder do
...
@@ -232,6 +232,26 @@ RSpec.describe TodosFinder do
expect
(
todos
).
to
match_array
([
todo2
,
todo1
])
expect
(
todos
).
to
match_array
([
todo2
,
todo1
])
end
end
end
end
context
'when filtering by target id'
do
it
'returns the expected todos for the target'
do
todos
=
finder
.
new
(
user
,
{
target_id:
issue
.
id
}).
execute
expect
(
todos
).
to
match_array
([
todo1
])
end
it
'returns the expected todos for multiple target ids'
do
todos
=
finder
.
new
(
user
,
{
target_id:
[
issue
.
id
,
merge_request
.
id
]
}).
execute
expect
(
todos
).
to
match_array
([
todo1
,
todo2
])
end
it
'returns the expected todos for empty target id collection'
do
todos
=
finder
.
new
(
user
,
{
target_id:
[]
}).
execute
expect
(
todos
).
to
match_array
([
todo1
,
todo2
])
end
end
end
end
context
'external authorization'
do
context
'external authorization'
do
...
@@ -307,9 +327,9 @@ RSpec.describe TodosFinder do
...
@@ -307,9 +327,9 @@ RSpec.describe TodosFinder do
it
'returns the expected types'
do
it
'returns the expected types'
do
expected_result
=
expected_result
=
if
Gitlab
.
ee?
if
Gitlab
.
ee?
%w[Epic Issue MergeRequest DesignManagement::Design]
%w[Epic Issue MergeRequest DesignManagement::Design
AlertManagement::Alert
]
else
else
%w[Issue MergeRequest DesignManagement::Design]
%w[Issue MergeRequest DesignManagement::Design
AlertManagement::Alert
]
end
end
expect
(
described_class
.
todo_types
).
to
contain_exactly
(
*
expected_result
)
expect
(
described_class
.
todo_types
).
to
contain_exactly
(
*
expected_result
)
...
...
spec/graphql/resolvers/todo_resolver_spec.rb
View file @
0100d939
...
@@ -99,7 +99,7 @@ RSpec.describe Resolvers::TodoResolver do
...
@@ -99,7 +99,7 @@ RSpec.describe Resolvers::TodoResolver do
end
end
end
end
context
'when no
user
is provided'
do
context
'when no
target
is provided'
do
it
'returns no todos'
do
it
'returns no todos'
do
todos
=
resolve
(
described_class
,
obj:
nil
,
args:
{},
ctx:
{
current_user:
current_user
})
todos
=
resolve
(
described_class
,
obj:
nil
,
args:
{},
ctx:
{
current_user:
current_user
})
...
@@ -107,7 +107,7 @@ RSpec.describe Resolvers::TodoResolver do
...
@@ -107,7 +107,7 @@ RSpec.describe Resolvers::TodoResolver do
end
end
end
end
context
'when
provided user is not
current user'
do
context
'when
target user is not the
current user'
do
it
'returns no todos'
do
it
'returns no todos'
do
other_user
=
create
(
:user
)
other_user
=
create
(
:user
)
...
@@ -116,6 +116,16 @@ RSpec.describe Resolvers::TodoResolver do
...
@@ -116,6 +116,16 @@ RSpec.describe Resolvers::TodoResolver do
expect
(
todos
).
to
be_empty
expect
(
todos
).
to
be_empty
end
end
end
end
context
'when request is for a todo target'
do
it
'returns only the todos for the target'
do
target
=
issue_todo_pending
.
target
todos
=
resolve
(
described_class
,
obj:
target
,
args:
{},
ctx:
{
current_user:
current_user
})
expect
(
todos
).
to
contain_exactly
(
issue_todo_pending
)
end
end
end
end
def
resolve_todos
(
args
=
{},
context
=
{
current_user:
current_user
})
def
resolve_todos
(
args
=
{},
context
=
{
current_user:
current_user
})
...
...
spec/graphql/types/alert_management/alert_type_spec.rb
View file @
0100d939
...
@@ -28,6 +28,7 @@ RSpec.describe GitlabSchema.types['AlertManagementAlert'] do
...
@@ -28,6 +28,7 @@ RSpec.describe GitlabSchema.types['AlertManagementAlert'] do
notes
notes
discussions
discussions
metrics_dashboard_url
metrics_dashboard_url
todos
]
]
expect
(
described_class
).
to
have_graphql_fields
(
*
expected_fields
)
expect
(
described_class
).
to
have_graphql_fields
(
*
expected_fields
)
...
...
spec/requests/api/graphql/project/alert_management/alert/todos_spec.rb
0 → 100644
View file @
0100d939
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
'getting Alert Management Alert Assignees'
do
include
GraphqlHelpers
let_it_be
(
:project
)
{
create
(
:project
)
}
let_it_be
(
:current_user
)
{
create
(
:user
)
}
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
project:
project
)
}
let_it_be
(
:other_alert
)
{
create
(
:alert_management_alert
,
project:
project
)
}
let_it_be
(
:todo
)
{
create
(
:todo
,
:pending
,
target:
alert
,
user:
current_user
,
project:
project
)
}
let_it_be
(
:other_todo
)
{
create
(
:todo
,
:pending
,
target:
other_alert
,
user:
current_user
,
project:
project
)
}
let
(
:fields
)
do
<<~
QUERY
nodes {
iid
todos {
nodes {
id
}
}
}
QUERY
end
let
(
:graphql_query
)
do
graphql_query_for
(
'project'
,
{
'fullPath'
=>
project
.
full_path
},
query_graphql_field
(
'alertManagementAlerts'
,
{},
fields
)
)
end
let
(
:gql_alerts
)
{
graphql_data
.
dig
(
'project'
,
'alertManagementAlerts'
,
'nodes'
)
}
let
(
:gql_todos
)
{
gql_alerts
.
map
{
|
gql_alert
|
[
gql_alert
[
'iid'
],
gql_alert
[
'todos'
][
'nodes'
]]
}.
to_h
}
let
(
:gql_alert_todo
)
{
gql_todos
[
alert
.
iid
.
to_s
].
first
}
let
(
:gql_other_alert_todo
)
{
gql_todos
[
other_alert
.
iid
.
to_s
].
first
}
before
do
project
.
add_developer
(
current_user
)
end
it
'includes the correct metrics dashboard url'
do
post_graphql
(
graphql_query
,
current_user:
current_user
)
expect
(
gql_alert_todo
[
'id'
]).
to
eq
(
todo
.
to_global_id
.
to_s
)
expect
(
gql_other_alert_todo
[
'id'
]).
to
eq
(
other_todo
.
to_global_id
.
to_s
)
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment