Commit f7bb2b1d authored by Sarah Yasonik's avatar Sarah Yasonik Committed by Tiger Watson

Add ability to search for an escalation policy by name

This adds a name argument to the escalationPolicies field
on projects, which allows a caller to provide a string
to search through escalation policies. Utility is limited
in the moment, as only one escalation policy is available
on each project, but that will change in future.

This change is needed to easily take advantage of shared
sidebar components in the UI.

Changelog: added
EE: true
parent b9f94fae
......@@ -13297,7 +13297,6 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="projecthttpurltorepo"></a>`httpUrlToRepo` | [`String`](#string) | URL to connect to the project via HTTPS. |
| <a id="projectid"></a>`id` | [`ID!`](#id) | ID of the project. |
| <a id="projectimportstatus"></a>`importStatus` | [`String`](#string) | Status of import background job of the project. |
| <a id="projectincidentmanagementescalationpolicies"></a>`incidentManagementEscalationPolicies` | [`EscalationPolicyTypeConnection`](#escalationpolicytypeconnection) | Incident Management escalation policies of the project. (see [Connections](#connections)) |
| <a id="projectissuesenabled"></a>`issuesEnabled` | [`Boolean`](#boolean) | Indicates if Issues are enabled for the current user. |
| <a id="projectjiraimportstatus"></a>`jiraImportStatus` | [`String`](#string) | Status of Jira import background job of the project. |
| <a id="projectjiraimports"></a>`jiraImports` | [`JiraImportConnection`](#jiraimportconnection) | Jira imports into the project. (see [Connections](#connections)) |
......@@ -13606,6 +13605,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectenvironmentssearch"></a>`search` | [`String`](#string) | Search query for environment name. |
| <a id="projectenvironmentsstates"></a>`states` | [`[String!]`](#string) | States of environments that should be included in result. |
##### `Project.incidentManagementEscalationPolicies`
Incident Management escalation policies of the project.
Returns [`EscalationPolicyTypeConnection`](#escalationpolicytypeconnection).
This field returns a [connection](#connections). It accepts the
four standard [pagination arguments](#connection-pagination-arguments):
`before: String`, `after: String`, `first: Int`, `last: Int`.
###### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectincidentmanagementescalationpoliciesname"></a>`name` | [`String`](#string) | Fuzzy search by escalation policy name. |
##### `Project.incidentManagementEscalationPolicy`
Incident Management escalation policy of the project.
......@@ -13617,6 +13632,7 @@ Returns [`EscalationPolicyType`](#escalationpolicytype).
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectincidentmanagementescalationpolicyid"></a>`id` | [`IncidentManagementEscalationPolicyID!`](#incidentmanagementescalationpolicyid) | ID of the escalation policy. |
| <a id="projectincidentmanagementescalationpolicyname"></a>`name` | [`String`](#string) | Fuzzy search by escalation policy name. |
##### `Project.incidentManagementOncallSchedules`
......@@ -12,6 +12,7 @@ module IncidentManagement
return IncidentManagement::EscalationPolicy.none unless allowed?
collection = project.incident_management_escalation_policies
collection = by_name_search(collection)
by_id(collection)
end
......@@ -28,5 +29,11 @@ module IncidentManagement
collection.id_in(params[:id])
end
def by_name_search(collection)
return collection unless params[:name_search].present?
collection.search_by_name(params[:name_search])
end
end
end
......@@ -9,6 +9,11 @@ module Resolvers
type Types::IncidentManagement::EscalationPolicyType.connection_type, null: true
argument :name,
GraphQL::Types::String,
required: false,
description: 'Fuzzy search by escalation policy name.'
when_single do
argument :id,
::Types::GlobalIDType[::IncidentManagement::EscalationPolicy],
......@@ -17,10 +22,16 @@ module Resolvers
prepare: ->(id, ctx) { id.model_id }
end
def resolve_with_lookahead(**args)
def resolve_with_lookahead(name: nil, **args)
context[:execution_time] = Time.current
apply_lookahead(::IncidentManagement::EscalationPoliciesFinder.new(current_user, project, args).execute)
apply_lookahead(
::IncidentManagement::EscalationPoliciesFinder.new(
current_user,
project,
{ name_search: name, **args }
).execute
)
end
private
......
......@@ -2,6 +2,8 @@
module IncidentManagement
class EscalationPolicy < ApplicationRecord
include Gitlab::SQL::Pattern
self.table_name = 'incident_management_escalation_policies'
belongs_to :project
......@@ -13,6 +15,7 @@ module IncidentManagement
validates :description, length: { maximum: 160 }
scope :for_project, -> (project) { where(project: project) }
scope :search_by_name, -> (query) { fuzzy_search(query, [:name]) }
accepts_nested_attributes_for :rules
......
......@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe IncidentManagement::EscalationPoliciesFinder do
let_it_be(:current_user) { create(:user) }
let_it_be_with_refind(:project) { create(:project) }
let_it_be(:escalation_policy) { create(:incident_management_escalation_policy, project: project) }
let_it_be(:escalation_policy) { create(:incident_management_escalation_policy, project: project, name: 'unique identifier') }
let_it_be(:escalation_policy_from_another_project) { create(:incident_management_escalation_policy) }
let(:params) { {} }
......@@ -32,6 +32,18 @@ RSpec.describe IncidentManagement::EscalationPoliciesFinder do
it { is_expected.to contain_exactly(escalation_policy) }
end
context 'when search_name is given' do
let(:params) { { name_search: 'ique iden' } }
it { is_expected.to contain_exactly(escalation_policy) }
context 'when the name does not match' do
let(:params) { { name_search: 'not a matching search' } }
it { is_expected.to eq(IncidentManagement::EscalationPolicy.none) }
end
end
end
context 'when user has no permissions' do
......
......@@ -7,7 +7,8 @@ RSpec.describe Resolvers::IncidentManagement::EscalationPoliciesResolver do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:policy) { create(:incident_management_escalation_policy, project: project) }
let_it_be(:policy) { create(:incident_management_escalation_policy, project: project, name: 'Target policy') }
let_it_be(:other_policy) { create(:incident_management_escalation_policy) }
let(:args) { {} }
let(:resolver) { described_class }
......@@ -29,6 +30,16 @@ RSpec.describe Resolvers::IncidentManagement::EscalationPoliciesResolver do
expect(resolved_policies.first).to have_attributes(id: policy.id)
end
context 'with name param provided' do
let(:args) { { name: 'target' } }
it 'returns escalation policies matching the name search' do
expect(resolved_policies.length).to eq(1)
expect(resolved_policies.first).to be_a(::IncidentManagement::EscalationPolicy)
expect(resolved_policies.first).to have_attributes(id: policy.id)
end
end
context 'when resolving a single item' do
let(:resolver) { described_class.single }
......
......@@ -38,12 +38,18 @@ RSpec.describe IncidentManagement::EscalationPolicy do
describe 'scopes' do
let_it_be(:project) { create(:project) }
let_it_be(:policy) { create(:incident_management_escalation_policy, project: project) }
let_it_be(:other_policy) { create(:incident_management_escalation_policy) }
let_it_be(:other_policy) { create(:incident_management_escalation_policy, name: 'Other policy') }
describe '.for_project' do
subject { described_class.for_project(project) }
it { is_expected.to contain_exactly(policy) }
end
describe '.search_by_name' do
subject { described_class.search_by_name('other') }
it { is_expected.to contain_exactly(other_policy) }
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