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
collection = project.alert_management_alerts
collection = by_status(collection)
collection = by_search(collection)
collection = by_iid(collection)
collection = by_assignee(collection)
collection = by_search(collection)
sort(collection)
end
......@@ -48,6 +50,10 @@ module AlertManagement
params[:sort] ? collection.sort_by_attribute(params[:sort]) : collection
end
def by_assignee(collection)
params[:assignee_username].present? ? collection.for_assignee_username(params[:assignee_username]) : collection
end
def authorized?
Ability.allowed?(current_user, :read_alert_management_alert, project)
end
......
......@@ -22,6 +22,10 @@ module Resolvers
description: 'Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.',
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
def resolve_with_lookahead(**args)
......
......@@ -9,6 +9,10 @@ module Resolvers
description: 'Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.',
required: false
argument :assignee_username, GraphQL::STRING_TYPE,
required: false,
description: 'Username of a user assigned to the issue'
def resolve(**args)
::Gitlab::AlertManagement::AlertStatusCounts.new(context[:current_user], object, args)
end
......
......@@ -113,6 +113,7 @@ module AlertManagement
scope :for_status, -> (status) { with_status(status) }
scope :for_fingerprint, -> (project, fingerprint) { where(project: project, fingerprint: fingerprint) }
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 :open, -> { with_status(open_statuses) }
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 {
A single Alert Management alert of the project
"""
alertManagementAlert(
"""
Username of a user assigned to the issue
"""
assigneeUsername: String
"""
IID of the alert. For example, "1"
"""
......@@ -13027,6 +13032,11 @@ type Project {
Counts of alerts by status for the project
"""
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.
"""
......@@ -13042,6 +13052,11 @@ type Project {
"""
after: String
"""
Username of a user assigned to the issue
"""
assigneeUsername: String
"""
Returns the elements in the list that come before the specified cursor.
"""
......
......@@ -38430,6 +38430,16 @@
"ofType": null
},
"defaultValue": null
},
{
"name": "assigneeUsername",
"description": "Username of a user assigned to the issue",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
}
],
"type": {
......@@ -38453,6 +38463,16 @@
"ofType": null
},
"defaultValue": null
},
{
"name": "assigneeUsername",
"description": "Username of a user assigned to the issue",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
}
],
"type": {
......@@ -38515,6 +38535,16 @@
},
"defaultValue": null
},
{
"name": "assigneeUsername",
"description": "Username of a user assigned to the issue",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
......@@ -191,59 +191,78 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
end
end
end
end
context 'search query given' do
let_it_be(:alert) do
create(:alert_management_alert,
:with_fingerprint,
title: 'Title',
description: 'Desc',
service: 'Service',
monitoring_tool: 'Monitor'
)
end
context 'search query given' do
let_it_be(:alert) do
create(:alert_management_alert,
:with_fingerprint,
project: project,
title: 'Title',
description: 'Desc',
service: 'Service',
monitoring_tool: 'Monitor'
)
end
before do
alert.project.add_developer(current_user)
end
context 'searching title' do
let(:params) { { search: alert.title } }
subject { described_class.new(current_user, alert.project, params).execute }
it { is_expected.to match_array([alert]) }
end
context 'searching title' do
let(:params) { { search: alert.title } }
context 'searching description' do
let(:params) { { search: alert.description } }
it { is_expected.to match_array([alert]) }
end
it { is_expected.to match_array([alert]) }
end
context 'searching description' do
let(:params) { { search: alert.description } }
context 'searching service' do
let(:params) { { search: alert.service } }
it { is_expected.to match_array([alert]) }
end
it { is_expected.to match_array([alert]) }
end
context 'searching service' do
let(:params) { { search: alert.service } }
context 'searching monitoring tool' do
let(:params) { { search: alert.monitoring_tool } }
it { is_expected.to match_array([alert]) }
end
it { is_expected.to match_array([alert]) }
end
context 'searching monitoring tool' do
let(:params) { { search: alert.monitoring_tool } }
context 'searching something else' do
let(:params) { { search: alert.fingerprint } }
it { is_expected.to match_array([alert]) }
end
it { is_expected.to be_empty }
end
context 'searching something else' do
let(:params) { { search: alert.fingerprint } }
context 'empty search' do
let(:params) { { search: ' ' } }
it { is_expected.to be_empty }
it { is_expected.not_to include(alert) }
end
end
context 'empty search' do
let(:params) { { search: ' ' } }
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]) }
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.to match_array([alert]) }
it { is_expected.not_to include(alert) }
end
end
end
end
......
......@@ -230,6 +230,35 @@ RSpec.describe AlertManagement::Alert do
it { is_expected.to match_array(env_alert) }
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
subject { described_class.where(project: alert_project).order_severity_with_open_prometheus_alert }
......
......@@ -139,6 +139,19 @@ RSpec.describe 'getting Alert Management Alerts' do
it { expect(alerts.size).to eq(0) }
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
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