Commit b2894eed authored by Igor Drozdov's avatar Igor Drozdov

Merge branch '233307-update-and-expose-board-labels' into 'master'

Update and expose board labels in graphql

See merge request gitlab-org/gitlab!44204
parents 7ea32c5d 02b38723
......@@ -1072,6 +1072,31 @@ type Board {
"""
id: ID!
"""
Labels of the board
"""
labels(
"""
Returns the elements in the list that come after the specified cursor.
"""
after: String
"""
Returns the elements in the list that come before the specified cursor.
"""
before: String
"""
Returns the first _n_ elements from the list.
"""
first: Int
"""
Returns the last _n_ elements from the list.
"""
last: Int
): LabelConnection
"""
Lists of the board
"""
......@@ -18763,6 +18788,16 @@ input UpdateBoardInput {
"""
id: ID!
"""
The IDs of labels to be added to the board.
"""
labelIds: [LabelID!]
"""
Labels of the issue
"""
labels: [String!]
"""
The id of milestone to be assigned to the board.
"""
......
......@@ -2840,6 +2840,59 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "labels",
"description": "Labels of the board",
"args": [
{
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "before",
"description": "Returns the elements in the list that come before the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "first",
"description": "Returns the first _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
},
{
"name": "last",
"description": "Returns the last _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "LabelConnection",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "lists",
"description": "Lists of the board",
......@@ -54769,6 +54822,42 @@
},
"defaultValue": null
},
{
"name": "labels",
"description": "Labels of the issue",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
},
"defaultValue": null
},
{
"name": "labelIds",
"description": "The IDs of labels to be added to the board.",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "LabelID",
"ofType": null
}
}
},
"defaultValue": null
},
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
......@@ -9,8 +9,10 @@ module EE
field :assignee, type: ::Types::UserType, null: true,
description: 'The board assignee.'
field :milestone, type: ::Types::MilestoneType, null: true,
description: 'The board milestone.'
field :epics, ::Types::Boards::BoardEpicType.connection_type, null: true,
description: 'Epics associated with board issues.',
resolver: ::Resolvers::BoardGroupings::EpicsResolver,
complexity: 5
field :hide_backlog_list, type: GraphQL::BOOLEAN_TYPE, null: true,
description: 'Whether or not backlog list is hidden.'
......@@ -18,13 +20,14 @@ module EE
field :hide_closed_list, type: GraphQL::BOOLEAN_TYPE, null: true,
description: 'Whether or not closed list is hidden.'
field :labels, ::Types::LabelType.connection_type, null: true,
description: 'Labels of the board'
field :milestone, type: ::Types::MilestoneType, null: true,
description: 'The board milestone.'
field :weight, type: GraphQL::INT_TYPE, null: true,
description: 'Weight of the board.'
field :epics, ::Types::Boards::BoardEpicType.connection_type, null: true,
description: 'Epics associated with board issues.',
resolver: ::Resolvers::BoardGroupings::EpicsResolver,
complexity: 5
end
end
end
......
......@@ -41,6 +41,14 @@ module Mutations
required: false,
description: 'The weight value to be assigned to the board.'
argument :labels, [GraphQL::STRING_TYPE],
required: false,
description: copy_field_description(Types::IssueType, :labels)
argument :label_ids, [::Types::GlobalIDType[::Label]],
required: false,
description: 'The IDs of labels to be added to the board.'
field :board,
Types::BoardType,
null: true,
......@@ -61,6 +69,15 @@ module Mutations
}
end
def ready?(**args)
if args.slice(*mutually_exclusive_args).size > 1
arg_str = mutually_exclusive_args.map { |x| x.to_s.camelize(:lower) }.join(' or ')
raise Gitlab::Graphql::Errors::ArgumentError, "one and only one of #{arg_str} is required"
end
super
end
private
def find_object(id:)
......@@ -76,8 +93,16 @@ module Mutations
args[:milestone_id] = GitlabSchema.parse_gid(args[:milestone_id], expected_type: ::Milestone).model_id
end
args[:label_ids] &&= args[:label_ids].map do |label_id|
::GitlabSchema.parse_gid(label_id, expected_type: ::Label).model_id
end
args
end
def mutually_exclusive_args
[:labels, :label_ids]
end
end
end
end
---
title: Update and expose board labels trough GraphQL API
merge_request: 44204
author:
type: added
......@@ -4,6 +4,8 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['Board'] do
it 'includes the ee specific fields' do
expect(described_class).to have_graphql_fields(:weight, :epics).at_least
expect(described_class).to have_graphql_fields(
:assignee, :epics, :hide_backlog_list, :hide_closed_list, :labels, :milestone, :weight
).at_least
end
end
......@@ -7,26 +7,31 @@ RSpec.describe Mutations::Boards::Update do
let_it_be(:user) { create(:user) }
let_it_be(:board) { create(:board, project: project) }
let_it_be(:milestone) { create(:milestone, project: project) }
let_it_be(:label1) { create(:label, project: project) }
let_it_be(:label2) { create(:label, project: project) }
let(:new_labels) { %w(new_label1 new_label2) }
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
let(:mutated_board) { subject[:board] }
specify { expect(described_class).to require_graphql_authorizations(:admin_board) }
let(:mutation_params) do
{
id: board.to_global_id,
name: 'Test board 1',
hide_backlog_list: true,
hide_closed_list: true,
weight: 3,
assignee_id: user.to_global_id,
milestone_id: milestone.to_global_id,
label_ids: [label1.to_global_id, label2.to_global_id]
}
end
describe '#resolve' do
let(:mutation_params) do
{
id: board.to_global_id,
name: 'Test board 1',
hide_backlog_list: true,
hide_closed_list: true,
weight: 3,
assignee_id: user.to_global_id,
milestone_id: milestone.to_global_id
}
end
subject { mutation.resolve(mutation_params) }
subject { mutation.resolve(mutation_params) }
specify { expect(described_class).to require_graphql_authorizations(:admin_board) }
describe '#resolve' do
context 'when the user cannot admin the board' do
it 'raises an error' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
......@@ -45,13 +50,40 @@ RSpec.describe Mutations::Boards::Update do
hide_closed_list: true,
weight: 3,
assignee: user,
milestone: milestone
milestone: milestone,
labels: [label1, label2]
}
subject
expect(board.reload).to have_attributes(expected_attributes)
end
context 'when passing labels param' do
before do
mutation_params.delete(:label_ids)
mutation_params.merge!(labels: new_labels)
end
it 'updates board with correct labels' do
subject
expect(board.reload.labels.pluck(:title)).to eq(new_labels)
end
end
end
end
describe '#ready' do
context 'when passing both labels & label_ids param' do
before do
mutation_params.merge!(labels: new_labels)
end
it 'raises exception when mutually exclusive params are given' do
expect { mutation.ready?(mutation_params) }
.to raise_error(Gitlab::Graphql::Errors::ArgumentError, /one and only one of/)
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