diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-19 08:27:35 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-19 08:27:35 +0000 |
commit | 7e9c479f7de77702622631cff2628a9c8dcbc627 (patch) | |
tree | c8f718a08e110ad7e1894510980d2155a6549197 /app/graphql/types | |
parent | e852b0ae16db4052c1c567d9efa4facc81146e88 (diff) | |
download | gitlab-ce-7e9c479f7de77702622631cff2628a9c8dcbc627.tar.gz |
Add latest changes from gitlab-org/gitlab@13-6-stable-eev13.6.0-rc42
Diffstat (limited to 'app/graphql/types')
51 files changed, 725 insertions, 67 deletions
diff --git a/app/graphql/types/alert_management/http_integration_type.rb b/app/graphql/types/alert_management/http_integration_type.rb new file mode 100644 index 00000000000..88782050b94 --- /dev/null +++ b/app/graphql/types/alert_management/http_integration_type.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Types + module AlertManagement + class HttpIntegrationType < BaseObject + graphql_name 'AlertManagementHttpIntegration' + description 'An endpoint and credentials used to accept alerts for a project' + + implements(Types::AlertManagement::IntegrationType) + + authorize :admin_operations + + def type + :http + end + + def api_url + nil + end + end + end +end diff --git a/app/graphql/types/alert_management/integration_type.rb b/app/graphql/types/alert_management/integration_type.rb new file mode 100644 index 00000000000..bf599885584 --- /dev/null +++ b/app/graphql/types/alert_management/integration_type.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module Types + module AlertManagement + module IntegrationType + include Types::BaseInterface + graphql_name 'AlertManagementIntegration' + + field :id, + GraphQL::ID_TYPE, + null: false, + description: 'ID of the integration' + + field :type, + AlertManagement::IntegrationTypeEnum, + null: false, + description: 'Type of integration' + + field :name, + GraphQL::STRING_TYPE, + null: true, + description: 'Name of the integration' + + field :active, + GraphQL::BOOLEAN_TYPE, + null: true, + description: 'Whether the endpoint is currently accepting alerts' + + field :token, + GraphQL::STRING_TYPE, + null: true, + description: 'Token used to authenticate alert notification requests' + + field :url, + GraphQL::STRING_TYPE, + null: true, + description: 'Endpoint which accepts alert notifications' + + field :api_url, + GraphQL::STRING_TYPE, + null: true, + description: 'URL at which Prometheus metrics can be queried to populate the metrics dashboard' + + definition_methods do + def resolve_type(object, context) + if object.is_a?(::PrometheusService) + Types::AlertManagement::PrometheusIntegrationType + else + Types::AlertManagement::HttpIntegrationType + end + end + end + + orphan_types Types::AlertManagement::PrometheusIntegrationType, + Types::AlertManagement::HttpIntegrationType + end + end +end diff --git a/app/graphql/types/alert_management/integration_type_enum.rb b/app/graphql/types/alert_management/integration_type_enum.rb new file mode 100644 index 00000000000..2f9be549e58 --- /dev/null +++ b/app/graphql/types/alert_management/integration_type_enum.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Types + module AlertManagement + class IntegrationTypeEnum < BaseEnum + graphql_name 'AlertManagementIntegrationType' + description 'Values of types of integrations' + + value 'PROMETHEUS', 'Prometheus integration', value: :prometheus + value 'HTTP', 'Integration with any monitoring tool', value: :http + end + end +end diff --git a/app/graphql/types/alert_management/prometheus_integration_type.rb b/app/graphql/types/alert_management/prometheus_integration_type.rb new file mode 100644 index 00000000000..f605e325b8b --- /dev/null +++ b/app/graphql/types/alert_management/prometheus_integration_type.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Types + module AlertManagement + class PrometheusIntegrationType < BaseObject + include ::Gitlab::Routing + + graphql_name 'AlertManagementPrometheusIntegration' + description 'An endpoint and credentials used to accept Prometheus alerts for a project' + + implements(Types::AlertManagement::IntegrationType) + + authorize :admin_project + + alias_method :prometheus_service, :object + + def name + prometheus_service.title + end + + def type + :prometheus + end + + def token + prometheus_service.project&.alerting_setting&.token + end + + def url + prometheus_service.project && notify_project_prometheus_alerts_url(prometheus_service.project, format: :json) + end + + def active + prometheus_service.manual_configuration? + end + end + end +end diff --git a/app/graphql/types/availability_enum.rb b/app/graphql/types/availability_enum.rb new file mode 100644 index 00000000000..61686b9359f --- /dev/null +++ b/app/graphql/types/availability_enum.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Types + class AvailabilityEnum < BaseEnum + graphql_name 'AvailabilityEnum' + description 'User availability status' + + ::UserStatus.availabilities.keys.each do |availability_value| + value availability_value.upcase, value: availability_value, description: availability_value.titleize + end + end +end diff --git a/app/graphql/types/base_object.rb b/app/graphql/types/base_object.rb index 70e665f8fc3..9c36c83d4a3 100644 --- a/app/graphql/types/base_object.rb +++ b/app/graphql/types/base_object.rb @@ -8,6 +8,12 @@ module Types field_class Types::BaseField + def self.accepts(*types) + @accepts ||= [] + @accepts += types + @accepts + end + # All graphql fields exposing an id, should expose a global id. def id GitlabSchema.id_from_object(object) @@ -16,5 +22,13 @@ module Types def current_user context[:current_user] end + + def self.assignable?(object) + assignable = accepts + + return true if assignable.blank? + + assignable.any? { |cls| object.is_a?(cls) } + end end end diff --git a/app/graphql/types/board_type.rb b/app/graphql/types/board_type.rb index f5dc9e08427..2a7b318e283 100644 --- a/app/graphql/types/board_type.rb +++ b/app/graphql/types/board_type.rb @@ -4,7 +4,7 @@ module Types class BoardType < BaseObject graphql_name 'Board' description 'Represents a project or group board' - + accepts ::Board authorize :read_board field :id, type: GraphQL::ID_TYPE, null: false, diff --git a/app/graphql/types/ci/detailed_status_type.rb b/app/graphql/types/ci/detailed_status_type.rb index f4a50115ee6..6d8af400ac4 100644 --- a/app/graphql/types/ci/detailed_status_type.rb +++ b/app/graphql/types/ci/detailed_status_type.rb @@ -30,7 +30,7 @@ module Types if obj.has_action? { button_title: obj.action_button_title, - icon: obj.icon, + icon: obj.action_icon, method: obj.action_method, path: obj.action_path, title: obj.action_title diff --git a/app/graphql/types/ci/job_type.rb b/app/graphql/types/ci/job_type.rb index 0ee1ad47b62..feaff4e81d8 100644 --- a/app/graphql/types/ci/job_type.rb +++ b/app/graphql/types/ci/job_type.rb @@ -6,6 +6,9 @@ module Types class JobType < BaseObject graphql_name 'CiJob' + field :pipeline, Types::Ci::PipelineType, null: false, + description: 'Pipeline the job belongs to', + resolve: -> (build, _, _) { Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Pipeline, build.pipeline_id).find } field :name, GraphQL::STRING_TYPE, null: true, description: 'Name of the job' field :needs, JobType.connection_type, null: true, diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb index c508b746317..c25db39f600 100644 --- a/app/graphql/types/ci/pipeline_type.rb +++ b/app/graphql/types/ci/pipeline_type.rb @@ -13,49 +13,89 @@ module Types field :id, GraphQL::ID_TYPE, null: false, description: 'ID of the pipeline' + field :iid, GraphQL::STRING_TYPE, null: false, description: 'Internal ID of the pipeline' field :sha, GraphQL::STRING_TYPE, null: false, description: "SHA of the pipeline's commit" + field :before_sha, GraphQL::STRING_TYPE, null: true, description: 'Base SHA of the source branch' + field :status, PipelineStatusEnum, null: false, description: "Status of the pipeline (#{::Ci::Pipeline.all_state_names.compact.join(', ').upcase})" + field :detailed_status, Types::Ci::DetailedStatusType, null: false, description: 'Detailed status of the pipeline', resolve: -> (obj, _args, ctx) { obj.detailed_status(ctx[:current_user]) } + field :config_source, PipelineConfigSourceEnum, null: true, description: "Config source of the pipeline (#{::Enums::Ci::Pipeline.config_sources.keys.join(', ').upcase})" + field :duration, GraphQL::INT_TYPE, null: true, description: 'Duration of the pipeline in seconds' + field :coverage, GraphQL::FLOAT_TYPE, null: true, description: 'Coverage percentage' + field :created_at, Types::TimeType, null: false, description: "Timestamp of the pipeline's creation" + field :updated_at, Types::TimeType, null: false, description: "Timestamp of the pipeline's last activity" + field :started_at, Types::TimeType, null: true, description: 'Timestamp when the pipeline was started' + field :finished_at, Types::TimeType, null: true, description: "Timestamp of the pipeline's completion" + field :committed_at, Types::TimeType, null: true, description: "Timestamp of the pipeline's commit" + field :stages, Types::Ci::StageType.connection_type, null: true, description: 'Stages of the pipeline', extras: [:lookahead], resolver: Resolvers::Ci::PipelineStagesResolver + field :user, Types::UserType, null: true, description: 'Pipeline user', resolve: -> (pipeline, _args, _context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, pipeline.user_id).find } + field :retryable, GraphQL::BOOLEAN_TYPE, description: 'Specifies if a pipeline can be retried', method: :retryable?, null: false + field :cancelable, GraphQL::BOOLEAN_TYPE, description: 'Specifies if a pipeline can be canceled', method: :cancelable?, null: false + + field :jobs, + ::Types::Ci::JobType.connection_type, + null: true, + description: 'Jobs belonging to the pipeline', + resolver: ::Resolvers::Ci::JobsResolver + + field :source_job, Types::Ci::JobType, null: true, + description: 'Job where pipeline was triggered from' + + field :downstream, Types::Ci::PipelineType.connection_type, null: true, + description: 'Pipelines this pipeline will trigger', + method: :triggered_pipelines_with_preloads + + field :upstream, Types::Ci::PipelineType, null: true, + description: 'Pipeline that triggered the pipeline', + method: :triggered_by_pipeline + + field :path, GraphQL::STRING_TYPE, null: true, + description: "Relative path to the pipeline's page", + resolve: -> (obj, _args, _ctx) { ::Gitlab::Routing.url_helpers.project_pipeline_path(obj.project, obj) } + + field :project, Types::ProjectType, null: true, + description: 'Project the pipeline belongs to' end end end diff --git a/app/graphql/types/ci/runner_setup_type.rb b/app/graphql/types/ci/runner_setup_type.rb new file mode 100644 index 00000000000..66abcf65adf --- /dev/null +++ b/app/graphql/types/ci/runner_setup_type.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Types + module Ci + # rubocop: disable Graphql/AuthorizeTypes + class RunnerSetupType < BaseObject + graphql_name 'RunnerSetup' + + field :install_instructions, GraphQL::STRING_TYPE, null: false, + description: 'Instructions for installing the runner on the specified architecture' + field :register_instructions, GraphQL::STRING_TYPE, null: true, + description: 'Instructions for registering the runner' + end + end +end diff --git a/app/graphql/types/commit_type.rb b/app/graphql/types/commit_type.rb index dd4b4c3b114..c24b47f08ef 100644 --- a/app/graphql/types/commit_type.rb +++ b/app/graphql/types/commit_type.rb @@ -40,16 +40,9 @@ module Types field :author, type: Types::UserType, null: true, description: 'Author of the commit' - field :pipelines, Types::Ci::PipelineType.connection_type, + field :pipelines, null: true, description: 'Pipelines of the commit ordered latest first', resolver: Resolvers::CommitPipelinesResolver - - field :latest_pipeline, - type: Types::Ci::PipelineType, - null: true, - deprecated: { reason: 'Use `pipelines`', milestone: '12.5' }, - description: 'Latest pipeline of the commit', - resolver: Resolvers::CommitPipelinesResolver.last end end diff --git a/app/graphql/types/container_repository_cleanup_status_enum.rb b/app/graphql/types/container_repository_cleanup_status_enum.rb new file mode 100644 index 00000000000..6e654e65360 --- /dev/null +++ b/app/graphql/types/container_repository_cleanup_status_enum.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Types + class ContainerRepositoryCleanupStatusEnum < BaseEnum + graphql_name 'ContainerRepositoryCleanupStatus' + description 'Status of the tags cleanup of a container repository' + + value 'UNSCHEDULED', value: 'cleanup_unscheduled', description: 'The tags cleanup is not scheduled. This is the default state.' + value 'SCHEDULED', value: 'cleanup_scheduled', description: 'The tags cleanup is scheduled and is going to be executed shortly.' + value 'UNFINISHED', value: 'cleanup_unfinished', description: 'The tags cleanup has been partially executed. There are still remaining tags to delete.' + value 'ONGOING', value: 'cleanup_ongoing', description: 'The tags cleanup is ongoing.' + end +end diff --git a/app/graphql/types/container_repository_details_type.rb b/app/graphql/types/container_repository_details_type.rb new file mode 100644 index 00000000000..34523f3ea4a --- /dev/null +++ b/app/graphql/types/container_repository_details_type.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Types + class ContainerRepositoryDetailsType < Types::ContainerRepositoryType + graphql_name 'ContainerRepositoryDetails' + + description 'Details of a container repository' + + authorize :read_container_image + + field :tags, + Types::ContainerRepositoryTagType.connection_type, + null: true, + description: 'Tags of the container repository', + max_page_size: 20 + + def can_delete + Ability.allowed?(current_user, :destroy_container_image, object) + end + end +end diff --git a/app/graphql/types/container_repository_status_enum.rb b/app/graphql/types/container_repository_status_enum.rb new file mode 100644 index 00000000000..8f3ba8f1083 --- /dev/null +++ b/app/graphql/types/container_repository_status_enum.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Types + class ContainerRepositoryStatusEnum < BaseEnum + graphql_name 'ContainerRepositoryStatus' + description 'Status of a container repository' + + ::ContainerRepository.statuses.keys.each do |status| + value status.upcase, value: status, description: "#{status.titleize} status." + end + end +end diff --git a/app/graphql/types/container_repository_tag_type.rb b/app/graphql/types/container_repository_tag_type.rb new file mode 100644 index 00000000000..25e605b689d --- /dev/null +++ b/app/graphql/types/container_repository_tag_type.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Types + class ContainerRepositoryTagType < BaseObject + graphql_name 'ContainerRepositoryTag' + + description 'A tag from a container repository' + + authorize :read_container_image + + field :name, GraphQL::STRING_TYPE, null: false, description: 'Name of the tag.' + field :path, GraphQL::STRING_TYPE, null: false, description: 'Path of the tag.' + field :location, GraphQL::STRING_TYPE, null: false, description: 'URL of the tag.' + field :digest, GraphQL::STRING_TYPE, null: false, description: 'Digest of the tag.' + field :revision, GraphQL::STRING_TYPE, null: false, description: 'Revision of the tag.' + field :short_revision, GraphQL::STRING_TYPE, null: false, description: 'Short revision of the tag.' + field :total_size, GraphQL::INT_TYPE, null: false, description: 'The size of the tag.' + field :created_at, Types::TimeType, null: false, description: 'Timestamp when the tag was created.' + field :can_delete, GraphQL::BOOLEAN_TYPE, null: false, description: 'Can the current user delete this tag.' + + def can_delete + Ability.allowed?(current_user, :destroy_container_image, object) + end + end +end diff --git a/app/graphql/types/container_repository_type.rb b/app/graphql/types/container_repository_type.rb new file mode 100644 index 00000000000..45d19fdbc50 --- /dev/null +++ b/app/graphql/types/container_repository_type.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Types + class ContainerRepositoryType < BaseObject + graphql_name 'ContainerRepository' + + description 'A container repository' + + authorize :read_container_image + + field :id, GraphQL::ID_TYPE, null: false, description: 'ID of the container repository.' + field :name, GraphQL::STRING_TYPE, null: false, description: 'Name of the container repository.' + field :path, GraphQL::STRING_TYPE, null: false, description: 'Path of the container repository.' + field :location, GraphQL::STRING_TYPE, null: false, description: 'URL of the container repository.' + field :created_at, Types::TimeType, null: false, description: 'Timestamp when the container repository was created.' + field :updated_at, Types::TimeType, null: false, description: 'Timestamp when the container repository was updated.' + 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 :expiration_policy_cleanup_status, Types::ContainerRepositoryCleanupStatusEnum, null: true, description: 'The tags cleanup status for the container repository.' + field :status, Types::ContainerRepositoryStatusEnum, null: true, description: 'Status of the container repository.' + field :tags_count, GraphQL::INT_TYPE, null: false, description: 'Number of tags associated with this image.' + field :can_delete, GraphQL::BOOLEAN_TYPE, null: false, description: 'Can the current user delete the container repository.' + + def can_delete + Ability.allowed?(current_user, :update_container_image, object) + end + end +end diff --git a/app/graphql/types/countable_connection_type.rb b/app/graphql/types/countable_connection_type.rb index 2538366b786..f67194d99b3 100644 --- a/app/graphql/types/countable_connection_type.rb +++ b/app/graphql/types/countable_connection_type.rb @@ -3,7 +3,7 @@ module Types # rubocop: disable Graphql/AuthorizeTypes class CountableConnectionType < GraphQL::Types::Relay::BaseConnection - field :count, Integer, null: false, + field :count, GraphQL::INT_TYPE, null: false, description: 'Total count of collection' def count diff --git a/app/graphql/types/custom_emoji_type.rb b/app/graphql/types/custom_emoji_type.rb new file mode 100644 index 00000000000..f7d1a7800bc --- /dev/null +++ b/app/graphql/types/custom_emoji_type.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Types + class CustomEmojiType < BaseObject + graphql_name 'CustomEmoji' + description 'A custom emoji uploaded by user' + + authorize :read_custom_emoji + + field :id, ::Types::GlobalIDType[::CustomEmoji], + null: false, + description: 'The ID of the emoji' + + field :name, GraphQL::STRING_TYPE, + null: false, + description: 'The name of the emoji' + + field :url, GraphQL::STRING_TYPE, + null: false, + method: :file, + description: 'The link to file of the emoji' + + field :external, GraphQL::BOOLEAN_TYPE, + null: false, + description: 'Whether the emoji is an external link' + end +end diff --git a/app/graphql/types/environment_type.rb b/app/graphql/types/environment_type.rb index e4631a4a903..e3885668643 100644 --- a/app/graphql/types/environment_type.rb +++ b/app/graphql/types/environment_type.rb @@ -18,9 +18,8 @@ module Types field :state, GraphQL::STRING_TYPE, null: false, description: 'State of the environment, for example: available/stopped' - field :path, GraphQL::STRING_TYPE, null: true, - description: 'The path to the environment. Will always return null ' \ - 'if `expose_environment_path_in_alert_details` feature flag is disabled' + field :path, GraphQL::STRING_TYPE, null: false, + description: 'The path to the environment.' field :metrics_dashboard, Types::Metrics::DashboardType, null: true, description: 'Metrics dashboard schema for the environment', diff --git a/app/graphql/types/global_id_type.rb b/app/graphql/types/global_id_type.rb index 9ae9ba32c13..4c51d4248dd 100644 --- a/app/graphql/types/global_id_type.rb +++ b/app/graphql/types/global_id_type.rb @@ -30,6 +30,8 @@ module Types # @param value [String] # @return [GID] def self.coerce_input(value, _ctx) + return if value.nil? + gid = GlobalID.parse(value) raise GraphQL::CoercionError, "#{value.inspect} is not a valid Global ID" if gid.nil? raise GraphQL::CoercionError, "#{value.inspect} is not a Gitlab Global ID" unless gid.app == GlobalID.app diff --git a/app/graphql/types/grafana_integration_type.rb b/app/graphql/types/grafana_integration_type.rb index 7db733fc62a..6625af36f82 100644 --- a/app/graphql/types/grafana_integration_type.rb +++ b/app/graphql/types/grafana_integration_type.rb @@ -16,13 +16,5 @@ module Types description: 'Timestamp of the issue\'s creation' field :updated_at, Types::TimeType, null: false, description: 'Timestamp of the issue\'s last activity' - - field :token, GraphQL::STRING_TYPE, null: false, - deprecated: { reason: 'Plain text token has been masked for security reasons', milestone: '12.7' }, - description: 'API token for the Grafana integration' - - def token - object.masked_token - end end end diff --git a/app/graphql/types/group_invitation_type.rb b/app/graphql/types/group_invitation_type.rb new file mode 100644 index 00000000000..0372ce178ff --- /dev/null +++ b/app/graphql/types/group_invitation_type.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Types + class GroupInvitationType < BaseObject + expose_permissions Types::PermissionTypes::Group + authorize :read_group + + implements InvitationInterface + + graphql_name 'GroupInvitation' + description 'Represents a Group Invitation' + + field :group, Types::GroupType, null: true, + description: 'Group that a User is invited to', + resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.source_id).find } + end +end diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index 199cc0308c5..fb028184488 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -17,6 +17,10 @@ module Types group.avatar_url(only_path: false) end + field :custom_emoji, Types::CustomEmojiType.connection_type, null: true, + description: 'Custom emoji within this namespace', + feature_flag: :custom_emoji + field :share_with_group_lock, GraphQL::BOOLEAN_TYPE, null: true, description: 'Indicates if sharing a project with another group within this group is prevented' @@ -82,11 +86,16 @@ module Types end field :group_members, - Types::GroupMemberType.connection_type, description: 'A membership of a user within this group', - extras: [:lookahead], resolver: Resolvers::GroupMembersResolver + field :container_repositories, + Types::ContainerRepositoryType.connection_type, + null: true, + description: 'Container repositories of the project', + resolver: Resolvers::ContainerRepositoriesResolver, + authorize: :read_container_image + def label(title:) BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args| LabelsFinder diff --git a/app/graphql/types/invitation_interface.rb b/app/graphql/types/invitation_interface.rb new file mode 100644 index 00000000000..a29716c292e --- /dev/null +++ b/app/graphql/types/invitation_interface.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Types + module InvitationInterface + include BaseInterface + + field :email, GraphQL::STRING_TYPE, null: false, + description: 'Email of the member to invite' + + field :access_level, Types::AccessLevelType, null: true, + description: 'GitLab::Access level' + + field :created_by, Types::UserType, null: true, + description: 'User that authorized membership' + + field :created_at, Types::TimeType, null: true, + description: 'Date and time the membership was created' + + field :updated_at, Types::TimeType, null: true, + description: 'Date and time the membership was last updated' + + field :expires_at, Types::TimeType, null: true, + description: 'Date and time the membership expires' + + field :user, Types::UserType, null: true, + description: 'User that is associated with the member object' + + definition_methods do + def resolve_type(object, context) + case object + when GroupMember + Types::GroupInvitationType + when ProjectMember + Types::ProjectInvitationType + else + raise ::Gitlab::Graphql::Errors::BaseError, "Unknown member type #{object.class.name}" + end + end + end + end +end diff --git a/app/graphql/types/issue_connection_type.rb b/app/graphql/types/issue_connection_type.rb new file mode 100644 index 00000000000..2e0f05f741e --- /dev/null +++ b/app/graphql/types/issue_connection_type.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Types + # rubocop: disable Graphql/AuthorizeTypes + class IssueConnectionType < CountableConnectionType + end +end + +Types::IssueConnectionType.prepend_if_ee('::EE::Types::IssueConnectionType') diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index 487508f448f..49c84f75e1a 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -4,7 +4,7 @@ module Types class IssueType < BaseObject graphql_name 'Issue' - connection_type_class(Types::CountableConnectionType) + connection_type_class(Types::IssueConnectionType) implements(Types::Notes::NoteableType) implements(Types::CurrentUserTodos) @@ -41,6 +41,9 @@ module Types field :assignees, Types::UserType.connection_type, null: true, description: 'Assignees of the issue' + field :updated_by, Types::UserType, null: true, + description: 'User that last updated the issue' + field :labels, Types::LabelType.connection_type, null: true, description: 'Labels of the issue' field :milestone, Types::MilestoneType, null: true, @@ -59,6 +62,8 @@ module Types description: 'Number of downvotes the issue has received' field :user_notes_count, GraphQL::INT_TYPE, null: false, description: 'Number of user notes of the issue' + field :user_discussions_count, GraphQL::INT_TYPE, null: false, + description: 'Number of user discussions in the issue' field :web_path, GraphQL::STRING_TYPE, null: false, method: :issue_path, description: 'Web path of the issue' field :web_url, GraphQL::STRING_TYPE, null: false, @@ -68,12 +73,19 @@ module Types field :participants, Types::UserType.connection_type, null: true, complexity: 5, description: 'List of participants in the issue' + field :emails_disabled, GraphQL::BOOLEAN_TYPE, null: false, + method: :project_emails_disabled?, + description: 'Indicates if a project has email notifications disabled: `true` if email notifications are disabled' field :subscribed, GraphQL::BOOLEAN_TYPE, method: :subscribed?, null: false, complexity: 5, description: 'Indicates the currently logged in user is subscribed to the issue' field :time_estimate, GraphQL::INT_TYPE, null: false, description: 'Time estimate of the issue' field :total_time_spent, GraphQL::INT_TYPE, null: false, description: 'Total time reported as spent on the issue' + field :human_time_estimate, GraphQL::STRING_TYPE, null: true, + description: 'Human-readable time estimate of the issue' + field :human_total_time_spent, GraphQL::STRING_TYPE, null: true, + description: 'Human-readable total time reported as spent on the issue' field :closed_at, Types::TimeType, null: true, description: 'Timestamp of when the issue was closed' @@ -86,11 +98,6 @@ module Types field :task_completion_status, Types::TaskCompletionStatus, null: false, description: 'Task completion status of the issue' - field :designs, Types::DesignManagement::DesignCollectionType, null: true, - method: :design_collection, - deprecated: { reason: 'Use `designCollection`', milestone: '12.2' }, - description: 'The designs associated with this issue' - field :design_collection, Types::DesignManagement::DesignCollectionType, null: true, description: 'Collection of design images associated with this issue' @@ -106,14 +113,48 @@ module Types field :severity, Types::IssuableSeverityEnum, null: true, description: 'Severity level of the incident' + field :moved, GraphQL::BOOLEAN_TYPE, method: :moved?, null: true, + description: 'Indicates if issue got moved from other project' + + field :moved_to, Types::IssueType, null: true, + description: 'Updated Issue after it got moved to another project' + + def user_notes_count + BatchLoader::GraphQL.for(object.id).batch(key: :issue_user_notes_count) do |ids, loader, args| + counts = Note.count_for_collection(ids, 'Issue').index_by(&:noteable_id) + + ids.each do |id| + loader.call(id, counts[id]&.count || 0) + end + end + end + + def user_discussions_count + BatchLoader::GraphQL.for(object.id).batch(key: :issue_user_discussions_count) do |ids, loader, args| + counts = Note.count_for_collection(ids, 'Issue', 'COUNT(DISTINCT discussion_id) as count').index_by(&:noteable_id) + + ids.each do |id| + loader.call(id, counts[id]&.count || 0) + end + end + end + def author Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find end + def updated_by + Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.updated_by_id).find + end + def milestone Gitlab::Graphql::Loaders::BatchModelLoader.new(Milestone, object.milestone_id).find end + def moved_to + Gitlab::Graphql::Loaders::BatchModelLoader.new(Issue, object.moved_to_id).find + end + def discussion_locked !!object.discussion_locked end diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index 372aeac055b..e68d6706c43 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -68,6 +68,8 @@ module Types description: 'SHA of the merge request commit (set once merged)' field :user_notes_count, GraphQL::INT_TYPE, null: true, description: 'User notes count of the merge request' + field :user_discussions_count, GraphQL::INT_TYPE, null: true, + description: 'Number of user discussions in the merge request' field :should_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :should_remove_source_branch?, null: true, description: 'Indicates if the source branch of the merge request will be deleted after merge' field :force_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :force_remove_source_branch?, null: true, @@ -86,9 +88,6 @@ module Types description: 'Rebase commit SHA of the merge request' field :rebase_in_progress, GraphQL::BOOLEAN_TYPE, method: :rebase_in_progress?, null: false, calls_gitaly: true, description: 'Indicates if there is a rebase currently in progress for the merge request' - field :merge_commit_message, GraphQL::STRING_TYPE, method: :default_merge_commit_message, null: true, - deprecated: { reason: 'Use `defaultMergeCommitMessage`', milestone: '11.8' }, - description: 'Default merge commit message of the merge request' field :default_merge_commit_message, GraphQL::STRING_TYPE, null: true, description: 'Default merge commit message of the merge request' field :merge_ongoing, GraphQL::BOOLEAN_TYPE, method: :merge_ongoing?, null: false, @@ -112,14 +111,13 @@ module Types field :head_pipeline, Types::Ci::PipelineType, null: true, method: :actual_head_pipeline, description: 'The pipeline running on the branch HEAD of the merge request' - field :pipelines, Types::Ci::PipelineType.connection_type, + field :pipelines, null: true, description: 'Pipelines for the merge request', resolver: Resolvers::MergeRequestPipelinesResolver field :milestone, Types::MilestoneType, null: true, - description: 'The milestone of the merge request', - resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Milestone, obj.milestone_id).find } + description: 'The milestone of the merge request' field :assignees, Types::UserType.connection_type, null: true, complexity: 5, description: 'Assignees of the merge request' field :author, Types::UserType, null: true, @@ -159,17 +157,25 @@ module Types object.approved_by_users end - # rubocop: disable CodeReuse/ActiveRecord def user_notes_count BatchLoader::GraphQL.for(object.id).batch(key: :merge_request_user_notes_count) do |ids, loader, args| - counts = Note.where(noteable_type: 'MergeRequest', noteable_id: ids).user.group(:noteable_id).count + counts = Note.count_for_collection(ids, 'MergeRequest').index_by(&:noteable_id) + + ids.each do |id| + loader.call(id, counts[id]&.count || 0) + end + end + end + + def user_discussions_count + BatchLoader::GraphQL.for(object.id).batch(key: :merge_request_user_discussions_count) do |ids, loader, args| + counts = Note.count_for_collection(ids, 'MergeRequest', 'COUNT(DISTINCT discussion_id) as count').index_by(&:noteable_id) ids.each do |id| - loader.call(id, counts[id] || 0) + loader.call(id, counts[id]&.count || 0) end end end - # rubocop: enable CodeReuse/ActiveRecord def diff_stats(path: nil) stats = Array.wrap(object.diff_stats&.to_a) diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 3f48e7b4a16..75ccac6d590 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -11,6 +11,13 @@ module Types mount_mutation Mutations::AlertManagement::UpdateAlertStatus mount_mutation Mutations::AlertManagement::Alerts::SetAssignees mount_mutation Mutations::AlertManagement::Alerts::Todo::Create + mount_mutation Mutations::AlertManagement::HttpIntegration::Create + mount_mutation Mutations::AlertManagement::HttpIntegration::Update + mount_mutation Mutations::AlertManagement::HttpIntegration::ResetToken + mount_mutation Mutations::AlertManagement::HttpIntegration::Destroy + mount_mutation Mutations::AlertManagement::PrometheusIntegration::Create + mount_mutation Mutations::AlertManagement::PrometheusIntegration::Update + mount_mutation Mutations::AlertManagement::PrometheusIntegration::ResetToken mount_mutation Mutations::AwardEmojis::Add mount_mutation Mutations::AwardEmojis::Remove mount_mutation Mutations::AwardEmojis::Toggle @@ -22,6 +29,7 @@ module Types mount_mutation Mutations::Boards::Lists::Destroy mount_mutation Mutations::Branches::Create, calls_gitaly: true mount_mutation Mutations::Commits::Create, calls_gitaly: true + mount_mutation Mutations::CustomEmoji::Create, feature_flag: :custom_emoji mount_mutation Mutations::Discussions::ToggleResolve mount_mutation Mutations::Issues::Create mount_mutation Mutations::Issues::SetAssignees @@ -32,6 +40,7 @@ module Types mount_mutation Mutations::Issues::SetSubscription mount_mutation Mutations::Issues::Update mount_mutation Mutations::Issues::Move + mount_mutation Mutations::Labels::Create mount_mutation Mutations::MergeRequests::Create mount_mutation Mutations::MergeRequests::Update mount_mutation Mutations::MergeRequests::SetLabels @@ -53,7 +62,13 @@ module Types description: 'Updates a DiffNote on an image (a `Note` where the `position.positionType` is `"image"`). ' \ 'If the body of the Note contains only quick actions, the Note will be ' \ 'destroyed during the update, and no Note will be returned' + mount_mutation Mutations::Notes::RepositionImageDiffNote mount_mutation Mutations::Notes::Destroy + mount_mutation Mutations::Releases::Create + mount_mutation Mutations::Terraform::State::Delete + mount_mutation Mutations::Terraform::State::Lock + mount_mutation Mutations::Terraform::State::Unlock + mount_mutation Mutations::Todos::Create mount_mutation Mutations::Todos::MarkDone mount_mutation Mutations::Todos::Restore mount_mutation Mutations::Todos::MarkAllDone @@ -68,6 +83,7 @@ module Types mount_mutation Mutations::DesignManagement::Delete, calls_gitaly: true mount_mutation Mutations::DesignManagement::Move mount_mutation Mutations::ContainerExpirationPolicies::Update + mount_mutation Mutations::ContainerRepositories::Destroy mount_mutation Mutations::Ci::PipelineCancel mount_mutation Mutations::Ci::PipelineDestroy mount_mutation Mutations::Ci::PipelineRetry diff --git a/app/graphql/types/notes/update_diff_image_position_input_type.rb b/app/graphql/types/notes/update_diff_image_position_input_type.rb index af99764f9f2..1b915b65ae9 100644 --- a/app/graphql/types/notes/update_diff_image_position_input_type.rb +++ b/app/graphql/types/notes/update_diff_image_position_input_type.rb @@ -23,6 +23,14 @@ module Types argument :height, GraphQL::INT_TYPE, required: false, description: copy_field_description(Types::Notes::DiffPositionType, :height) + + def prepare + to_h.compact.tap do |properties| + if properties.empty? + raise GraphQL::ExecutionError, "At least one property of `#{self.class.graphql_name}` must be set" + end + end + end end # rubocop: enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/permission_types/custom_emoji.rb b/app/graphql/types/permission_types/custom_emoji.rb new file mode 100644 index 00000000000..0b2e7da44f5 --- /dev/null +++ b/app/graphql/types/permission_types/custom_emoji.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Types + module PermissionTypes + class CustomEmoji < BasePermissionType + graphql_name 'CustomEmojiPermissions' + + abilities :create_custom_emoji, :read_custom_emoji + end + end +end diff --git a/app/graphql/types/permission_types/note.rb b/app/graphql/types/permission_types/note.rb index a585d3daaa8..923f2b660fe 100644 --- a/app/graphql/types/permission_types/note.rb +++ b/app/graphql/types/permission_types/note.rb @@ -5,7 +5,7 @@ module Types class Note < BasePermissionType graphql_name 'NotePermissions' - abilities :read_note, :create_note, :admin_note, :resolve_note, :award_emoji + abilities :read_note, :create_note, :admin_note, :resolve_note, :reposition_note, :award_emoji end end end diff --git a/app/graphql/types/project_invitation_type.rb b/app/graphql/types/project_invitation_type.rb new file mode 100644 index 00000000000..a5367a4f204 --- /dev/null +++ b/app/graphql/types/project_invitation_type.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Types + class ProjectInvitationType < BaseObject + graphql_name 'ProjectInvitation' + description 'Represents a Project Membership Invitation' + + expose_permissions Types::PermissionTypes::Project + + implements InvitationInterface + + authorize :read_project + + field :project, Types::ProjectType, null: true, + description: 'Project ID for the project of the invitation' + + def project + Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.source_id).find + end + end +end diff --git a/app/graphql/types/project_statistics_type.rb b/app/graphql/types/project_statistics_type.rb index b3916e42e92..26cb5ab59b5 100644 --- a/app/graphql/types/project_statistics_type.rb +++ b/app/graphql/types/project_statistics_type.rb @@ -10,18 +10,20 @@ module Types description: 'Commit count of the project' field :storage_size, GraphQL::FLOAT_TYPE, null: false, - description: 'Storage size of the project' + description: 'Storage size of the project in bytes' field :repository_size, GraphQL::FLOAT_TYPE, null: false, - description: 'Repository size of the project' + description: 'Repository size of the project in bytes' field :lfs_objects_size, GraphQL::FLOAT_TYPE, null: false, - description: 'Large File Storage (LFS) object size of the project' + description: 'Large File Storage (LFS) object size of the project in bytes' field :build_artifacts_size, GraphQL::FLOAT_TYPE, null: false, - description: 'Build artifacts size of the project' + description: 'Build artifacts size of the project in bytes' field :packages_size, GraphQL::FLOAT_TYPE, null: false, - description: 'Packages size of the project' + description: 'Packages size of the project in bytes' field :wiki_size, GraphQL::FLOAT_TYPE, null: true, - description: 'Wiki size of the project' + description: 'Wiki size of the project in bytes' field :snippets_size, GraphQL::FLOAT_TYPE, null: true, - description: 'Snippets size of the project' + description: 'Snippets size of the project in bytes' + field :uploads_size, GraphQL::FLOAT_TYPE, null: true, + description: 'Uploads 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 c7fc193abe8..5a436886117 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -161,7 +161,6 @@ module Types resolver: Resolvers::ProjectMilestonesResolver field :project_members, - Types::MemberInterface.connection_type, description: 'Members of the project', resolver: Resolvers::ProjectMembersResolver @@ -188,9 +187,9 @@ module Types resolver: Resolvers::PackagesResolver field :pipelines, - Types::Ci::PipelineType.connection_type, null: true, description: 'Build pipelines of the project', + extras: [:lookahead], resolver: Resolvers::ProjectPipelinesResolver field :pipeline, @@ -267,6 +266,12 @@ module Types description: 'Counts of alerts by status for the project', resolver: Resolvers::AlertManagement::AlertStatusCountsResolver + field :alert_management_integrations, + Types::AlertManagement::IntegrationType.connection_type, + null: true, + description: 'Integrations which can receive alerts for the project', + resolver: Resolvers::AlertManagement::IntegrationsResolver + field :releases, Types::ReleaseType.connection_type, null: true, @@ -285,6 +290,12 @@ module Types null: true, description: 'The container expiration policy of the project' + field :container_repositories, + Types::ContainerRepositoryType.connection_type, + null: true, + description: 'Container repositories of the project', + resolver: Resolvers::ContainerRepositoriesResolver + field :label, Types::LabelType, null: true, diff --git a/app/graphql/types/projects/namespace_project_sort_enum.rb b/app/graphql/types/projects/namespace_project_sort_enum.rb index 1e13deb6508..ede29748beb 100644 --- a/app/graphql/types/projects/namespace_project_sort_enum.rb +++ b/app/graphql/types/projects/namespace_project_sort_enum.rb @@ -7,6 +7,7 @@ module Types description 'Values for sorting projects' value 'SIMILARITY', 'Most similar to the search query', value: :similarity + value 'STORAGE', 'Sort by storage size', value: :storage end end end diff --git a/app/graphql/types/projects/service_type_enum.rb b/app/graphql/types/projects/service_type_enum.rb index 340fdff6b86..34e06c67be6 100644 --- a/app/graphql/types/projects/service_type_enum.rb +++ b/app/graphql/types/projects/service_type_enum.rb @@ -5,7 +5,7 @@ module Types class ServiceTypeEnum < BaseEnum graphql_name 'ServiceType' - ::Service.services_types.each do |service_type| + ::Service.available_services_types(include_dev: false).each do |service_type| value service_type.underscore.upcase, value: service_type end end diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index bd4b53bdaa7..d194b0979b3 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -50,10 +50,14 @@ module Types field :milestone, ::Types::MilestoneType, null: true, description: 'Find a milestone' do - argument :id, ::Types::GlobalIDType[Milestone], - required: true, - description: 'Find a milestone by its ID' - end + argument :id, ::Types::GlobalIDType[Milestone], required: true, description: 'Find a milestone by its ID' + end + + field :container_repository, Types::ContainerRepositoryDetailsType, + null: true, + description: 'Find a container repository' do + argument :id, ::Types::GlobalIDType[::ContainerRepository], required: true, description: 'The global ID of the container repository' + end field :user, Types::UserType, null: true, @@ -84,6 +88,10 @@ module Types null: true, description: 'Supported runner platforms', resolver: Resolvers::Ci::RunnerPlatformsResolver + field :runner_setup, Types::Ci::RunnerSetupType, null: true, + description: 'Get runner setup instructions', + resolver: Resolvers::Ci::RunnerSetupResolver + def design_management DesignManagementObject.new(nil) end @@ -101,6 +109,13 @@ module Types id = ::Types::GlobalIDType[Milestone].coerce_isolated_input(id) GitlabSchema.find_by_gid(id) end + + def container_repository(id:) + # TODO: remove this line when the compatibility layer is removed + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = ::Types::GlobalIDType[::ContainerRepository].coerce_isolated_input(id) + GitlabSchema.find_by_gid(id) + end end end diff --git a/app/graphql/types/release_asset_link_input_type.rb b/app/graphql/types/release_asset_link_input_type.rb new file mode 100644 index 00000000000..d13861fad8f --- /dev/null +++ b/app/graphql/types/release_asset_link_input_type.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Types + # rubocop: disable Graphql/AuthorizeTypes + class ReleaseAssetLinkInputType < BaseInputObject + graphql_name 'ReleaseAssetLinkInput' + description 'Fields that are available when modifying a release asset link' + + argument :name, GraphQL::STRING_TYPE, + required: true, + description: 'Name of the asset link' + + argument :url, GraphQL::STRING_TYPE, + required: true, + description: 'URL of the asset link' + + argument :direct_asset_path, GraphQL::STRING_TYPE, + required: false, as: :filepath, + description: 'Relative path for a direct asset link' + + argument :link_type, Types::ReleaseAssetLinkTypeEnum, + required: false, default_value: 'other', + description: 'The type of the asset link' + end +end diff --git a/app/graphql/types/release_asset_link_type.rb b/app/graphql/types/release_asset_link_type.rb index 0e519ece791..8fb051f5627 100644 --- a/app/graphql/types/release_asset_link_type.rb +++ b/app/graphql/types/release_asset_link_type.rb @@ -24,10 +24,8 @@ module Types def direct_asset_url return object.url unless object.filepath - release = object.release - project = release.project - - Gitlab::Routing.url_helpers.project_release_url(project, release) << object.filepath + release = object.release.present + release.download_url(object.filepath) end end end diff --git a/app/graphql/types/release_asset_link_type_enum.rb b/app/graphql/types/release_asset_link_type_enum.rb index 01862ada56d..70601b9f8da 100644 --- a/app/graphql/types/release_asset_link_type_enum.rb +++ b/app/graphql/types/release_asset_link_type_enum.rb @@ -3,7 +3,7 @@ module Types class ReleaseAssetLinkTypeEnum < BaseEnum graphql_name 'ReleaseAssetLinkType' - description 'Type of the link: `other`, `runbook`, `image`, `package`; defaults to `other`' + description 'Type of the link: `other`, `runbook`, `image`, `package`' ::Releases::Link.link_types.keys.each do |link_type| value link_type.upcase, value: link_type, description: "#{link_type.titleize} link type" diff --git a/app/graphql/types/release_assets_input_type.rb b/app/graphql/types/release_assets_input_type.rb new file mode 100644 index 00000000000..3fcb517e044 --- /dev/null +++ b/app/graphql/types/release_assets_input_type.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Types + # rubocop: disable Graphql/AuthorizeTypes + class ReleaseAssetsInputType < BaseInputObject + graphql_name 'ReleaseAssetsInput' + description 'Fields that are available when modifying release assets' + + argument :links, [Types::ReleaseAssetLinkInputType], + required: false, + description: 'A list of asset links to associate to the release' + end +end diff --git a/app/graphql/types/release_links_type.rb b/app/graphql/types/release_links_type.rb index f61a16f5b67..619bb1e6c3a 100644 --- a/app/graphql/types/release_links_type.rb +++ b/app/graphql/types/release_links_type.rb @@ -12,12 +12,18 @@ module Types field :self_url, GraphQL::STRING_TYPE, null: true, description: 'HTTP URL of the release' - field :merge_requests_url, GraphQL::STRING_TYPE, null: true, - description: 'HTTP URL of the merge request page filtered by this release' - field :issues_url, GraphQL::STRING_TYPE, null: true, - description: 'HTTP URL of the issues page filtered by this release' field :edit_url, GraphQL::STRING_TYPE, null: true, description: "HTTP URL of the release's edit page", authorize: :update_release + field :opened_merge_requests_url, GraphQL::STRING_TYPE, null: true, + description: 'HTTP URL of the merge request page, filtered by this release and `state=open`' + field :merged_merge_requests_url, GraphQL::STRING_TYPE, null: true, + description: 'HTTP URL of the merge request page , filtered by this release and `state=merged`' + field :closed_merge_requests_url, GraphQL::STRING_TYPE, null: true, + description: 'HTTP URL of the merge request page , filtered by this release and `state=closed`' + field :opened_issues_url, GraphQL::STRING_TYPE, null: true, + description: 'HTTP URL of the issues page, filtered by this release and `state=open`' + field :closed_issues_url, GraphQL::STRING_TYPE, null: true, + description: 'HTTP URL of the issues page, filtered by this release and `state=closed`' end end diff --git a/app/graphql/types/release_sort_enum.rb b/app/graphql/types/release_sort_enum.rb new file mode 100644 index 00000000000..2f9af1bced9 --- /dev/null +++ b/app/graphql/types/release_sort_enum.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Types + # Not inheriting from Types::SortEnum since we only want + # to implement a subset of the sort values it defines. + class ReleaseSortEnum < BaseEnum + graphql_name 'ReleaseSort' + description 'Values for sorting releases' + + # Borrowed from Types::SortEnum + # These values/descriptions should stay in-sync as much as possible. + value 'CREATED_DESC', 'Created at descending order', value: :created_desc + value 'CREATED_ASC', 'Created at ascending order', value: :created_asc + + value 'RELEASED_AT_DESC', 'Released at by descending order', value: :released_at_desc + value 'RELEASED_AT_ASC', 'Released at by ascending order', value: :released_at_asc + end +end diff --git a/app/graphql/types/root_storage_statistics_type.rb b/app/graphql/types/root_storage_statistics_type.rb index 224e8c7ee03..21448b33bb5 100644 --- a/app/graphql/types/root_storage_statistics_type.rb +++ b/app/graphql/types/root_storage_statistics_type.rb @@ -14,5 +14,6 @@ module Types field :wiki_size, GraphQL::FLOAT_TYPE, null: false, description: 'The wiki size in bytes' field :snippets_size, GraphQL::FLOAT_TYPE, null: false, description: 'The snippets size in bytes' field :pipeline_artifacts_size, GraphQL::FLOAT_TYPE, null: false, description: 'The CI pipeline artifacts size in bytes' + field :uploads_size, GraphQL::FLOAT_TYPE, null: false, description: 'The uploads size in bytes' end end diff --git a/app/graphql/types/security/report_type_enum.rb b/app/graphql/types/security/report_type_enum.rb new file mode 100644 index 00000000000..ee67f68b27b --- /dev/null +++ b/app/graphql/types/security/report_type_enum.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Types + module Security + class ReportTypeEnum < BaseEnum + graphql_name 'SecurityReportTypeEnum' + + ::Security::SecurityJobsFinder.allowed_job_types.each do |report_type| + value report_type.upcase, + value: report_type, + description: "#{report_type.upcase.to_s.tr('_', ' ')} scan report" + end + end + end +end diff --git a/app/graphql/types/snippet_type.rb b/app/graphql/types/snippet_type.rb index 495c25c1776..f587adf207f 100644 --- a/app/graphql/types/snippet_type.rb +++ b/app/graphql/types/snippet_type.rb @@ -13,7 +13,7 @@ module Types expose_permissions Types::PermissionTypes::Snippet - field :id, GraphQL::ID_TYPE, + field :id, Types::GlobalIDType[::Snippet], description: 'ID of the snippet', null: false diff --git a/app/graphql/types/terraform/state_type.rb b/app/graphql/types/terraform/state_type.rb index f25f3a7789b..05b6d130f19 100644 --- a/app/graphql/types/terraform/state_type.rb +++ b/app/graphql/types/terraform/state_type.rb @@ -7,6 +7,8 @@ module Types authorize :read_terraform_state + connection_type_class(Types::CountableConnectionType) + field :id, GraphQL::ID_TYPE, null: false, description: 'ID of the Terraform state' @@ -25,6 +27,11 @@ module Types null: true, description: 'Timestamp the Terraform state was locked' + field :latest_version, Types::Terraform::StateVersionType, + complexity: 3, + null: true, + description: 'The latest version of the Terraform state' + field :created_at, Types::TimeType, null: false, description: 'Timestamp the Terraform state was created' diff --git a/app/graphql/types/terraform/state_version_type.rb b/app/graphql/types/terraform/state_version_type.rb new file mode 100644 index 00000000000..b1fbe42ecaf --- /dev/null +++ b/app/graphql/types/terraform/state_version_type.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Types + module Terraform + class StateVersionType < BaseObject + graphql_name 'TerraformStateVersion' + + authorize :read_terraform_state + + field :id, GraphQL::ID_TYPE, + null: false, + description: 'ID of the Terraform state version' + + field :created_by_user, Types::UserType, + null: true, + authorize: :read_user, + description: 'The user that created this version', + resolve: -> (version, _, _) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, version.created_by_user_id).find } + + field :job, Types::Ci::JobType, + null: true, + authorize: :read_build, + description: 'The job that created this version', + resolve: -> (version, _, _) { Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Build, version.ci_build_id).find } + + field :created_at, Types::TimeType, + null: false, + description: 'Timestamp the version was created' + + field :updated_at, Types::TimeType, + null: false, + description: 'Timestamp the version was updated' + end + end +end diff --git a/app/graphql/types/user_status_type.rb b/app/graphql/types/user_status_type.rb index ff277c1f8e8..9cf6c862d3d 100644 --- a/app/graphql/types/user_status_type.rb +++ b/app/graphql/types/user_status_type.rb @@ -11,5 +11,7 @@ module Types description: 'User status message' field :emoji, GraphQL::STRING_TYPE, null: true, description: 'String representation of emoji' + field :availability, Types::AvailabilityEnum, null: false, + description: 'User availability status' end end diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb index 8047708776d..11c5369f726 100644 --- a/app/graphql/types/user_type.rb +++ b/app/graphql/types/user_type.rb @@ -32,6 +32,10 @@ module Types field :group_memberships, Types::GroupMemberType.connection_type, null: true, description: 'Group memberships of the user', method: :group_members + field :group_count, GraphQL::INT_TYPE, null: true, + resolver: Resolvers::Users::GroupCountResolver, + description: 'Group count for the user', + feature_flag: :user_group_counts field :status, Types::UserStatusType, null: true, description: 'User status' field :project_memberships, Types::ProjectMemberType.connection_type, null: true, @@ -42,10 +46,10 @@ module Types resolver: Resolvers::UserStarredProjectsResolver # Merge request field: MRs can be either authored or assigned: - field :authored_merge_requests, Types::MergeRequestType.connection_type, null: true, + field :authored_merge_requests, resolver: Resolvers::AuthoredMergeRequestsResolver, description: 'Merge Requests authored by the user' - field :assigned_merge_requests, Types::MergeRequestType.connection_type, null: true, + field :assigned_merge_requests, resolver: Resolvers::AssignedMergeRequestsResolver, description: 'Merge Requests assigned to the user' |