Commit 9c61110c authored by Jonathan Schafer's avatar Jonathan Schafer

Search by namespace from Global Security Dashboard

When searching for projects, this MR adds the ability to search
by namespace as well as project name.
parent 58f318e0
......@@ -16,6 +16,10 @@ module Resolvers
required: false,
description: 'Filter projects by IDs'
argument :search_namespaces, GraphQL::BOOLEAN_TYPE,
required: false,
description: 'Include namespace in project search'
def resolve(**args)
ProjectsFinder
.new(current_user: current_user, params: project_finder_params(args), project_ids_relation: parse_gids(args[:ids]))
......@@ -28,7 +32,8 @@ module Resolvers
{
without_deleted: true,
non_public: params[:membership],
search: params[:search]
search: params[:search],
search_namespaces: params[:search_namespaces]
}.compact
end
......
......@@ -14023,6 +14023,11 @@ type Query {
Search query for project name, path, or description
"""
search: String
"""
Include namespace in project search
"""
searchNamespaces: Boolean
): ProjectConnection
"""
......
......@@ -41107,6 +41107,16 @@
},
"defaultValue": null
},
{
"name": "searchNamespaces",
"description": "Include namespace in project search",
"type": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
},
"defaultValue": null
},
{
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
......@@ -222,6 +222,7 @@ export default {
search: searchQuery,
first: this.$options.PROJECTS_PER_PAGE,
after: pageInfo.endCursor,
searchNamespaces: true,
},
});
},
......
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
#import "ee/security_dashboard/graphql/project.fragment.graphql"
query getProjects($search: String!, $after: String = "", $first: Int!) {
projects(search: $search, after: $after, first: $first, membership: true) {
query getProjects(
$search: String!
$after: String = ""
$first: Int!
$searchNamespaces: Boolean = false
) {
projects(
search: $search
after: $after
first: $first
membership: true
searchNamespaces: $searchNamespaces
) {
nodes {
...Project
}
......
---
title: Search projects by namespace from Global Security Dashboard
merge_request: 41191
author:
type: changed
......@@ -86,6 +86,7 @@ describe('Project Manager component', () => {
search: 'test',
first: wrapper.vm.$options.PROJECTS_PER_PAGE,
after: '',
searchNamespaces: true,
},
});
});
......
......@@ -8,10 +8,15 @@ RSpec.describe Resolvers::ProjectsResolver do
describe '#resolve' do
subject { resolve(described_class, obj: nil, args: filters, ctx: { current_user: current_user }) }
let_it_be(:group) { create(:group, name: 'public-group') }
let_it_be(:private_group) { create(:group, name: 'private-group') }
let_it_be(:project) { create(:project, :public) }
let_it_be(:other_project) { create(:project, :public) }
let_it_be(:group_project) { create(:project, :public, group: group) }
let_it_be(:private_project) { create(:project, :private) }
let_it_be(:other_private_project) { create(:project, :private) }
let_it_be(:other_private_project) { create(:project, :private) }
let_it_be(:private_group_project) { create(:project, :private, group: private_group) }
let_it_be(:user) { create(:user) }
......@@ -20,6 +25,7 @@ RSpec.describe Resolvers::ProjectsResolver do
before_all do
project.add_developer(user)
private_project.add_developer(user)
private_group.add_developer(user)
end
context 'when user is not logged in' do
......@@ -27,7 +33,7 @@ RSpec.describe Resolvers::ProjectsResolver do
context 'when no filters are applied' do
it 'returns all public projects' do
is_expected.to contain_exactly(project, other_project)
is_expected.to contain_exactly(project, other_project, group_project)
end
context 'when search filter is provided' do
......@@ -45,6 +51,22 @@ RSpec.describe Resolvers::ProjectsResolver do
is_expected.to be_empty
end
end
context 'when searchNamespaces filter is provided' do
let(:filters) { { search: 'group', search_namespaces: true } }
it 'returns projects in a matching namespace' do
is_expected.to contain_exactly(group_project)
end
end
context 'when searchNamespaces filter false' do
let(:filters) { { search: 'group', search_namespaces: false } }
it 'returns ignores namespace matches' do
is_expected.to be_empty
end
end
end
end
......@@ -53,7 +75,7 @@ RSpec.describe Resolvers::ProjectsResolver do
context 'when no filters are applied' do
it 'returns all visible projects for the user' do
is_expected.to contain_exactly(project, other_project, private_project)
is_expected.to contain_exactly(project, other_project, group_project, private_project, private_group_project)
end
context 'when search filter is provided' do
......@@ -68,7 +90,23 @@ RSpec.describe Resolvers::ProjectsResolver do
let(:filters) { { membership: true } }
it 'returns projects that user is member of' do
is_expected.to contain_exactly(project, private_project)
is_expected.to contain_exactly(project, private_project, private_group_project)
end
end
context 'when searchNamespaces filter is provided' do
let(:filters) { { search: 'group', search_namespaces: true } }
it 'returns projects from matching group' do
is_expected.to contain_exactly(group_project, private_group_project)
end
end
context 'when searchNamespaces filter false' do
let(:filters) { { search: 'group', search_namespaces: false } }
it 'returns ignores namespace matches' do
is_expected.to be_empty
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