Commit e39b91d0 authored by David O'Regan's avatar David O'Regan Committed by Peter Leitzen

Alert Management assignee filter

Allow for Alert Management to
support filtering via assignee
username
parent fb7aca94
...@@ -19,8 +19,10 @@ module AlertManagement ...@@ -19,8 +19,10 @@ module AlertManagement
collection = project.alert_management_alerts collection = project.alert_management_alerts
collection = by_status(collection) collection = by_status(collection)
collection = by_search(collection)
collection = by_iid(collection) collection = by_iid(collection)
collection = by_assignee(collection)
collection = by_search(collection)
sort(collection) sort(collection)
end end
...@@ -48,6 +50,10 @@ module AlertManagement ...@@ -48,6 +50,10 @@ module AlertManagement
params[:sort] ? collection.sort_by_attribute(params[:sort]) : collection params[:sort] ? collection.sort_by_attribute(params[:sort]) : collection
end end
def by_assignee(collection)
params[:assignee_username].present? ? collection.for_assignee_username(params[:assignee_username]) : collection
end
def authorized? def authorized?
Ability.allowed?(current_user, :read_alert_management_alert, project) Ability.allowed?(current_user, :read_alert_management_alert, project)
end end
......
...@@ -22,6 +22,10 @@ module Resolvers ...@@ -22,6 +22,10 @@ module Resolvers
description: 'Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.', description: 'Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.',
required: false required: false
argument :assignee_username, GraphQL::STRING_TYPE,
required: false,
description: 'Username of a user assigned to the issue'
type Types::AlertManagement::AlertType, null: true type Types::AlertManagement::AlertType, null: true
def resolve_with_lookahead(**args) def resolve_with_lookahead(**args)
......
...@@ -9,6 +9,10 @@ module Resolvers ...@@ -9,6 +9,10 @@ module Resolvers
description: 'Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.', description: 'Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.',
required: false required: false
argument :assignee_username, GraphQL::STRING_TYPE,
required: false,
description: 'Username of a user assigned to the issue'
def resolve(**args) def resolve(**args)
::Gitlab::AlertManagement::AlertStatusCounts.new(context[:current_user], object, args) ::Gitlab::AlertManagement::AlertStatusCounts.new(context[:current_user], object, args)
end end
......
...@@ -113,6 +113,7 @@ module AlertManagement ...@@ -113,6 +113,7 @@ module AlertManagement
scope :for_status, -> (status) { with_status(status) } scope :for_status, -> (status) { with_status(status) }
scope :for_fingerprint, -> (project, fingerprint) { where(project: project, fingerprint: fingerprint) } scope :for_fingerprint, -> (project, fingerprint) { where(project: project, fingerprint: fingerprint) }
scope :for_environment, -> (environment) { where(environment: environment) } scope :for_environment, -> (environment) { where(environment: environment) }
scope :for_assignee_username, -> (assignee_username) { joins(:assignees).merge(User.by_username(assignee_username)) }
scope :search, -> (query) { fuzzy_search(query, [:title, :description, :monitoring_tool, :service]) } scope :search, -> (query) { fuzzy_search(query, [:title, :description, :monitoring_tool, :service]) }
scope :open, -> { with_status(open_statuses) } scope :open, -> { with_status(open_statuses) }
scope :not_resolved, -> { without_status(:resolved) } scope :not_resolved, -> { without_status(:resolved) }
......
---
title: Make alerts searchable by assignee username in GraphQL API
merge_request: 44911
author:
type: added
...@@ -13002,6 +13002,11 @@ type Project { ...@@ -13002,6 +13002,11 @@ type Project {
A single Alert Management alert of the project A single Alert Management alert of the project
""" """
alertManagementAlert( alertManagementAlert(
"""
Username of a user assigned to the issue
"""
assigneeUsername: String
""" """
IID of the alert. For example, "1" IID of the alert. For example, "1"
""" """
...@@ -13027,6 +13032,11 @@ type Project { ...@@ -13027,6 +13032,11 @@ type Project {
Counts of alerts by status for the project Counts of alerts by status for the project
""" """
alertManagementAlertStatusCounts( alertManagementAlertStatusCounts(
"""
Username of a user assigned to the issue
"""
assigneeUsername: String
""" """
Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool. Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.
""" """
...@@ -13042,6 +13052,11 @@ type Project { ...@@ -13042,6 +13052,11 @@ type Project {
""" """
after: String after: String
"""
Username of a user assigned to the issue
"""
assigneeUsername: String
""" """
Returns the elements in the list that come before the specified cursor. Returns the elements in the list that come before the specified cursor.
""" """
......
...@@ -38430,6 +38430,16 @@ ...@@ -38430,6 +38430,16 @@
"ofType": null "ofType": null
}, },
"defaultValue": null "defaultValue": null
},
{
"name": "assigneeUsername",
"description": "Username of a user assigned to the issue",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
} }
], ],
"type": { "type": {
...@@ -38453,6 +38463,16 @@ ...@@ -38453,6 +38463,16 @@
"ofType": null "ofType": null
}, },
"defaultValue": null "defaultValue": null
},
{
"name": "assigneeUsername",
"description": "Username of a user assigned to the issue",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
} }
], ],
"type": { "type": {
...@@ -38515,6 +38535,16 @@ ...@@ -38515,6 +38535,16 @@
}, },
"defaultValue": null "defaultValue": null
}, },
{
"name": "assigneeUsername",
"description": "Username of a user assigned to the issue",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{ {
"name": "after", "name": "after",
"description": "Returns the elements in the list that come after the specified cursor.", "description": "Returns the elements in the list that come after the specified cursor.",
...@@ -191,12 +191,12 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do ...@@ -191,12 +191,12 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
end end
end end
end end
end
context 'search query given' do context 'search query given' do
let_it_be(:alert) do let_it_be(:alert) do
create(:alert_management_alert, create(:alert_management_alert,
:with_fingerprint, :with_fingerprint,
project: project,
title: 'Title', title: 'Title',
description: 'Desc', description: 'Desc',
service: 'Service', service: 'Service',
...@@ -204,12 +204,6 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do ...@@ -204,12 +204,6 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
) )
end end
before do
alert.project.add_developer(current_user)
end
subject { described_class.new(current_user, alert.project, params).execute }
context 'searching title' do context 'searching title' do
let(:params) { { search: alert.title } } let(:params) { { search: alert.title } }
...@@ -243,8 +237,33 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do ...@@ -243,8 +237,33 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
context 'empty search' do context 'empty search' do
let(:params) { { search: ' ' } } let(:params) { { search: ' ' } }
it { is_expected.not_to include(alert) }
end
end
context 'assignee username given' do
let_it_be(:assignee) { create(:user) }
let_it_be(:alert) { create(:alert_management_alert, project: project, assignees: [assignee]) }
let(:params) { { assignee_username: username } }
context 'with valid assignee_username' do
let(:username) { assignee.username }
it { is_expected.to match_array([alert]) } it { is_expected.to match_array([alert]) }
end end
context 'with invalid assignee_username' do
let(:username) { 'unknown username' }
it { is_expected.to be_empty }
end
context 'with empty assignee_username' do
let(:username) { ' ' }
it { is_expected.not_to include(alert) }
end
end
end end
end end
......
...@@ -230,6 +230,35 @@ RSpec.describe AlertManagement::Alert do ...@@ -230,6 +230,35 @@ RSpec.describe AlertManagement::Alert do
it { is_expected.to match_array(env_alert) } it { is_expected.to match_array(env_alert) }
end end
describe '.for_assignee_username' do
let_it_be(:alert) { triggered_alert }
let_it_be(:assignee) { create(:user) }
subject { AlertManagement::Alert.for_assignee_username(assignee_username) }
before_all do
alert.update!(assignees: [assignee])
end
context 'when matching assignee_username' do
let(:assignee_username) { assignee.username }
it { is_expected.to contain_exactly(alert) }
end
context 'when unknown assignee_username' do
let(:assignee_username) { 'unknown username' }
it { is_expected.to be_empty }
end
context 'with empty assignee_username' do
let(:assignee_username) { ' ' }
it { is_expected.to be_empty }
end
end
describe '.order_severity_with_open_prometheus_alert' do describe '.order_severity_with_open_prometheus_alert' do
subject { described_class.where(project: alert_project).order_severity_with_open_prometheus_alert } subject { described_class.where(project: alert_project).order_severity_with_open_prometheus_alert }
......
...@@ -139,6 +139,19 @@ RSpec.describe 'getting Alert Management Alerts' do ...@@ -139,6 +139,19 @@ RSpec.describe 'getting Alert Management Alerts' do
it { expect(alerts.size).to eq(0) } it { expect(alerts.size).to eq(0) }
end end
end end
context 'assignee_username' do
let(:alert) { triggered_alert }
let(:assignee) { alert.assignees.first! }
let(:params) { { assignee_username: assignee.username } }
it_behaves_like 'a working graphql query'
specify do
expect(alerts.size).to eq(1)
expect(first_alert['iid']).to eq(alert.iid.to_s)
end
end
end end
end end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment