Commit a11a84ec authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '235676-it-s-hard-to-add-a-project-to-the-instance-security-dashboard' into 'master'

Search by namespace in Security Dashboard

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