Commit 2e89e796 authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Merge branch '338667-initialize-relative-positions-of-issues-appearing-in-board-list' into 'master'

Update relative positions on querying board issues

See merge request gitlab-org/gitlab!68715
parents 51f59fb5 4786e97f
...@@ -27,9 +27,7 @@ module Boards ...@@ -27,9 +27,7 @@ module Boards
list_service = Boards::Issues::ListService.new(board_parent, current_user, filter_params) list_service = Boards::Issues::ListService.new(board_parent, current_user, filter_params)
issues = issues_from(list_service) issues = issues_from(list_service)
if Gitlab::Database.read_write? && !board.disabled_for?(current_user) ::Boards::Issues::ListService.initialize_relative_positions(board, current_user, issues)
Issue.move_nulls_to_end(issues)
end
render_issues(issues, list_service.metadata) render_issues(issues, list_service.metadata)
end end
......
...@@ -15,8 +15,11 @@ module Resolvers ...@@ -15,8 +15,11 @@ module Resolvers
def resolve(**args) def resolve(**args)
filter_params = item_filters(args[:filters]).merge(board_id: list.board.id, id: list.id) filter_params = item_filters(args[:filters]).merge(board_id: list.board.id, id: list.id)
service = ::Boards::Issues::ListService.new(list.board.resource_parent, context[:current_user], filter_params) service = ::Boards::Issues::ListService.new(list.board.resource_parent, context[:current_user], filter_params)
pagination_connections = Gitlab::Graphql::Pagination::Keyset::Connection.new(service.execute)
service.execute ::Boards::Issues::ListService.initialize_relative_positions(list.board, current_user, pagination_connections.items)
pagination_connections
end end
# https://gitlab.com/gitlab-org/gitlab/-/issues/235681 # https://gitlab.com/gitlab-org/gitlab/-/issues/235681
......
...@@ -9,6 +9,14 @@ module Boards ...@@ -9,6 +9,14 @@ module Boards
IssuesFinder.valid_params IssuesFinder.valid_params
end end
# It is a class method because we cannot apply it
# prior to knowing how many items should be fetched for a list.
def self.initialize_relative_positions(board, current_user, issues)
if Gitlab::Database.read_write? && !board.disabled_for?(current_user)
Issue.move_nulls_to_end(issues)
end
end
private private
def order(items) def order(items)
......
...@@ -134,6 +134,6 @@ RSpec.describe Resolvers::BoardListIssuesResolver do ...@@ -134,6 +134,6 @@ RSpec.describe Resolvers::BoardListIssuesResolver do
end end
def resolve_board_list_issues(args) def resolve_board_list_issues(args)
resolve(described_class, obj: list, args: args, ctx: { current_user: user }) resolve(described_class, obj: list, args: args, ctx: { current_user: user }).items
end end
end end
...@@ -20,18 +20,20 @@ RSpec.describe Resolvers::BoardListIssuesResolver do ...@@ -20,18 +20,20 @@ RSpec.describe Resolvers::BoardListIssuesResolver do
let!(:issue1) { create(:issue, project: project, labels: [label], relative_position: 10) } let!(:issue1) { create(:issue, project: project, labels: [label], relative_position: 10) }
let!(:issue2) { create(:issue, project: project, labels: [label, label2], relative_position: 12) } let!(:issue2) { create(:issue, project: project, labels: [label, label2], relative_position: 12) }
let!(:issue3) { create(:issue, project: project, labels: [label, label3], relative_position: 10) } let!(:issue3) { create(:issue, project: project, labels: [label, label3], relative_position: 10) }
let!(:issue4) { create(:issue, project: project, labels: [label], relative_position: nil) }
it 'returns the issues in the correct order' do it 'returns issues in the correct order with non-nil relative positions', :aggregate_failures do
# by relative_position and then ID # by relative_position and then ID
issues = resolve_board_list_issues result = resolve_board_list_issues
expect(issues.map(&:id)).to eq [issue3.id, issue1.id, issue2.id] expect(result.map(&:id)).to eq [issue3.id, issue1.id, issue2.id, issue4.id]
expect(result.map(&:relative_position)).not_to include(nil)
end end
it 'finds only issues matching filters' do it 'finds only issues matching filters' do
result = resolve_board_list_issues(args: { filters: { label_name: [label.title], not: { label_name: [label2.title] } } }) result = resolve_board_list_issues(args: { filters: { label_name: [label.title], not: { label_name: [label2.title] } } })
expect(result).to match_array([issue1, issue3]) expect(result).to match_array([issue1, issue3, issue4])
end end
it 'finds only issues matching search param' do it 'finds only issues matching search param' do
...@@ -49,7 +51,7 @@ RSpec.describe Resolvers::BoardListIssuesResolver do ...@@ -49,7 +51,7 @@ RSpec.describe Resolvers::BoardListIssuesResolver do
it 'accepts assignee wildcard id NONE' do it 'accepts assignee wildcard id NONE' do
result = resolve_board_list_issues(args: { filters: { assignee_wildcard_id: 'NONE' } }) result = resolve_board_list_issues(args: { filters: { assignee_wildcard_id: 'NONE' } })
expect(result).to match_array([issue1, issue2, issue3]) expect(result).to match_array([issue1, issue2, issue3, issue4])
end end
it 'accepts assignee wildcard id ANY' do it 'accepts assignee wildcard id ANY' do
...@@ -89,6 +91,6 @@ RSpec.describe Resolvers::BoardListIssuesResolver do ...@@ -89,6 +91,6 @@ RSpec.describe Resolvers::BoardListIssuesResolver do
end end
def resolve_board_list_issues(args: {}, current_user: user) def resolve_board_list_issues(args: {}, current_user: user)
resolve(described_class, obj: list, args: args, ctx: { current_user: current_user }) resolve(described_class, obj: list, args: args, ctx: { current_user: current_user }).items
end end
end end
...@@ -48,13 +48,18 @@ RSpec.describe 'get board lists' do ...@@ -48,13 +48,18 @@ RSpec.describe 'get board lists' do
issues_data.map { |i| i['title'] } issues_data.map { |i| i['title'] }
end end
def issue_relative_positions
issues_data.map { |i| i['relativePosition'] }
end
shared_examples 'group and project board list issues query' do shared_examples 'group and project board list issues query' do
let!(:board) { create(:board, resource_parent: board_parent) } let!(:board) { create(:board, resource_parent: board_parent) }
let!(:label_list) { create(:list, board: board, label: label, position: 10) } let!(:label_list) { create(:list, board: board, label: label, position: 10) }
let!(:issue1) { create(:issue, project: issue_project, labels: [label, label2], relative_position: 9) } let!(:issue1) { create(:issue, project: issue_project, labels: [label, label2], relative_position: 9) }
let!(:issue2) { create(:issue, project: issue_project, labels: [label, label2], relative_position: 2) } let!(:issue2) { create(:issue, project: issue_project, labels: [label, label2], relative_position: 2) }
let!(:issue3) { create(:issue, project: issue_project, labels: [label], relative_position: 9) } let!(:issue3) { create(:issue, project: issue_project, labels: [label, label2], relative_position: nil) }
let!(:issue4) { create(:issue, project: issue_project, labels: [label2], relative_position: 432) } let!(:issue4) { create(:issue, project: issue_project, labels: [label], relative_position: 9) }
let!(:issue5) { create(:issue, project: issue_project, labels: [label2], relative_position: 432) }
context 'when the user does not have access to the board' do context 'when the user does not have access to the board' do
it 'returns nil' do it 'returns nil' do
...@@ -69,10 +74,11 @@ RSpec.describe 'get board lists' do ...@@ -69,10 +74,11 @@ RSpec.describe 'get board lists' do
board_parent.add_reporter(user) board_parent.add_reporter(user)
end end
it 'can access the issues' do it 'can access the issues', :aggregate_failures do
post_graphql(query("id: \"#{global_id_of(label_list)}\""), current_user: user) post_graphql(query("id: \"#{global_id_of(label_list)}\""), current_user: user)
expect(issue_titles).to eq([issue2.title, issue1.title]) expect(issue_titles).to eq([issue2.title, issue1.title, issue3.title])
expect(issue_relative_positions).not_to include(nil)
end end
end end
end end
......
...@@ -139,4 +139,51 @@ RSpec.describe Boards::Issues::ListService do ...@@ -139,4 +139,51 @@ RSpec.describe Boards::Issues::ListService do
end end
# rubocop: enable RSpec/MultipleMemoizedHelpers # rubocop: enable RSpec/MultipleMemoizedHelpers
end end
describe '.initialize_relative_positions' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :empty_repo) }
let_it_be(:board) { create(:board, project: project) }
let_it_be(:backlog) { create(:backlog_list, board: board) }
let(:issue) { create(:issue, project: project, relative_position: nil) }
context "when 'Gitlab::Database::read_write?' is true" do
before do
allow(Gitlab::Database).to receive(:read_write?).and_return(true)
end
context 'user cannot move issues' do
it 'does not initialize the relative positions of issues' do
described_class.initialize_relative_positions(board, user, [issue])
expect(issue.relative_position).to eq nil
end
end
context 'user can move issues' do
before do
project.add_developer(user)
end
it 'initializes the relative positions of issues' do
described_class.initialize_relative_positions(board, user, [issue])
expect(issue.relative_position).not_to eq nil
end
end
end
context "when 'Gitlab::Database::read_write?' is false" do
before do
allow(Gitlab::Database).to receive(:read_write?).and_return(false)
end
it 'does not initialize the relative positions of issues' do
described_class.initialize_relative_positions(board, user, [issue])
expect(issue.relative_position).to eq nil
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