diff --git a/app/assets/javascripts/graphql_shared/possible_types.json b/app/assets/javascripts/graphql_shared/possible_types.json index aa2028c43808da4e2118b4dffc443732b3529746..c581aae59edbd6d9f3df45d9d14ed9987a457985 100644 --- a/app/assets/javascripts/graphql_shared/possible_types.json +++ b/app/assets/javascripts/graphql_shared/possible_types.json @@ -281,6 +281,7 @@ "WorkItemWidgetDesigns", "WorkItemWidgetDevelopment", "WorkItemWidgetEmailParticipants", + "WorkItemWidgetErrorTracking", "WorkItemWidgetHealthStatus", "WorkItemWidgetHierarchy", "WorkItemWidgetIteration", diff --git a/app/graphql/types/work_items/widget_interface.rb b/app/graphql/types/work_items/widget_interface.rb index 573fff53f2e4470f5c680750c0fdde282da50989..abf30bb21c10ace97dc7d4667e1fca4dea388b3d 100644 --- a/app/graphql/types/work_items/widget_interface.rb +++ b/app/graphql/types/work_items/widget_interface.rb @@ -34,7 +34,8 @@ module WidgetInterface ::WorkItems::Widgets::CrmContacts => ::Types::WorkItems::Widgets::CrmContactsType, ::WorkItems::Widgets::EmailParticipants => ::Types::WorkItems::Widgets::EmailParticipantsType, ::WorkItems::Widgets::CustomStatus => ::Types::WorkItems::Widgets::CustomStatusType, - ::WorkItems::Widgets::LinkedResources => ::Types::WorkItems::Widgets::LinkedResourcesType + ::WorkItems::Widgets::LinkedResources => ::Types::WorkItems::Widgets::LinkedResourcesType, + ::WorkItems::Widgets::ErrorTracking => ::Types::WorkItems::Widgets::ErrorTrackingType }.freeze def self.type_mappings diff --git a/app/graphql/types/work_items/widgets/error_tracking_type.rb b/app/graphql/types/work_items/widgets/error_tracking_type.rb new file mode 100644 index 0000000000000000000000000000000000000000..02cfe3bbdfc047690b4b72a4c2e897e474b6fb69 --- /dev/null +++ b/app/graphql/types/work_items/widgets/error_tracking_type.rb @@ -0,0 +1,21 @@ +# 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 -- reason above + class ErrorTrackingType < BaseObject + graphql_name 'WorkItemWidgetErrorTracking' + description 'Represents the error tracking widget' + + implements ::Types::WorkItems::WidgetInterface + + field :identifier, GraphQL::Types::BigInt, null: true, + description: 'Error tracking issue id.', method: :sentry_issue_identifier + end + # rubocop:enable Graphql/AuthorizeTypes + end + end +end diff --git a/app/models/work_items/widget_definition.rb b/app/models/work_items/widget_definition.rb index 0fe67c848ec048d4b406769e0855e63e9cba3618..fa2c602a3c7a6be713461b64ca95eca90024e049 100644 --- a/app/models/work_items/widget_definition.rb +++ b/app/models/work_items/widget_definition.rb @@ -44,7 +44,8 @@ class WidgetDefinition < ApplicationRecord email_participants: 25, custom_status: 26, linked_resources: 27, - custom_fields: 28 # EE-only + custom_fields: 28, # EE-only + error_tracking: 29 } attribute :widget_options, ::Gitlab::Database::Type::IndifferentJsonb.new diff --git a/app/models/work_items/widgets/error_tracking.rb b/app/models/work_items/widgets/error_tracking.rb new file mode 100644 index 0000000000000000000000000000000000000000..16d75efe1af83ac47a4a62c6a32aa7d0a3f345fe --- /dev/null +++ b/app/models/work_items/widgets/error_tracking.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module WorkItems + module Widgets + class ErrorTracking < Base + delegate :sentry_issue, to: :work_item, allow_nil: true + + delegate :sentry_issue_identifier, to: :sentry_issue, allow_nil: true + end + end +end diff --git a/app/services/work_items/data_sync/widgets/error_tracking.rb b/app/services/work_items/data_sync/widgets/error_tracking.rb new file mode 100644 index 0000000000000000000000000000000000000000..684d89a4de313e4d3b6b457a79312a913a8c8c20 --- /dev/null +++ b/app/services/work_items/data_sync/widgets/error_tracking.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module WorkItems + module DataSync + module Widgets + class ErrorTracking < Base + # Placeholder, see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/174793#note_2246113161 + # Need this class to make spec pass at https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/spec/models/ee/work_items/widget_definition_spec.rb#L49 + end + end + end +end diff --git a/db/migrate/20250128163345_add_error_tracking_to_work_item_widget.rb b/db/migrate/20250128163345_add_error_tracking_to_work_item_widget.rb new file mode 100644 index 0000000000000000000000000000000000000000..98b542753f71244d09b119d144815fab421503e0 --- /dev/null +++ b/db/migrate/20250128163345_add_error_tracking_to_work_item_widget.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class AddErrorTrackingToWorkItemWidget < Gitlab::Database::Migration[2.2] + include Gitlab::Database::MigrationHelpers::WorkItems::Widgets + + restrict_gitlab_migration gitlab_schema: :gitlab_main + disable_ddl_transaction! + milestone '17.9' + + WORK_ITEM_TYPE_ENUM_VALUE = 0 # issue + WIDGETS = [ + { + name: 'Error Tracking', + widget_type: 29 + } + ] + + def up + add_widget_definitions(type_enum_value: WORK_ITEM_TYPE_ENUM_VALUE, widgets: WIDGETS) + end + + def down + remove_widget_definitions(type_enum_value: WORK_ITEM_TYPE_ENUM_VALUE, widgets: WIDGETS) + end +end diff --git a/db/schema_migrations/20250128163345 b/db/schema_migrations/20250128163345 new file mode 100644 index 0000000000000000000000000000000000000000..ad6ef33b055798b3d661f374a190f68880d630bb --- /dev/null +++ b/db/schema_migrations/20250128163345 @@ -0,0 +1 @@ +5b03997dd2a4dd27bdf78aa63130438cffcbc37b8234225c1cf780e599e25f09 \ No newline at end of file diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md index 8f3c380316d3c5983358c9482b0a15fe5fe60eed..dcb66adc0881d9facc178e9f5db137546609581e 100644 --- a/doc/api/graphql/reference/_index.md +++ b/doc/api/graphql/reference/_index.md @@ -39279,6 +39279,17 @@ Represents email participants widget. | <a id="workitemwidgetemailparticipantsemailparticipants"></a>`emailParticipants` | [`EmailParticipantTypeConnection`](#emailparticipanttypeconnection) | Collection of email participants associated with the work item. (see [Connections](#connections)) | | <a id="workitemwidgetemailparticipantstype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. | +### `WorkItemWidgetErrorTracking` + +Represents the error tracking widget. + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="workitemwidgeterrortrackingidentifier"></a>`identifier` | [`BigInt`](#bigint) | Error tracking issue id. | +| <a id="workitemwidgeterrortrackingtype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. | + ### `WorkItemWidgetHealthStatus` Represents a health status widget. @@ -43396,6 +43407,7 @@ Type of a work item widget. | <a id="workitemwidgettypedesigns"></a>`DESIGNS` | Designs widget. | | <a id="workitemwidgettypedevelopment"></a>`DEVELOPMENT` | Development widget. | | <a id="workitemwidgettypeemail_participants"></a>`EMAIL_PARTICIPANTS` | Email Participants widget. | +| <a id="workitemwidgettypeerror_tracking"></a>`ERROR_TRACKING` | Error Tracking widget. | | <a id="workitemwidgettypehealth_status"></a>`HEALTH_STATUS` | Health Status widget. | | <a id="workitemwidgettypehierarchy"></a>`HIERARCHY` | Hierarchy widget. | | <a id="workitemwidgettypeiteration"></a>`ITERATION` | Iteration widget. | @@ -45791,6 +45803,7 @@ Implementations: - [`WorkItemWidgetDesigns`](#workitemwidgetdesigns) - [`WorkItemWidgetDevelopment`](#workitemwidgetdevelopment) - [`WorkItemWidgetEmailParticipants`](#workitemwidgetemailparticipants) +- [`WorkItemWidgetErrorTracking`](#workitemwidgeterrortracking) - [`WorkItemWidgetHealthStatus`](#workitemwidgethealthstatus) - [`WorkItemWidgetHierarchy`](#workitemwidgethierarchy) - [`WorkItemWidgetIteration`](#workitemwidgetiteration) diff --git a/ee/spec/models/ee/work_items/widget_definition_spec.rb b/ee/spec/models/ee/work_items/widget_definition_spec.rb index 849cfe8037549b1357a6be0256e3984997a63478..db18cb7e65a8245e8ea92e1576fbe72194228c41 100644 --- a/ee/spec/models/ee/work_items/widget_definition_spec.rb +++ b/ee/spec/models/ee/work_items/widget_definition_spec.rb @@ -34,7 +34,8 @@ ::WorkItems::Widgets::CrmContacts, ::WorkItems::Widgets::EmailParticipants, ::WorkItems::Widgets::CustomStatus, - ::WorkItems::Widgets::CustomFields + ::WorkItems::Widgets::CustomFields, + ::WorkItems::Widgets::ErrorTracking ) end diff --git a/lib/gitlab/database_importers/work_items/base_type_importer.rb b/lib/gitlab/database_importers/work_items/base_type_importer.rb index 257e3d35c8055876b45ef3e31dbb965926ea4563..b4eb7298c145ed58e3b6ee4cf389c0a63003763b 100644 --- a/lib/gitlab/database_importers/work_items/base_type_importer.rb +++ b/lib/gitlab/database_importers/work_items/base_type_importer.rb @@ -31,7 +31,8 @@ module BaseTypeImporter crm_contacts: 'CRM contacts', email_participants: 'Email participants', custom_status: 'Custom status', - custom_fields: 'Custom fields' + custom_fields: 'Custom fields', + error_tracking: 'Error tracking' }.freeze WIDGETS_FOR_TYPE = { @@ -45,6 +46,7 @@ module BaseTypeImporter :designs, :development, :email_participants, + :error_tracking, :health_status, :hierarchy, :iteration, diff --git a/spec/graphql/types/work_items/widget_interface_spec.rb b/spec/graphql/types/work_items/widget_interface_spec.rb index e2235b02468b823160d05cee558e583294864fae..ee7085c6f2c1ddc8d14a14cb28bd7cd8a0edba7b 100644 --- a/spec/graphql/types/work_items/widget_interface_spec.rb +++ b/spec/graphql/types/work_items/widget_interface_spec.rb @@ -31,6 +31,7 @@ WorkItems::Widgets::CrmContacts | Types::WorkItems::Widgets::CrmContactsType WorkItems::Widgets::EmailParticipants | Types::WorkItems::Widgets::EmailParticipantsType WorkItems::Widgets::CustomStatus | Types::WorkItems::Widgets::CustomStatusType + WorkItems::Widgets::ErrorTracking | Types::WorkItems::Widgets::ErrorTrackingType end with_them do diff --git a/spec/graphql/types/work_items/widgets/error_tracking_type_spec.rb b/spec/graphql/types/work_items/widgets/error_tracking_type_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..98d830a364c460fd7a6cd6636664dee43d4df733 --- /dev/null +++ b/spec/graphql/types/work_items/widgets/error_tracking_type_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Types::WorkItems::Widgets::ErrorTrackingType, feature_category: :team_planning do + it 'exposes the expected fields' do + expected_fields = %i[type identifier] + + expect(described_class).to have_graphql_fields(*expected_fields) + end +end diff --git a/spec/migrations/20250128163345_add_error_tracking_to_work_item_widget_spec.rb b/spec/migrations/20250128163345_add_error_tracking_to_work_item_widget_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..16fcd761f500748e24a365f622dc48d0ce413be4 --- /dev/null +++ b/spec/migrations/20250128163345_add_error_tracking_to_work_item_widget_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe AddErrorTrackingToWorkItemWidget, :migration, feature_category: :team_planning do + # Tests for `n` widgets in your migration when using the work items widgets migration helper + it_behaves_like 'migration that adds widgets to a work item type' +end diff --git a/spec/models/work_items/widget_definition_spec.rb b/spec/models/work_items/widget_definition_spec.rb index ad76b6ef73fec3a207777325ada36e1b1bbf4c64..dd033c032a2cac7ec6869efeb81524657ecfa244 100644 --- a/spec/models/work_items/widget_definition_spec.rb +++ b/spec/models/work_items/widget_definition_spec.rb @@ -22,7 +22,8 @@ ::WorkItems::Widgets::Development, ::WorkItems::Widgets::CrmContacts, ::WorkItems::Widgets::EmailParticipants, - ::WorkItems::Widgets::CustomStatus + ::WorkItems::Widgets::CustomStatus, + ::WorkItems::Widgets::ErrorTracking ] if Gitlab.ee? diff --git a/spec/models/work_items/widgets/error_tracking_spec.rb b/spec/models/work_items/widgets/error_tracking_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..22d12cfe3b40bdc7d9458a6e8aff2846a08d905e --- /dev/null +++ b/spec/models/work_items/widgets/error_tracking_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe WorkItems::Widgets::ErrorTracking, feature_category: :team_planning do + let_it_be(:work_item) { create(:work_item) } + let_it_be(:sentry_issue) { create(:sentry_issue, issue: work_item) } + + describe '.type' do + it { expect(described_class.type).to eq(:error_tracking) } + end + + describe '#type' do + it { expect(described_class.new(work_item).type).to eq(:error_tracking) } + end + + describe '.sentry_issue' do + it { expect(described_class.new(work_item).sentry_issue).to eq(sentry_issue) } + end + + describe '.sentry_issue_identifier' do + it { expect(described_class.new(work_item).sentry_issue_identifier).to eq(sentry_issue.sentry_issue_identifier) } + end +end