summaryrefslogtreecommitdiff
path: root/app/graphql/types
diff options
context:
space:
mode:
Diffstat (limited to 'app/graphql/types')
-rw-r--r--app/graphql/types/alert_management/alert_type.rb10
-rw-r--r--app/graphql/types/base_field.rb7
-rw-r--r--app/graphql/types/ci/config_variable_type.rb1
-rw-r--r--app/graphql/types/ci/freeze_period_status_enum.rb13
-rw-r--r--app/graphql/types/ci/freeze_period_type.rb41
-rw-r--r--app/graphql/types/ci/pipeline_schedule_type.rb46
-rw-r--r--app/graphql/types/ci/pipeline_schedule_variable_type.rb13
-rw-r--r--app/graphql/types/ci/pipeline_type.rb2
-rw-r--r--app/graphql/types/ci/runner_job_execution_status_enum.rb19
-rw-r--r--app/graphql/types/ci/runner_type.rb93
-rw-r--r--app/graphql/types/commit_signature_interface.rb5
-rw-r--r--app/graphql/types/commit_signatures/gpg_signature_type.rb1
-rw-r--r--app/graphql/types/commit_signatures/ssh_signature_type.rb23
-rw-r--r--app/graphql/types/commit_signatures/x509_signature_type.rb1
-rw-r--r--app/graphql/types/container_repository_type.rb2
-rw-r--r--app/graphql/types/dependency_proxy/manifest_type.rb2
-rw-r--r--app/graphql/types/deployment_details_type.rb17
-rw-r--r--app/graphql/types/deployment_type.rb18
-rw-r--r--app/graphql/types/environment_type.rb11
-rw-r--r--app/graphql/types/global_id_type.rb4
-rw-r--r--app/graphql/types/group_connection.rb22
-rw-r--r--app/graphql/types/issue_type_enum.rb4
-rw-r--r--app/graphql/types/key_type.rb17
-rw-r--r--app/graphql/types/merge_request_type.rb4
-rw-r--r--app/graphql/types/mutation_type.rb4
-rw-r--r--app/graphql/types/nested_environment_type.rb28
-rw-r--r--app/graphql/types/notes/note_type.rb8
-rw-r--r--app/graphql/types/packages/package_links_type.rb2
-rw-r--r--app/graphql/types/permission_types/base_permission_type.rb8
-rw-r--r--app/graphql/types/permission_types/deployment.rb14
-rw-r--r--app/graphql/types/permission_types/environment.rb11
-rw-r--r--app/graphql/types/permission_types/project.rb3
-rw-r--r--app/graphql/types/project_statistics_type.rb8
-rw-r--r--app/graphql/types/project_type.rb31
-rw-r--r--app/graphql/types/projects/fork_details_type.rb20
-rw-r--r--app/graphql/types/query_type.rb2
-rw-r--r--app/graphql/types/release_type.rb10
-rw-r--r--app/graphql/types/root_storage_statistics_type.rb2
-rw-r--r--app/graphql/types/subscription_type.rb5
-rw-r--r--app/graphql/types/todo_action_enum.rb3
-rw-r--r--app/graphql/types/todo_type.rb6
-rw-r--r--app/graphql/types/user_interface.rb5
-rw-r--r--app/graphql/types/work_items/notes_filter_type_enum.rb20
-rw-r--r--app/graphql/types/work_items/widget_interface.rb5
-rw-r--r--app/graphql/types/work_items/widgets/hierarchy_type.rb23
-rw-r--r--app/graphql/types/work_items/widgets/notes_type.rb26
46 files changed, 506 insertions, 114 deletions
diff --git a/app/graphql/types/alert_management/alert_type.rb b/app/graphql/types/alert_management/alert_type.rb
index a0d19229d3d..a13453f9194 100644
--- a/app/graphql/types/alert_management/alert_type.rb
+++ b/app/graphql/types/alert_management/alert_type.rb
@@ -13,6 +13,11 @@ module Types
authorize :read_alert_management_alert
+ field :id,
+ GraphQL::Types::ID,
+ null: false,
+ description: 'ID of the alert.'
+
field :iid,
GraphQL::Types::ID,
null: false,
@@ -116,7 +121,10 @@ module Types
null: true,
description: 'Runbook for the alert as defined in alert details.'
- field :todos, description: 'To-do items of the current user for the alert.', resolver: Resolvers::TodosResolver
+ field :todos,
+ Types::TodoType.connection_type,
+ description: 'To-do items of the current user for the alert.',
+ resolver: Resolvers::TodosResolver
field :details_url,
GraphQL::Types::String,
diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb
index 36ba3399754..615c143a0b9 100644
--- a/app/graphql/types/base_field.rb
+++ b/app/graphql/types/base_field.rb
@@ -135,15 +135,16 @@ module Types
:resolver_complexity, args, child_complexity: child_complexity
).to_i
complexity += 1 if calls_gitaly?
- complexity += complexity * connection_complexity_multiplier(ctx, args)
+ ext_conn = resolver&.try(:calculate_ext_conn_complexity)
+ complexity += complexity * connection_complexity_multiplier(ctx, args, calculate_ext_conn_complexity: ext_conn)
complexity.to_i
end
end
- def connection_complexity_multiplier(ctx, args)
+ def connection_complexity_multiplier(ctx, args, calculate_ext_conn_complexity:)
# Resolvers may add extra complexity depending on number of items being loaded.
- return 0 unless connection?
+ return 0 if !connection? && !calculate_ext_conn_complexity
page_size = max_page_size || ctx.schema.default_max_page_size
limit_value = [args[:first], args[:last], page_size].compact.min
diff --git a/app/graphql/types/ci/config_variable_type.rb b/app/graphql/types/ci/config_variable_type.rb
index 5b5890fd5a5..020af5b2444 100644
--- a/app/graphql/types/ci/config_variable_type.rb
+++ b/app/graphql/types/ci/config_variable_type.rb
@@ -19,6 +19,7 @@ module Types
description: 'Value of the variable.'
field :value_options, [GraphQL::Types::String],
+ hash_key: :options,
null: true,
description: 'Value options for the variable.'
end
diff --git a/app/graphql/types/ci/freeze_period_status_enum.rb b/app/graphql/types/ci/freeze_period_status_enum.rb
new file mode 100644
index 00000000000..aebd0f537e9
--- /dev/null
+++ b/app/graphql/types/ci/freeze_period_status_enum.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ class FreezePeriodStatusEnum < BaseEnum
+ graphql_name 'CiFreezePeriodStatus'
+ description 'Deploy freeze period status'
+
+ value 'ACTIVE', value: :active, description: 'Freeze period is active.'
+ value 'INACTIVE', value: :inactive, description: 'Freeze period is inactive.'
+ end
+ end
+end
diff --git a/app/graphql/types/ci/freeze_period_type.rb b/app/graphql/types/ci/freeze_period_type.rb
new file mode 100644
index 00000000000..6a3f2ed8fa4
--- /dev/null
+++ b/app/graphql/types/ci/freeze_period_type.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ class FreezePeriodType < BaseObject
+ graphql_name 'CiFreezePeriod'
+ description 'Represents a deployment freeze window of a project'
+
+ authorize :read_freeze_period
+
+ present_using ::Ci::FreezePeriodPresenter
+
+ field :status, Types::Ci::FreezePeriodStatusEnum,
+ description: 'Freeze period status.',
+ null: false
+
+ field :start_cron, GraphQL::Types::String,
+ description: 'Start of the freeze period in cron format.',
+ null: false,
+ method: :freeze_start
+
+ field :end_cron, GraphQL::Types::String,
+ description: 'End of the freeze period in cron format.',
+ null: false,
+ method: :freeze_end
+
+ field :cron_timezone, GraphQL::Types::String,
+ description: 'Time zone for the cron fields, defaults to UTC if not provided.',
+ null: true
+
+ field :start_time, Types::TimeType,
+ description: 'Timestamp (UTC) of when the current/next active period starts.',
+ null: true
+
+ field :end_time, Types::TimeType,
+ description: 'Timestamp (UTC) of when the current/next active period ends.',
+ null: true,
+ method: :time_end_from_now
+ end
+ end
+end
diff --git a/app/graphql/types/ci/pipeline_schedule_type.rb b/app/graphql/types/ci/pipeline_schedule_type.rb
index 04f9fc78a92..904fa3f1c72 100644
--- a/app/graphql/types/ci/pipeline_schedule_type.rb
+++ b/app/graphql/types/ci/pipeline_schedule_type.rb
@@ -5,6 +5,8 @@ module Types
class PipelineScheduleType < BaseObject
graphql_name 'PipelineSchedule'
+ description 'Represents a pipeline schedule'
+
connection_type_class(Types::CountableConnectionType)
expose_permissions Types::PermissionTypes::Ci::PipelineSchedules
@@ -17,7 +19,9 @@ module Types
field :owner, ::Types::UserType, null: false, description: 'Owner of the pipeline schedule.'
- field :active, GraphQL::Types::Boolean, null: false, description: 'Indicates if a pipeline schedule is active.'
+ field :active, GraphQL::Types::Boolean, null: false, description: 'Indicates if the pipeline schedule is active.'
+
+ field :project, ::Types::ProjectType, null: true, description: 'Project of the pipeline schedule.'
field :next_run_at, Types::TimeType, null: false, description: 'Time when the next pipeline will run.'
@@ -26,20 +30,50 @@ module Types
field :last_pipeline, PipelineType, null: true, description: 'Last pipeline object.'
field :ref_for_display, GraphQL::Types::String,
- null: true, description: 'Git ref for the pipeline schedule.', method: :ref_for_display
-
- field :ref_path, GraphQL::Types::String, null: true, description: 'Path to the ref that triggered the pipeline.'
+ null: true, description: 'Git ref for the pipeline schedule.'
field :for_tag, GraphQL::Types::Boolean,
null: false, description: 'Indicates if a pipelines schedule belongs to a tag.', method: :for_tag?
- field :cron, GraphQL::Types::String, null: false, description: 'Cron notation for the schedule.'
+ field :edit_path, GraphQL::Types::String,
+ null: true,
+ description: 'Edit path of the pipeline schedule.',
+ authorize: :update_pipeline_schedule
+
+ field :variables,
+ Types::Ci::PipelineScheduleVariableType.connection_type,
+ null: true,
+ description: 'Pipeline schedule variables.',
+ authorize: :read_pipeline_schedule_variables
+
+ field :ref, GraphQL::Types::String,
+ null: true, description: 'Ref of the pipeline schedule.', method: :ref_for_display
+
+ field :ref_path, GraphQL::Types::String,
+ null: true,
+ description: 'Path to the ref that triggered the pipeline.'
- field :cron_timezone, GraphQL::Types::String, null: false, description: 'Timezone for the pipeline schedule.'
+ field :cron, GraphQL::Types::String,
+ null: false,
+ description: 'Cron notation for the schedule.'
+
+ field :cron_timezone, GraphQL::Types::String,
+ null: false,
+ description: 'Timezone for the pipeline schedule.'
+
+ field :created_at, Types::TimeType,
+ null: false, description: 'Timestamp of when the pipeline schedule was created.'
+
+ field :updated_at, Types::TimeType,
+ null: false, description: 'Timestamp of when the pipeline schedule was last updated.'
def ref_path
::Gitlab::Routing.url_helpers.project_commits_path(object.project, object.ref_for_display)
end
+
+ def edit_path
+ ::Gitlab::Routing.url_helpers.edit_project_pipeline_schedule_path(object.project, object)
+ end
end
end
end
diff --git a/app/graphql/types/ci/pipeline_schedule_variable_type.rb b/app/graphql/types/ci/pipeline_schedule_variable_type.rb
new file mode 100644
index 00000000000..1cb407bc2e4
--- /dev/null
+++ b/app/graphql/types/ci/pipeline_schedule_variable_type.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ class PipelineScheduleVariableType < BaseObject
+ graphql_name 'PipelineScheduleVariable'
+
+ authorize :read_pipeline_schedule_variables
+
+ implements(VariableInterface)
+ end
+ end
+end
diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb
index 4a523f2edd9..cb561f48b3b 100644
--- a/app/graphql/types/ci/pipeline_type.rb
+++ b/app/graphql/types/ci/pipeline_type.rb
@@ -78,7 +78,7 @@ module Types
resolver: Resolvers::Ci::PipelineStagesResolver
field :user,
- type: Types::UserType,
+ type: 'Types::UserType',
null: true,
description: 'Pipeline user.'
diff --git a/app/graphql/types/ci/runner_job_execution_status_enum.rb b/app/graphql/types/ci/runner_job_execution_status_enum.rb
new file mode 100644
index 00000000000..686ea085199
--- /dev/null
+++ b/app/graphql/types/ci/runner_job_execution_status_enum.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ class RunnerJobExecutionStatusEnum < BaseEnum
+ graphql_name 'CiRunnerJobExecutionStatus'
+
+ value 'IDLE',
+ description: "Runner is idle.",
+ value: :idle,
+ deprecated: { milestone: '15.7', reason: :alpha }
+
+ value 'RUNNING',
+ description: 'Runner is executing jobs.',
+ value: :running,
+ deprecated: { milestone: '15.7', reason: :alpha }
+ end
+ end
+end
diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb
index a9c76974850..5d34906f7b8 100644
--- a/app/graphql/types/ci/runner_type.rb
+++ b/app/graphql/types/ci/runner_type.rb
@@ -23,6 +23,9 @@ module Types
deprecated: { reason: 'Use paused', milestone: '14.8' }
field :admin_url, GraphQL::Types::String, null: true,
description: 'Admin URL of the runner. Only available for administrators.'
+ field :architecture_name, GraphQL::Types::String, null: true,
+ description: 'Architecture provided by the the runner.',
+ method: :architecture
field :contacted_at, Types::TimeType, null: true,
description: 'Timestamp of last contact from this runner.',
method: :contacted_at
@@ -35,32 +38,39 @@ module Types
field :executor_name, GraphQL::Types::String, null: true,
description: 'Executor last advertised by the runner.',
method: :executor_name
- field :platform_name, GraphQL::Types::String, null: true,
- description: 'Platform provided by the runner.',
- method: :platform
- field :architecture_name, GraphQL::Types::String, null: true,
- description: 'Architecture provided by the the runner.',
- method: :architecture
- field :maintenance_note, GraphQL::Types::String, null: true,
- description: 'Runner\'s maintenance notes.'
- field :groups, ::Types::GroupType.connection_type, null: true,
- description: 'Groups the runner is associated with. For group runners only.'
+ field :groups, 'Types::GroupConnection',
+ null: true,
+ resolver: ::Resolvers::Ci::RunnerGroupsResolver,
+ description: 'Groups the runner is associated with. For group runners only.'
field :id, ::Types::GlobalIDType[::Ci::Runner], null: false,
description: 'ID of the runner.'
field :ip_address, GraphQL::Types::String, null: true,
description: 'IP address of the runner.'
field :job_count, GraphQL::Types::Int, null: true,
description: "Number of jobs processed by the runner (limited to #{JOB_COUNT_LIMIT}, plus one to indicate that more items exist)."
+ field :job_execution_status,
+ Types::Ci::RunnerJobExecutionStatusEnum,
+ null: true,
+ description: 'Job execution status of the runner.',
+ deprecated: { milestone: '15.7', reason: :alpha }
field :jobs, ::Types::Ci::JobType.connection_type, null: true,
description: 'Jobs assigned to the runner. This field can only be resolved for one runner in any single request.',
authorize: :read_builds,
resolver: ::Resolvers::Ci::RunnerJobsResolver
field :locked, GraphQL::Types::Boolean, null: true,
description: 'Indicates the runner is locked.'
+ field :maintenance_note, GraphQL::Types::String, null: true,
+ description: 'Runner\'s maintenance notes.'
field :maximum_timeout, GraphQL::Types::Int, null: true,
description: 'Maximum timeout (in seconds) for jobs processed by the runner.'
+ field :owner_project, ::Types::ProjectType, null: true,
+ description: 'Project that owns the runner. For project runners only.',
+ resolver: ::Resolvers::Ci::RunnerOwnerProjectResolver
field :paused, GraphQL::Types::Boolean, null: false,
description: 'Indicates the runner is paused and not available to run jobs.'
+ field :platform_name, GraphQL::Types::String, null: true,
+ description: 'Platform provided by the runner.',
+ method: :platform
field :project_count, GraphQL::Types::Int, null: true,
description: 'Number of projects that the runner is associated with.'
field :projects,
@@ -88,9 +98,6 @@ module Types
method: :token_expires_at
field :version, GraphQL::Types::String, null: true,
description: 'Version of the runner.'
- field :owner_project, ::Types::ProjectType, null: true,
- description: 'Project that owns the runner. For project runners only.',
- resolver: ::Resolvers::Ci::RunnerOwnerProjectResolver
markdown_field :maintenance_note_html, null: true
@@ -99,8 +106,25 @@ module Types
end
def job_count
- # We limit to 1 above the JOB_COUNT_LIMIT to indicate that more items exist after JOB_COUNT_LIMIT
- runner.builds.limit(JOB_COUNT_LIMIT + 1).count
+ BatchLoader::GraphQL.for(runner.id).batch(key: :job_count) do |runner_ids, loader, _args|
+ # rubocop: disable CodeReuse/ActiveRecord
+ # We limit to 1 above the JOB_COUNT_LIMIT to indicate that more items exist after JOB_COUNT_LIMIT
+ builds_tbl = ::Ci::Build.arel_table
+ runners_tbl = ::Ci::Runner.arel_table
+ lateral_query = ::Ci::Build.select(1)
+ .where(builds_tbl['runner_id'].eq(runners_tbl['id']))
+ .limit(JOB_COUNT_LIMIT + 1)
+ counts = ::Ci::Runner.joins("JOIN LATERAL (#{lateral_query.to_sql}) builds_with_limit ON true")
+ .id_in(runner_ids)
+ .select(:id, Arel.star.count.as('count'))
+ .group(:id)
+ .index_by(&:id)
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ runner_ids.each do |runner_id|
+ loader.call(runner_id, counts[runner_id]&.count || 0)
+ end
+ end
end
def admin_url
@@ -111,14 +135,13 @@ module Types
Gitlab::Routing.url_helpers.edit_admin_runner_url(runner) if can_admin_runners?
end
- # rubocop: disable CodeReuse/ActiveRecord
def project_count
BatchLoader::GraphQL.for(runner.id).batch(key: :runner_project_count) do |ids, loader, args|
counts = ::Ci::Runner.project_type
.select(:id, 'COUNT(ci_runner_projects.id) as count')
.left_outer_joins(:runner_projects)
- .where(id: ids)
- .group(:id)
+ .id_in(ids)
+ .group(:id) # rubocop: disable CodeReuse/ActiveRecord
.index_by(&:id)
ids.each do |id|
@@ -126,12 +149,15 @@ module Types
end
end
end
- # rubocop: enable CodeReuse/ActiveRecord
- def groups
- return unless runner.group_type?
+ def job_execution_status
+ BatchLoader::GraphQL.for(runner.id).batch(key: :running_builds_exist) do |runner_ids, loader|
+ statuses = ::Ci::Runner.id_in(runner_ids).with_running_builds.index_by(&:id)
- batched_owners(::Ci::RunnerNamespace, Group, :runner_groups, :namespace_id)
+ runner_ids.each do |runner_id|
+ loader.call(runner_id, statuses[runner_id] ? :running : :idle)
+ end
+ end
end
private
@@ -139,29 +165,6 @@ module Types
def can_admin_runners?
context[:current_user]&.can_admin_all_resources?
end
-
- # rubocop: disable CodeReuse/ActiveRecord
- def batched_owners(runner_assoc_type, assoc_type, key, column_name)
- BatchLoader::GraphQL.for(runner.id).batch(key: key) do |runner_ids, loader|
- plucked_runner_and_owner_ids = runner_assoc_type
- .select(:runner_id, column_name)
- .where(runner_id: runner_ids)
- .pluck(:runner_id, column_name)
- # In plucked_runner_and_owner_ids, first() represents the runner ID, and second() the owner ID,
- # so let's group the owner IDs by runner ID
- runner_owner_ids_by_runner_id = plucked_runner_and_owner_ids
- .group_by(&:first)
- .transform_values { |runner_and_owner_id| runner_and_owner_id.map(&:second) }
-
- owner_ids = runner_owner_ids_by_runner_id.values.flatten.uniq
- owners = assoc_type.where(id: owner_ids).index_by(&:id)
-
- runner_ids.each do |runner_id|
- loader.call(runner_id, runner_owner_ids_by_runner_id[runner_id]&.map { |owner_id| owners[owner_id] } || [])
- end
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
end
end
end
diff --git a/app/graphql/types/commit_signature_interface.rb b/app/graphql/types/commit_signature_interface.rb
index 6b0c16e538a..0449a0634ef 100644
--- a/app/graphql/types/commit_signature_interface.rb
+++ b/app/graphql/types/commit_signature_interface.rb
@@ -21,7 +21,8 @@ module Types
description: 'Project of the associated commit.'
orphan_types Types::CommitSignatures::GpgSignatureType,
- Types::CommitSignatures::X509SignatureType
+ Types::CommitSignatures::X509SignatureType,
+ Types::CommitSignatures::SshSignatureType
def self.resolve_type(object, context)
case object
@@ -29,6 +30,8 @@ module Types
Types::CommitSignatures::GpgSignatureType
when ::CommitSignatures::X509CommitSignature
Types::CommitSignatures::X509SignatureType
+ when ::CommitSignatures::SshSignature
+ Types::CommitSignatures::SshSignatureType
else
raise 'Unsupported commit signature type'
end
diff --git a/app/graphql/types/commit_signatures/gpg_signature_type.rb b/app/graphql/types/commit_signatures/gpg_signature_type.rb
index 2a845fff3e2..3baf2d9d21d 100644
--- a/app/graphql/types/commit_signatures/gpg_signature_type.rb
+++ b/app/graphql/types/commit_signatures/gpg_signature_type.rb
@@ -11,6 +11,7 @@ module Types
authorize :download_code
field :user, Types::UserType, null: true,
+ method: :signed_by_user,
description: 'User associated with the key.'
field :gpg_key_user_name, GraphQL::Types::String,
diff --git a/app/graphql/types/commit_signatures/ssh_signature_type.rb b/app/graphql/types/commit_signatures/ssh_signature_type.rb
new file mode 100644
index 00000000000..92eb4f7949a
--- /dev/null
+++ b/app/graphql/types/commit_signatures/ssh_signature_type.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Types
+ module CommitSignatures
+ class SshSignatureType < Types::BaseObject
+ graphql_name 'SshSignature'
+ description 'SSH signature for a signed commit'
+
+ implements Types::CommitSignatureInterface
+
+ authorize :download_code
+
+ field :user, Types::UserType, null: true,
+ method: :signed_by_user,
+ calls_gitaly: true,
+ description: 'User associated with the key.'
+
+ field :key, Types::KeyType,
+ null: true,
+ description: 'SSH key used for the signature.'
+ end
+ end
+end
diff --git a/app/graphql/types/commit_signatures/x509_signature_type.rb b/app/graphql/types/commit_signatures/x509_signature_type.rb
index 9ac96dbc015..2d58c3d5b5d 100644
--- a/app/graphql/types/commit_signatures/x509_signature_type.rb
+++ b/app/graphql/types/commit_signatures/x509_signature_type.rb
@@ -11,6 +11,7 @@ module Types
authorize :download_code
field :user, Types::UserType, null: true,
+ method: :signed_by_user,
calls_gitaly: true,
description: 'User associated with the key.'
diff --git a/app/graphql/types/container_repository_type.rb b/app/graphql/types/container_repository_type.rb
index cb818ac5e92..dfa599e798c 100644
--- a/app/graphql/types/container_repository_type.rb
+++ b/app/graphql/types/container_repository_type.rb
@@ -13,6 +13,7 @@ module Types
field :expiration_policy_cleanup_status, Types::ContainerRepositoryCleanupStatusEnum, null: true, description: 'Tags cleanup status for the container repository.'
field :expiration_policy_started_at, Types::TimeType, null: true, description: 'Timestamp when the cleanup done by the expiration policy was started on the container repository.'
field :id, GraphQL::Types::ID, null: false, description: 'ID of the container repository.'
+ field :last_cleanup_deleted_tags_count, GraphQL::Types::Int, null: true, description: 'Number of deleted tags from the last cleanup.'
field :location, GraphQL::Types::String, null: false, description: 'URL of the container repository.'
field :migration_state, GraphQL::Types::String, null: false, description: 'Migration state of the container repository.'
field :name, GraphQL::Types::String, null: false, description: 'Name of the container repository.'
@@ -21,7 +22,6 @@ module Types
field :status, Types::ContainerRepositoryStatusEnum, null: true, description: 'Status of the container repository.'
field :tags_count, GraphQL::Types::Int, null: false, description: 'Number of tags associated with this image.'
field :updated_at, Types::TimeType, null: false, description: 'Timestamp when the container repository was updated.'
- field :last_cleanup_deleted_tags_count, GraphQL::Types::Int, null: true, description: 'Number of deleted tags from the last cleanup.'
def can_delete
Ability.allowed?(current_user, :update_container_image, object)
diff --git a/app/graphql/types/dependency_proxy/manifest_type.rb b/app/graphql/types/dependency_proxy/manifest_type.rb
index f7e751e30d3..53b7610e490 100644
--- a/app/graphql/types/dependency_proxy/manifest_type.rb
+++ b/app/graphql/types/dependency_proxy/manifest_type.rb
@@ -14,11 +14,11 @@ module Types
field :id, ::Types::GlobalIDType[::DependencyProxy::Manifest], null: false, description: 'ID of the manifest.'
field :image_name, GraphQL::Types::String, null: false, description: 'Name of the image.'
field :size, GraphQL::Types::String, null: false, description: 'Size of the manifest file.'
- field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.'
field :status,
Types::DependencyProxy::ManifestTypeEnum,
null: false,
description: "Status of the manifest (#{::DependencyProxy::Manifest.statuses.keys.join(', ')})"
+ field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.'
def image_name
object.file_name.chomp(File.extname(object.file_name))
diff --git a/app/graphql/types/deployment_details_type.rb b/app/graphql/types/deployment_details_type.rb
deleted file mode 100644
index bbb5cc8e3f1..00000000000
--- a/app/graphql/types/deployment_details_type.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-module Types
- class DeploymentDetailsType < DeploymentType
- graphql_name 'DeploymentDetails'
- description 'The details of the deployment'
- authorize :read_deployment
- present_using ::Deployments::DeploymentPresenter
-
- field :tags,
- [Types::DeploymentTagType],
- description: 'Git tags that contain this deployment.',
- calls_gitaly: true
- end
-end
-
-Types::DeploymentDetailsType.prepend_mod_with('Types::DeploymentDetailsType')
diff --git a/app/graphql/types/deployment_type.rb b/app/graphql/types/deployment_type.rb
index 59b59dc4e1d..1c23fd44ea1 100644
--- a/app/graphql/types/deployment_type.rb
+++ b/app/graphql/types/deployment_type.rb
@@ -1,12 +1,6 @@
# frozen_string_literal: true
module Types
- # If you're considering to add a new field in DeploymentType, please follow this guideline:
- # - If the field is preloadable in batch, define it in DeploymentType.
- # In this case, you should extend DeploymentsResolver logic to preload the field. Also, add a new test that
- # fetching the specific field for multiple deployments doesn't cause N+1 query problem.
- # - If the field is NOT preloadable in batch, define it in DeploymentDetailsType.
- # This type can be only fetched for a single deployment, so you don't need to take care of the preloading.
class DeploymentType < BaseObject
graphql_name 'Deployment'
description 'The deployment of an environment'
@@ -15,6 +9,8 @@ module Types
authorize :read_deployment
+ expose_permissions Types::PermissionTypes::Deployment
+
field :id,
GraphQL::Types::ID,
description: 'Global ID of the deployment.'
@@ -65,5 +61,15 @@ module Types
Types::UserType,
description: 'User who executed the deployment.',
method: :deployed_by
+
+ field :tags,
+ [Types::DeploymentTagType],
+ description: 'Git tags that contain this deployment. ' \
+ 'This field can only be resolved for one deployment in any single request.',
+ calls_gitaly: true do
+ extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1
+ end
end
end
+
+Types::DeploymentType.prepend_mod_with('Types::DeploymentType')
diff --git a/app/graphql/types/environment_type.rb b/app/graphql/types/environment_type.rb
index dd2286d333d..5f58fc38540 100644
--- a/app/graphql/types/environment_type.rb
+++ b/app/graphql/types/environment_type.rb
@@ -9,6 +9,12 @@ module Types
authorize :read_environment
+ expose_permissions Types::PermissionTypes::Environment,
+ description: 'Permissions for the current user on the resource. '\
+ 'This field can only be resolved for one environment in any single request.' do
+ extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1
+ end
+
field :name, GraphQL::Types::String, null: false,
description: 'Human-readable name of the environment.'
@@ -67,6 +73,11 @@ module Types
description: 'Last deployment of the environment.',
resolver: Resolvers::Environments::LastDeploymentResolver
+ field :deploy_freezes,
+ [Types::Ci::FreezePeriodType],
+ null: true,
+ description: 'Deployment freeze periods of the environment.'
+
def tier
object.tier.to_sym
end
diff --git a/app/graphql/types/global_id_type.rb b/app/graphql/types/global_id_type.rb
index a71c2fb0e6c..7ebd98ff2e7 100644
--- a/app/graphql/types/global_id_type.rb
+++ b/app/graphql/types/global_id_type.rb
@@ -49,9 +49,7 @@ module Types
An example `#{graphql_name}` is: `"#{::Gitlab::GlobalId.build(model_name: model_name, id: 1)}"`.
#{
if deprecation = Gitlab::GlobalId::Deprecations.deprecation_by(model_name)
- 'The older format `"' +
- ::Gitlab::GlobalId.build(model_name: deprecation.old_name, id: 1).to_s +
- '"` was deprecated in ' + deprecation.milestone + '.'
+ "The older format `\"#{::Gitlab::GlobalId.build(model_name: deprecation.old_name, id: 1)}\"` was deprecated in #{deprecation.milestone}."
end}
MD
diff --git a/app/graphql/types/group_connection.rb b/app/graphql/types/group_connection.rb
new file mode 100644
index 00000000000..e4332e24302
--- /dev/null
+++ b/app/graphql/types/group_connection.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+# Normally this wouldn't be needed and we could use
+#
+# type Types::GroupType.connection_type, null: true
+#
+# in a resolver. However we can end up with cyclic definitions.
+# Running the spec locally can result in errors like
+#
+# NameError: uninitialized constant Types::GroupType
+#
+# or other errors. To fix this, we created this file and use
+#
+# type "Types::GroupConnection", null: true
+#
+# which gives a delayed resolution, and the proper connection type.
+#
+# See gitlab/app/graphql/types/ci/runner_type.rb
+# Reference: https://github.com/rmosolgo/graphql-ruby/issues/3974#issuecomment-1084444214
+# and https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#testing-tips-and-tricks
+#
+Types::GroupConnection = Types::GroupType.connection_type
diff --git a/app/graphql/types/issue_type_enum.rb b/app/graphql/types/issue_type_enum.rb
index 78cd27f60c3..d7f587ff03d 100644
--- a/app/graphql/types/issue_type_enum.rb
+++ b/app/graphql/types/issue_type_enum.rb
@@ -16,5 +16,9 @@ module Types
value 'OBJECTIVE', value: 'objective',
description: 'Objective issue type. Available only when feature flag `okrs_mvc` is enabled.',
alpha: { milestone: '15.6' }
+
+ value 'KEY_RESULT', value: 'key_result',
+ description: 'Key Result issue type. Available only when feature flag `okrs_mvc` is enabled.',
+ alpha: { milestone: '15.7' }
end
end
diff --git a/app/graphql/types/key_type.rb b/app/graphql/types/key_type.rb
new file mode 100644
index 00000000000..30699793045
--- /dev/null
+++ b/app/graphql/types/key_type.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Types
+ class KeyType < Types::BaseObject # rubocop:disable Graphql/AuthorizeTypes
+ graphql_name 'Key'
+ description 'Represents an SSH key.'
+
+ field :created_at, Types::TimeType, null: false,
+ description: 'Timestamp of when the key was created.'
+ field :expires_at, Types::TimeType, null: false,
+ description: "Timestamp of when the key expires. It's null if it never expires."
+ field :id, GraphQL::Types::ID, null: false, description: 'ID of the key.'
+ field :key, GraphQL::Types::String, null: false, method: :publishable_key,
+ description: 'Public key of the key pair.'
+ field :title, GraphQL::Types::String, null: false, description: 'Title of the key.'
+ end
+end
diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb
index 49bf7aa638c..abf7b3ad530 100644
--- a/app/graphql/types/merge_request_type.rb
+++ b/app/graphql/types/merge_request_type.rb
@@ -200,10 +200,10 @@ module Types
description: 'Array of available auto merge strategies.'
field :commits, Types::CommitType.connection_type, null: true,
calls_gitaly: true, description: 'Merge request commits.'
- field :committers, Types::UserType.connection_type, null: true, complexity: 5,
- calls_gitaly: true, description: 'Users who have added commits to the merge request.'
field :commits_without_merge_commits, Types::CommitType.connection_type, null: true,
calls_gitaly: true, description: 'Merge request commits excluding merge commits.'
+ field :committers, Types::UserType.connection_type, null: true, complexity: 5,
+ calls_gitaly: true, description: 'Users who have added commits to the merge request.'
field :has_ci, GraphQL::Types::Boolean, null: false, method: :has_ci?,
description: 'Indicates if the merge request has CI.'
field :merge_user, Types::UserType, null: true,
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 1cbb2ede544..b342e57804b 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -63,6 +63,8 @@ module Types
mount_mutation Mutations::Issues::SetEscalationStatus
mount_mutation Mutations::Issues::Update
mount_mutation Mutations::Issues::Move
+ mount_mutation Mutations::Issues::LinkAlerts
+ mount_mutation Mutations::Issues::UnlinkAlert
mount_mutation Mutations::Labels::Create
mount_mutation Mutations::MergeRequests::Accept
mount_mutation Mutations::MergeRequests::Create
@@ -117,6 +119,8 @@ module Types
mount_mutation Mutations::Ci::Pipeline::Retry
mount_mutation Mutations::Ci::PipelineSchedule::Delete
mount_mutation Mutations::Ci::PipelineSchedule::TakeOwnership
+ mount_mutation Mutations::Ci::PipelineSchedule::Play
+ mount_mutation Mutations::Ci::PipelineSchedule::Create
mount_mutation Mutations::Ci::CiCdSettingsUpdate, deprecated: {
reason: :renamed,
replacement: 'ProjectCiCdSettingsUpdate',
diff --git a/app/graphql/types/nested_environment_type.rb b/app/graphql/types/nested_environment_type.rb
new file mode 100644
index 00000000000..b835af2bf45
--- /dev/null
+++ b/app/graphql/types/nested_environment_type.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Types
+ # rubocop: disable Graphql/AuthorizeTypes
+ class NestedEnvironmentType < BaseObject
+ graphql_name 'NestedEnvironment'
+ description 'Describes where code is deployed for a project organized by folder.'
+
+ field :name, GraphQL::Types::String,
+ null: false, description: 'Human-readable name of the environment.'
+
+ field :size, GraphQL::Types::Int,
+ null: false, description: 'Number of environments nested in the folder.'
+
+ field :environment,
+ Types::EnvironmentType,
+ null: true, description: 'Latest environment in the folder.'
+
+ def environment
+ BatchLoader::GraphQL.for(object.last_id).batch do |environment_ids, loader|
+ Environment.id_in(environment_ids).each do |environment|
+ loader.call(environment.id, environment)
+ end
+ end
+ end
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+end
diff --git a/app/graphql/types/notes/note_type.rb b/app/graphql/types/notes/note_type.rb
index eef5ce40bde..05629ea9223 100644
--- a/app/graphql/types/notes/note_type.rb
+++ b/app/graphql/types/notes/note_type.rb
@@ -77,6 +77,14 @@ module Types
def author
Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find
end
+
+ # We now support also SyntheticNote notes as a NoteType, but SyntheticNote does not have a real note ID,
+ # as SyntheticNote is generated dynamically from a ResourceEvent instance.
+ def id
+ return super unless object.is_a?(SyntheticNote)
+
+ ::Gitlab::GlobalId.build(object, model_name: object.class.to_s, id: object.discussion_id)
+ end
end
end
end
diff --git a/app/graphql/types/packages/package_links_type.rb b/app/graphql/types/packages/package_links_type.rb
index f16937530b9..eb29fb655bd 100644
--- a/app/graphql/types/packages/package_links_type.rb
+++ b/app/graphql/types/packages/package_links_type.rb
@@ -12,6 +12,8 @@ module Types
field :web_path, GraphQL::Types::String, null: true, description: 'Path to the package details page.'
def web_path
+ return unless object.default?
+
package_path(object)
end
end
diff --git a/app/graphql/types/permission_types/base_permission_type.rb b/app/graphql/types/permission_types/base_permission_type.rb
index 07e6e7a55d6..0192af25d0f 100644
--- a/app/graphql/types/permission_types/base_permission_type.rb
+++ b/app/graphql/types/permission_types/base_permission_type.rb
@@ -11,20 +11,20 @@ module Types
abilities.each { |ability| ability_field(ability) }
end
- def self.ability_field(ability, **kword_args)
+ def self.ability_field(ability, **kword_args, &block)
define_field_resolver_method(ability) unless resolving_keywords?(kword_args)
- permission_field(ability, **kword_args)
+ permission_field(ability, **kword_args, &block)
end
- def self.permission_field(name, **kword_args)
+ def self.permission_field(name, **kword_args, &block)
kword_args = kword_args.reverse_merge(
name: name,
type: GraphQL::Types::Boolean,
description: "Indicates the user can perform `#{name}` on this resource",
null: false)
- field(**kword_args) # rubocop:disable Graphql/Descriptions
+ field(**kword_args, &block) # rubocop:disable Graphql/Descriptions
end
def self.define_field_resolver_method(ability)
diff --git a/app/graphql/types/permission_types/deployment.rb b/app/graphql/types/permission_types/deployment.rb
new file mode 100644
index 00000000000..fce376552b1
--- /dev/null
+++ b/app/graphql/types/permission_types/deployment.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Types
+ module PermissionTypes
+ class Deployment < BasePermissionType
+ graphql_name 'DeploymentPermissions'
+
+ abilities :destroy_deployment
+ ability_field :update_deployment, calls_gitaly: true
+ end
+ end
+end
+
+Types::PermissionTypes::Deployment.prepend_mod_with('Types::PermissionTypes::Deployment')
diff --git a/app/graphql/types/permission_types/environment.rb b/app/graphql/types/permission_types/environment.rb
new file mode 100644
index 00000000000..59c9fce64e5
--- /dev/null
+++ b/app/graphql/types/permission_types/environment.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Types
+ module PermissionTypes
+ class Environment < BasePermissionType
+ graphql_name 'EnvironmentPermissions'
+
+ abilities :update_environment, :destroy_environment, :stop_environment
+ end
+ end
+end
diff --git a/app/graphql/types/permission_types/project.rb b/app/graphql/types/permission_types/project.rb
index f6a5563d367..c833b512222 100644
--- a/app/graphql/types/permission_types/project.rb
+++ b/app/graphql/types/permission_types/project.rb
@@ -17,7 +17,8 @@ module Types
:admin_wiki, :admin_project, :update_pages,
:admin_remote_mirror, :create_label, :update_wiki, :destroy_wiki,
:create_pages, :destroy_pages, :read_pages_content, :admin_operations,
- :read_merge_request, :read_design, :create_design, :destroy_design
+ :read_merge_request, :read_design, :create_design, :destroy_design,
+ :read_environment
permission_field :create_snippet
diff --git a/app/graphql/types/project_statistics_type.rb b/app/graphql/types/project_statistics_type.rb
index c43baf1280b..a1d721856a9 100644
--- a/app/graphql/types/project_statistics_type.rb
+++ b/app/graphql/types/project_statistics_type.rb
@@ -11,6 +11,10 @@ module Types
field :build_artifacts_size, GraphQL::Types::Float, null: false,
description: 'Build artifacts size of the project in bytes.'
+ field :container_registry_size,
+ GraphQL::Types::Float,
+ null: true,
+ description: 'Container Registry size of the project in bytes.'
field :lfs_objects_size,
GraphQL::Types::Float,
null: false,
@@ -29,9 +33,5 @@ module Types
description: 'Uploads size of the project in bytes.'
field :wiki_size, GraphQL::Types::Float, null: true,
description: 'Wiki size of the project in bytes.'
- field :container_registry_size,
- GraphQL::Types::Float,
- null: true,
- description: 'Container Registry size of the project in bytes.'
end
end
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index 771dad00fb3..fe13ee7ef3c 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -258,8 +258,11 @@ module Types
field :environments,
Types::EnvironmentType.connection_type,
null: true,
- description: 'Environments of the project.',
- resolver: Resolvers::EnvironmentsResolver
+ description: 'Environments of the project. ' \
+ 'This field can only be resolved for one project in any single request.',
+ resolver: Resolvers::EnvironmentsResolver do
+ extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1
+ end
field :environment,
Types::EnvironmentType,
@@ -267,8 +270,18 @@ module Types
description: 'A single environment of the project.',
resolver: Resolvers::EnvironmentsResolver.single
+ field :nested_environments,
+ Types::NestedEnvironmentType.connection_type,
+ null: true,
+ calls_gitaly: true,
+ description: 'Environments for this project with nested folders, ' \
+ 'can only be resolved for one project in any single request',
+ resolver: Resolvers::Environments::NestedEnvironmentsResolver do
+ extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1
+ end
+
field :deployment,
- Types::DeploymentDetailsType,
+ Types::DeploymentType,
null: true,
description: 'Details of the deployment of the project.',
resolver: Resolvers::DeploymentResolver.single
@@ -526,6 +539,13 @@ module Types
resolver: Resolvers::Projects::ForkTargetsResolver,
description: 'Namespaces in which the current user can fork the project into.'
+ field :fork_details, Types::Projects::ForkDetailsType,
+ calls_gitaly: true,
+ alpha: { milestone: '15.7' },
+ authorize: :read_code,
+ resolver: Resolvers::Projects::ForkDetailsResolver,
+ description: 'Details of the fork project compared to its upstream project.'
+
field :branch_rules,
Types::Projects::BranchRuleType.connection_type,
null: true,
@@ -537,6 +557,11 @@ module Types
description: "Programming languages used in the project.",
calls_gitaly: true
+ field :runners, Types::Ci::RunnerType.connection_type,
+ null: true,
+ resolver: ::Resolvers::Ci::ProjectRunnersResolver,
+ description: "Find runners visible to the current user."
+
def timelog_categories
object.project_namespace.timelog_categories if Feature.enabled?(:timelog_categories)
end
diff --git a/app/graphql/types/projects/fork_details_type.rb b/app/graphql/types/projects/fork_details_type.rb
new file mode 100644
index 00000000000..88c17d89620
--- /dev/null
+++ b/app/graphql/types/projects/fork_details_type.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Types
+ module Projects
+ # rubocop: disable Graphql/AuthorizeTypes
+ class ForkDetailsType < BaseObject
+ graphql_name 'ForkDetails'
+ description 'Details of the fork project compared to its upstream project.'
+
+ field :ahead, GraphQL::Types::Int,
+ null: true,
+ description: 'Number of commits ahead of upstream.'
+
+ field :behind, GraphQL::Types::Int,
+ null: true,
+ description: 'Number of commits behind upstream.'
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index 21cb3f9e06c..7263f792bae 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -67,7 +67,7 @@ module Types
end
field :package,
- description: 'Find a package. This field can only be resolved for one query in any single request.',
+ description: 'Find a package. This field can only be resolved for one query in any single request. Returns `null` if a package has no `default` status.',
resolver: Resolvers::PackageDetailsResolver
field :user, Types::UserType,
diff --git a/app/graphql/types/release_type.rb b/app/graphql/types/release_type.rb
index a20e53ad1bd..8516256b433 100644
--- a/app/graphql/types/release_type.rb
+++ b/app/graphql/types/release_type.rb
@@ -13,9 +13,6 @@ module Types
present_using ReleasePresenter
- field :id, ::Types::GlobalIDType[Release],
- null: false,
- description: 'Global ID of the release.'
field :assets, Types::ReleaseAssetsType, null: true, method: :itself,
description: 'Assets of the release.'
field :created_at, Types::TimeType, null: true,
@@ -26,6 +23,11 @@ module Types
description: 'Description (also known as "release notes") of the release.'
field :evidences, Types::EvidenceType.connection_type, null: true,
description: 'Evidence for the release.'
+ field :historical_release, GraphQL::Types::Boolean, null: true, method: :historical_release?,
+ description: 'Indicates the release is an historical release.'
+ field :id, ::Types::GlobalIDType[Release],
+ null: false,
+ description: 'Global ID of the release.'
field :links, Types::ReleaseLinksType, null: true, method: :itself,
description: 'Links of the release.'
field :milestones, Types::MilestoneType.connection_type, null: true,
@@ -42,8 +44,6 @@ module Types
authorize: :read_code
field :upcoming_release, GraphQL::Types::Boolean, null: true, method: :upcoming_release?,
description: 'Indicates the release is an upcoming release.'
- field :historical_release, GraphQL::Types::Boolean, null: true, method: :historical_release?,
- description: 'Indicates the release is an historical release.'
field :author, Types::UserType, null: true,
description: 'User that created the release.'
diff --git a/app/graphql/types/root_storage_statistics_type.rb b/app/graphql/types/root_storage_statistics_type.rb
index b1b712aab38..64aaf3e73a0 100644
--- a/app/graphql/types/root_storage_statistics_type.rb
+++ b/app/graphql/types/root_storage_statistics_type.rb
@@ -7,6 +7,7 @@ module Types
authorize :read_statistics
field :build_artifacts_size, GraphQL::Types::Float, null: false, description: 'CI artifacts size in bytes.'
+ field :container_registry_size, GraphQL::Types::Float, null: false, description: 'Container Registry size in bytes.'
field :dependency_proxy_size, GraphQL::Types::Float, null: false, description: 'Dependency Proxy sizes in bytes.'
field :lfs_objects_size, GraphQL::Types::Float, null: false, description: 'LFS objects size in bytes.'
field :packages_size, GraphQL::Types::Float, null: false, description: 'Packages size in bytes.'
@@ -16,6 +17,5 @@ module Types
field :storage_size, GraphQL::Types::Float, null: false, description: 'Total storage in bytes.'
field :uploads_size, GraphQL::Types::Float, null: false, description: 'Uploads size in bytes.'
field :wiki_size, GraphQL::Types::Float, null: false, description: 'Wiki size in bytes.'
- field :container_registry_size, GraphQL::Types::Float, null: false, description: 'Container Registry size in bytes.'
end
end
diff --git a/app/graphql/types/subscription_type.rb b/app/graphql/types/subscription_type.rb
index 9d5edec82b2..f7f26ba4c5a 100644
--- a/app/graphql/types/subscription_type.rb
+++ b/app/graphql/types/subscription_type.rb
@@ -34,6 +34,11 @@ module Types
subscription: Subscriptions::IssuableUpdated,
null: true,
description: 'Triggered when the merge status of a merge request is updated.'
+
+ field :merge_request_approval_state_updated,
+ subscription: Subscriptions::IssuableUpdated,
+ null: true,
+ description: 'Triggered when approval state of a merge request is updated.'
end
end
diff --git a/app/graphql/types/todo_action_enum.rb b/app/graphql/types/todo_action_enum.rb
index ef43b6eb464..33e1c4e98a4 100644
--- a/app/graphql/types/todo_action_enum.rb
+++ b/app/graphql/types/todo_action_enum.rb
@@ -5,11 +5,12 @@ module Types
value 'assigned', value: 1, description: 'User was assigned.'
value 'mentioned', value: 2, description: 'User was mentioned.'
value 'build_failed', value: 3, description: 'Build triggered by the user failed.'
- value 'marked', value: 4, description: 'User added a TODO.'
+ value 'marked', value: 4, description: 'User added a to-do item.'
value 'approval_required', value: 5, description: 'User was set as an approver.'
value 'unmergeable', value: 6, description: 'Merge request authored by the user could not be merged.'
value 'directly_addressed', value: 7, description: 'User was directly addressed.'
value 'merge_train_removed', value: 8, description: 'Merge request authored by the user was removed from the merge train.'
value 'review_requested', value: 9, description: 'Review was requested from the user.'
+ value 'member_access_requested', value: 10, description: 'Group access requested from the user.'
end
end
diff --git a/app/graphql/types/todo_type.rb b/app/graphql/types/todo_type.rb
index 0de6b1d6f8a..6e5ce35033b 100644
--- a/app/graphql/types/todo_type.rb
+++ b/app/graphql/types/todo_type.rb
@@ -15,13 +15,11 @@ module Types
field :project, Types::ProjectType,
description: 'Project this to-do item is associated with.',
- null: true,
- authorize: :read_project
+ null: true
field :group, 'Types::GroupType',
description: 'Group this to-do item is associated with.',
- null: true,
- authorize: :read_group
+ null: true
field :author, Types::UserType,
description: 'Author of this to-do item.',
diff --git a/app/graphql/types/user_interface.rb b/app/graphql/types/user_interface.rb
index f49b3eee4f5..51046d09f90 100644
--- a/app/graphql/types/user_interface.rb
+++ b/app/graphql/types/user_interface.rb
@@ -88,7 +88,10 @@ module Types
null: true,
description: 'Personal namespace of the user.'
- field :todos, resolver: Resolvers::TodosResolver, description: 'To-do items of the user.'
+ field :todos,
+ Types::TodoType.connection_type,
+ description: 'To-do items of the user.',
+ resolver: Resolvers::TodosResolver
# Merge request field: MRs can be authored, assigned, or assigned-for-review:
field :authored_merge_requests,
diff --git a/app/graphql/types/work_items/notes_filter_type_enum.rb b/app/graphql/types/work_items/notes_filter_type_enum.rb
new file mode 100644
index 00000000000..93fb4689f0b
--- /dev/null
+++ b/app/graphql/types/work_items/notes_filter_type_enum.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Types
+ module WorkItems
+ class NotesFilterTypeEnum < BaseEnum
+ graphql_name 'NotesFilterType'
+ description 'Work item notes collection type.'
+
+ ::UserPreference::NOTES_FILTERS.each_pair do |key, value|
+ value key.upcase,
+ value: value,
+ description: UserPreference.notes_filters.invert[::UserPreference::NOTES_FILTERS[key]]
+ end
+
+ def self.default_value
+ ::UserPreference::NOTES_FILTERS[:all_notes]
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/work_items/widget_interface.rb b/app/graphql/types/work_items/widget_interface.rb
index b85d0a23535..672a78f12e1 100644
--- a/app/graphql/types/work_items/widget_interface.rb
+++ b/app/graphql/types/work_items/widget_interface.rb
@@ -17,7 +17,8 @@ module Types
::Types::WorkItems::Widgets::LabelsType,
::Types::WorkItems::Widgets::AssigneesType,
::Types::WorkItems::Widgets::StartAndDueDateType,
- ::Types::WorkItems::Widgets::MilestoneType
+ ::Types::WorkItems::Widgets::MilestoneType,
+ ::Types::WorkItems::Widgets::NotesType
].freeze
def self.ce_orphan_types
@@ -41,6 +42,8 @@ module Types
::Types::WorkItems::Widgets::StartAndDueDateType
when ::WorkItems::Widgets::Milestone
::Types::WorkItems::Widgets::MilestoneType
+ when ::WorkItems::Widgets::Notes
+ ::Types::WorkItems::Widgets::NotesType
else
raise "Unknown GraphQL type for widget #{object}"
end
diff --git a/app/graphql/types/work_items/widgets/hierarchy_type.rb b/app/graphql/types/work_items/widgets/hierarchy_type.rb
index 0ccd8af7dc8..4ec8ec84779 100644
--- a/app/graphql/types/work_items/widgets/hierarchy_type.rb
+++ b/app/graphql/types/work_items/widgets/hierarchy_type.rb
@@ -20,8 +20,29 @@ module Types
null: true, complexity: 5,
description: 'Child work items.'
+ field :has_children, GraphQL::Types::Boolean,
+ null: false, description: 'Indicates if the work item has children.'
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def has_children?
+ BatchLoader::GraphQL.for(object.work_item.id).batch(default_value: false) do |ids, loader|
+ links_for_parents = ::WorkItems::ParentLink.for_parents(ids)
+ .select(:work_item_parent_id)
+ .group(:work_item_parent_id)
+ .reorder(nil)
+
+ links_for_parents.each { |link| loader.call(link.work_item_parent_id, true) }
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ alias_method :has_children, :has_children?
+
def children
- object.children.inc_relations_for_permission_check
+ relation = object.children
+ relation = relation.inc_relations_for_permission_check unless object.children.loaded?
+
+ relation
end
end
# rubocop:enable Graphql/AuthorizeTypes
diff --git a/app/graphql/types/work_items/widgets/notes_type.rb b/app/graphql/types/work_items/widgets/notes_type.rb
new file mode 100644
index 00000000000..7da2777beee
--- /dev/null
+++ b/app/graphql/types/work_items/widgets/notes_type.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Types
+ module WorkItems
+ module Widgets
+ # Disabling widget level authorization as it might be too granular
+ # and we already authorize the parent work item
+ # rubocop:disable Graphql/AuthorizeTypes
+ class NotesType < BaseObject
+ graphql_name 'WorkItemWidgetNotes'
+ description 'Represents a notes widget'
+
+ implements Types::WorkItems::WidgetInterface
+
+ # This field loads user comments, system notes and resource events as a discussion for an work item,
+ # raising the complexity considerably. In order to discourage fetching this field as part of fetching
+ # a list of issues we raise the complexity
+ field :discussions, Types::Notes::DiscussionType.connection_type,
+ null: true,
+ description: "Notes on this work item.",
+ resolver: Resolvers::WorkItems::WorkItemDiscussionsResolver
+ end
+ # rubocop:enable Graphql/AuthorizeTypes
+ end
+ end
+end