diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue index 6d081a74453f45cbc4e86b941a9a218eb3aeb76e..cd455d9540f724b601820d15285914389128dbeb 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail.vue @@ -235,9 +235,6 @@ export default { showIntersectionObserver() { return !this.isModal && !this.editMode; }, - hasLinkedWorkItems() { - return this.glFeatures.linkedWorkItems; - }, workItemLinkedItems() { return this.isWidgetPresent(WIDGET_TYPE_LINKED_ITEMS); }, @@ -246,9 +243,6 @@ export default { this.workItemType, ); }, - showWorkItemLinkedItems() { - return this.hasLinkedWorkItems && this.workItemLinkedItems; - }, titleClassHeader() { return { 'gl-sm-display-none! gl-mt-3': this.parentWorkItem, @@ -601,7 +595,7 @@ export default { @addChild="$emit('addChild')" /> `blocked` | [`Boolean`](#boolean) | Indicates the work item is blocked. Returns `null`if `linked_work_items` feature flag is disabled. | -| `blockedByCount` | [`Int`](#int) | Count of items blocking the work item. Returns `null`if `linked_work_items` feature flag is disabled. | -| `blockingCount` | [`Int`](#int) | Count of items the work item is blocking. Returns `null`if `linked_work_items` feature flag is disabled. | +| `blocked` | [`Boolean`](#boolean) | Indicates the work item is blocked. | +| `blockedByCount` | [`Int`](#int) | Count of items blocking the work item. | +| `blockingCount` | [`Int`](#int) | Count of items the work item is blocking. | | `type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. | #### Fields with arguments ##### `WorkItemWidgetLinkedItems.linkedItems` -Linked items for the work item. Returns `null` if `linked_work_items` feature flag is disabled. +Linked items for the work item. DETAILS: **Introduced** in GitLab 16.3. diff --git a/doc/architecture/blueprints/work_items/index.md b/doc/architecture/blueprints/work_items/index.md index 2f673c51321ef628ea61f0e8610581f4c9724dde..b112de4dc6f73d3f015cbdf09d7507eaf2fb090f 100644 --- a/doc/architecture/blueprints/work_items/index.md +++ b/doc/architecture/blueprints/work_items/index.md @@ -76,7 +76,7 @@ All Work Item types share the same pool of predefined widgets and are customized | [WorkItemWidgetHierarchy](../../../api/graphql/reference/index.md#workitemwidgethierarchy) | Hierarchy of work items, including support for boolean representing presence of children. **Note:** Hierarchy is currently available only for OKRs. | `okrs_mvc` |`Guest`|No| | [WorkItemWidgetIteration](../../../api/graphql/reference/index.md#workitemwidgetiteration) | Iteration assignment support for work item | |`Reporter`|No| | [WorkItemWidgetLabels](../../../api/graphql/reference/index.md#workitemwidgetlabels) | List of labels added to work items, including support for checking whether scoped labels are supported | |`Reporter`|Yes| -| [WorkItemWidgetLinkedItems](../../../api/graphql/reference/index.md#workitemwidgetlinkeditems) | List of work items added as related to a given work item, with possible relationship types being `relates_to`, `blocks`, and `blocked_by`. Includes support for individual counts of blocked status, blocked by, blocking, and related to. | `linked_work_items`|`Guest`|No| +| [WorkItemWidgetLinkedItems](../../../api/graphql/reference/index.md#workitemwidgetlinkeditems) | List of work items added as related to a given work item, with possible relationship types being `relates_to`, `blocks`, and `blocked_by`. Includes support for individual counts of blocked status, blocked by, blocking, and related to. | |`Guest`|No| | [WorkItemWidgetMilestone](../../../api/graphql/reference/index.md#workitemwidgetmilestone) | Milestone assignment support for work item | |`Reporter`|No| | [WorkItemWidgetNotes](../../../api/graphql/reference/index.md#workitemwidgetnotes) | List of discussions within a work item | |`Guest`|Yes| | [WorkItemWidgetNotifications](../../../api/graphql/reference/index.md#workitemwidgetnotifications) | Notifications subscription status of a work item for current user | |Anyone who can view|No| diff --git a/doc/user/okrs.md b/doc/user/okrs.md index 615979708f786588d86946591df75895af0c6958..301659657166a0eb8e04bbe60012d48dc89c505e 100644 --- a/doc/user/okrs.md +++ b/doc/user/okrs.md @@ -536,10 +536,7 @@ If you find a bug, [comment on the feedback issue](https://gitlab.com/gitlab-org > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/416558) in GitLab 16.5 [with a flag](../administration/feature_flags.md) named `linked_work_items`. Enabled by default. > - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139394) in GitLab 16.7. > - Adding related items by entering their URLs and IDs [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/427594) in GitLab 16.8. - -FLAG: -On self-managed GitLab, by default this feature is available. To hide the feature, an administrator can [disable the feature flag](../administration/feature_flags.md) named `linked_work_items`. -On GitLab.com and GitLab Dedicated, this feature is available. +> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/150148) in GitLab 17.0. Feature flag `linked_work_items` removed. Linked items are a bi-directional relationship and appear in a block below the Child objectives and key results. You can link an objective, key result, or a task in the same project with each other. diff --git a/doc/user/tasks.md b/doc/user/tasks.md index ac40c7f85771651d04de2eedd66187c1c900f700..fb4b577bb23421755562819b3b00875d817b2933 100644 --- a/doc/user/tasks.md +++ b/doc/user/tasks.md @@ -540,10 +540,7 @@ If you find a bug, [comment on the feedback issue](https://gitlab.com/gitlab-org > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/416558) in GitLab 16.5 [with a flag](../administration/feature_flags.md) named `linked_work_items`. Disabled by default. > - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139394) in GitLab 16.7. > - Adding related items by entering their URLs and IDs [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/427594) in GitLab 16.8. - -FLAG: -On self-managed GitLab, by default this feature is available. To hide the feature, an administrator can [disable the feature flag](../administration/feature_flags.md) named `linked_work_items`. -On GitLab.com, this feature is available. On GitLab Dedicated, this feature is not available. +> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/150148) in GitLab 17.0. Feature flag `linked_work_items` removed. Linked items are a bi-directional relationship and appear in a block below the emoji reactions section. You can link an objective, key result, or a task in the same project with each other. diff --git a/ee/app/graphql/ee/types/work_items/widgets/linked_items_type.rb b/ee/app/graphql/ee/types/work_items/widgets/linked_items_type.rb index c671091e35bc2bc1cb30b50e14eb69c0dc149da1..4f6b9a7295db059141769d7e2f17fc0874606905 100644 --- a/ee/app/graphql/ee/types/work_items/widgets/linked_items_type.rb +++ b/ee/app/graphql/ee/types/work_items/widgets/linked_items_type.rb @@ -10,32 +10,23 @@ module LinkedItemsType prepended do field :blocked, GraphQL::Types::Boolean, null: true, - description: 'Indicates the work item is blocked. Returns `null`' \ - 'if `linked_work_items` feature flag is disabled.' + description: 'Indicates the work item is blocked.' field :blocking_count, GraphQL::Types::Int, null: true, - description: 'Count of items the work item is blocking. Returns `null`' \ - 'if `linked_work_items` feature flag is disabled.' + description: 'Count of items the work item is blocking.' field :blocked_by_count, GraphQL::Types::Int, null: true, - description: 'Count of items blocking the work item. Returns `null`' \ - 'if `linked_work_items` feature flag is disabled.' + description: 'Count of items blocking the work item.' def blocked - return unless linked_items_enabled? - aggregator_class.new(context, object.work_item.id) { |count| (count || 0) > 0 } end def blocked_by_count - return unless linked_items_enabled? - aggregator_class.new(context, object.work_item.id) { |count| count || 0 } end def blocking_count - return unless linked_items_enabled? - object.work_item.blocking_issues_count end @@ -44,10 +35,6 @@ def blocking_count def aggregator_class ::Gitlab::Graphql::Aggregations::WorkItems::LazyLinksAggregate end - - def linked_items_enabled? - object.work_item.resource_parent.linked_work_items_feature_flag_enabled? - end end end end diff --git a/ee/spec/requests/api/graphql/work_item_spec.rb b/ee/spec/requests/api/graphql/work_item_spec.rb index df251587337b70d83097e3b7a4a71ae45e61cf95..025f436f03e11561eee301d217d3fe72853cb592 100644 --- a/ee/spec/requests/api/graphql/work_item_spec.rb +++ b/ee/spec/requests/api/graphql/work_item_spec.rb @@ -732,27 +732,6 @@ def find_note(work_item, starting_with) ) end end - - context 'when `linked_work_items` feature flag is disabled' do - before do - stub_feature_flags(linked_work_items: false) - end - - it 'returns null fields' do - post_graphql(query, current_user: current_user) - expect(work_item_data).to include( - 'widgets' => include( - hash_including( - 'type' => 'LINKED_ITEMS', - 'blocked' => nil, - 'blockedByCount' => nil, - 'blockingCount' => nil, - 'linkedItems' => { 'nodes' => [] } - ) - ) - ) - end - end end describe 'hierarchy widget' do diff --git a/spec/features/projects/work_items/linked_work_items_spec.rb b/spec/features/projects/work_items/linked_work_items_spec.rb index f9cdd7b78ab733168b8051e63eceef8d8450af32..326855e0ef34c5b4b544047405672aa1df128d1d 100644 --- a/spec/features/projects/work_items/linked_work_items_spec.rb +++ b/spec/features/projects/work_items/linked_work_items_spec.rb @@ -27,7 +27,6 @@ sign_in(user) stub_feature_flags(work_items: true) - stub_feature_flags(linked_work_items: true) visit work_items_path diff --git a/spec/frontend/work_items/components/work_item_detail_spec.js b/spec/frontend/work_items/components/work_item_detail_spec.js index a54c6e71d36e5d8d28ce1b1ffc5ade0ee59e2441..4354d9204eb5dfd7aaa4a7bcd8dbe3ceb38b77f7 100644 --- a/spec/frontend/work_items/components/work_item_detail_spec.js +++ b/spec/frontend/work_items/components/work_item_detail_spec.js @@ -102,7 +102,6 @@ describe('WorkItemDetail component', () => { error = undefined, workItemsMvc2Enabled = false, workItemsBeta = false, - linkedWorkItemsEnabled = false, } = {}) => { wrapper = shallowMountExtended(WorkItemDetail, { apolloProvider: createMockApollo([ @@ -125,7 +124,6 @@ describe('WorkItemDetail component', () => { provide: { glFeatures: { workItemsMvc2: workItemsMvc2Enabled, - linkedWorkItems: linkedWorkItemsEnabled, workItemsBeta, }, hasIssueWeightsFeature: true, @@ -516,8 +514,13 @@ describe('WorkItemDetail component', () => { }); describe('relationship widget', () => { - it('does not render linked items by default', async () => { - createComponent(); + it('does not render when no linkedItems present', async () => { + const mockEmptyLinkedItems = workItemByIidResponseFactory({ + linkedItems: [], + }); + const handler = jest.fn().mockResolvedValue(mockEmptyLinkedItems); + + createComponent({ handler }); await waitForPromises(); expect(findWorkItemRelationships().exists()).toBe(false); @@ -530,7 +533,7 @@ describe('WorkItemDetail component', () => { const handler = jest.fn().mockResolvedValue(mockWorkItemLinkedItem); it('renders relationship widget when work item has linked items', async () => { - createComponent({ handler, linkedWorkItemsEnabled: true }); + createComponent({ handler }); await waitForPromises(); expect(findWorkItemRelationships().exists()).toBe(true); @@ -539,7 +542,6 @@ describe('WorkItemDetail component', () => { it('opens the modal with the linked item when `showModal` is emitted', async () => { createComponent({ handler, - linkedWorkItemsEnabled: true, workItemsMvc2Enabled: true, }); await waitForPromises(); @@ -564,7 +566,6 @@ describe('WorkItemDetail component', () => { isModal: true, handler, workItemsMvc2Enabled: true, - linkedWorkItemsEnabled: true, }); await waitForPromises(); diff --git a/spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb b/spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb index 726d1dcf664dae642b1c0b6caca11458f5d8b02f..78cba3518fa828edc342e889455551fbb6ef9b67 100644 --- a/spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb +++ b/spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb @@ -144,13 +144,5 @@ end end end - - context 'when `linked_work_items` feature flag is disabled' do - before do - stub_feature_flags(linked_work_items: false) - end - - it_behaves_like 'a mutation that returns a top-level access error' - end end end diff --git a/spec/requests/api/graphql/mutations/work_items/linked_items/remove_spec.rb b/spec/requests/api/graphql/mutations/work_items/linked_items/remove_spec.rb index 8455b73793ec0c26cd14b40c6c1e6850e358e016..bd30129516b5dd3ffb819ef14b50077e844ca495 100644 --- a/spec/requests/api/graphql/mutations/work_items/linked_items/remove_spec.rb +++ b/spec/requests/api/graphql/mutations/work_items/linked_items/remove_spec.rb @@ -108,13 +108,5 @@ it_behaves_like 'a mutation that returns top-level errors', errors: ['workItemsIds cannot be empty'] end - - context 'when `linked_work_items` feature flag is disabled' do - before do - stub_feature_flags(linked_work_items: false) - end - - it_behaves_like 'a mutation that returns a top-level access error' - end end end diff --git a/spec/requests/api/graphql/work_item_spec.rb b/spec/requests/api/graphql/work_item_spec.rb index 41f3ccb897732021d9b709f1362a945c009e49d8..6dfcacdefd15fef59a7e1b93d52961e5f3753417 100644 --- a/spec/requests/api/graphql/work_item_spec.rb +++ b/spec/requests/api/graphql/work_item_spec.rb @@ -695,24 +695,6 @@ def pagination_results_data(nodes) expect(widget_data.dig("nodes", 0, "linkType")).to eq('relates_to') end end - - context 'when `linked_work_items` feature flag is disabled' do - before do - stub_feature_flags(linked_work_items: false) - post_graphql(query, current_user: current_user) - end - - it 'returns empty result' do - expect(work_item_data).to include( - 'widgets' => include( - hash_including( - 'type' => 'LINKED_ITEMS', - 'linkedItems' => { "nodes" => [] } - ) - ) - ) - end - end end end