Commit 7691d182 authored by Pedro Pombeiro's avatar Pedro Pombeiro Committed by Natalia Tepluhina

Add /health_status, /clear_health_status quick actions

parent 8bb0cff3
...@@ -639,6 +639,9 @@ You can then see the issue's status in the issues list and the epic tree. ...@@ -639,6 +639,9 @@ You can then see the issue's status in the issues list and the epic tree.
After an issue is closed, its health status can't be edited and the **Edit** button becomes disabled After an issue is closed, its health status can't be edited and the **Edit** button becomes disabled
until the issue is reopened. until the issue is reopened.
You can also set and clear health statuses using the `/health_status` and `/clear_health_status`
[quick actions](../quick_actions.md#issues-merge-requests-and-epics).
## Publish an issue **(ULTIMATE)** ## Publish an issue **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30906) in GitLab 13.1. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30906) in GitLab 13.1.
......
This diff is collapsed.
---
key_path: redis_hll_counters.quickactions.i_quickactions_clear_health_status_monthly
name: "count_clear_health_status_quick_actions_monthly"
description: Count of MAU using the `/clear_health_status` quick action
product_section: dev
product_stage: plan
product_group: group::project management
product_category: issue_tracking
value_type: number
status: active
milestone: "14.7"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77215
time_frame: 28d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
options:
events:
- i_quickactions_clear_health_status
performance_indicator_type: []
distribution:
- ee
tier:
- ultimate
---
key_path: redis_hll_counters.quickactions.i_quickactions_health_status_monthly
name: "count_health_status_quick_actions_monthly"
description: Count of MAU using the `/health_status` quick action
product_section: dev
product_stage: plan
product_group: group::project management
product_category: issue_tracking
value_type: number
status: active
milestone: "14.7"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77215
time_frame: 28d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
options:
events:
- i_quickactions_health_status
performance_indicator_type: []
distribution:
- ee
tier:
- ultimate
---
key_path: redis_hll_counters.quickactions.i_quickactions_health_status_weekly
name: "count_health_status_quick_actions_weekly"
description: Count of WAU using the `/health_status` quick action
product_section: dev
product_stage: plan
product_group: group::project management
product_category: issue_tracking
value_type: number
status: active
milestone: "14.7"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77215
time_frame: 7d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
options:
events:
- i_quickactions_health_status
performance_indicator_type: []
distribution:
- ee
tier:
- ultimate
---
key_path: redis_hll_counters.quickactions.i_quickactions_clear_health_status_weekly
name: "count_clear_health_status_quick_actions_weekly"
description: Count of WAU using the `/clear_health_status` quick action
product_section: dev
product_stage: plan
product_group: group::project management
product_category: issue_tracking
value_type: number
status: active
milestone: "14.7"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77215
time_frame: 7d
data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
options:
events:
- i_quickactions_clear_health_status
performance_indicator_type: []
distribution:
- ee
tier:
- ultimate
...@@ -136,6 +136,52 @@ module EE ...@@ -136,6 +136,52 @@ module EE
@execution_message[:publish] = _('Failed to publish issue on status page.') @execution_message[:publish] = _('Failed to publish issue on status page.')
end end
end end
desc _('Set health status')
explanation do |health_status|
_("Sets health status to %{health_status}.") % { health_status: health_status } if health_status
end
params "<#{::Issue.health_statuses.keys.join('|')}>"
types Issue
condition do
quick_action_target.supports_health_status? &&
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target)
end
parse_params do |health_status|
find_health_status(health_status)
end
command :health_status do |health_status|
if health_status
@updates[:health_status] = health_status
@execution_message[:health_status] = _("Set health status to %{health_status}.") % { health_status: health_status }
end
end
desc _('Clear health status')
explanation _('Clears health status.')
execution_message _('Cleared health status.')
types Issue
condition do
quick_action_target.persisted? &&
quick_action_target.supports_health_status? &&
quick_action_target.health_status &&
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", quick_action_target)
end
command :clear_health_status do
@updates[:health_status] = nil
end
end
private
def find_health_status(health_status_param)
return unless health_status_param
health_status_param = health_status_param.downcase
health_statuses = ::Issue.health_statuses.keys.map(&:downcase)
health_statuses.include?(health_status_param) && health_status_param
end end
end end
end end
......
...@@ -1043,6 +1043,127 @@ RSpec.describe QuickActions::InterpretService do ...@@ -1043,6 +1043,127 @@ RSpec.describe QuickActions::InterpretService do
end end
end end
shared_examples 'health_status command' do
it 'populates health_status specified by the /health_status command' do
_, updates = service.execute(content, issuable)
expect(updates).to eq(health_status: health_status)
end
end
shared_examples 'clear_health_status command' do
it 'populates health_status: nil if content contains /clear_health_status' do
issuable.update!(health_status: 'on_track')
_, updates = service.execute(content, issuable)
expect(updates).to eq(health_status: nil)
end
end
context 'issuable health statuses licensed' do
let(:issuable) { issue }
before do
stub_licensed_features(issuable_health_status: true)
end
context 'health_status' do
let(:content) { "/health_status #{health_status}" }
it_behaves_like 'health_status command' do
let(:health_status) { 'on_track' }
end
it_behaves_like 'health_status command' do
let(:health_status) { 'at_risk' }
end
context 'when health_status is invalid' do
it 'does not populate health_status' do
content = "/health_status unknown"
_, updates = service.execute(content, issuable)
expect(updates).to be_empty
end
end
context 'when the user does not have enough permissions' do
before do
allow(current_user).to receive(:can?).with(:use_quick_actions).and_return(true)
allow(current_user).to receive(:can?).with(:admin_issue, issuable).and_return(false)
end
it 'returns an error message' do
content = "/health_status on_track"
_, updates, message = service.execute(content, issuable)
expect(updates).to be_empty
expect(message).to eq('Could not apply health_status command.')
end
end
end
context 'clear_health_status' do
it_behaves_like 'clear_health_status command' do
let(:content) { '/clear_health_status' }
end
context 'when the user does not have enough permissions' do
before do
allow(current_user).to receive(:can?).with(:use_quick_actions).and_return(true)
allow(current_user).to receive(:can?).with(:admin_issue, issuable).and_return(false)
end
it 'returns an error message' do
content = "/clear_health_status"
_, updates, message = service.execute(content, issuable)
expect(updates).to be_empty
expect(message).to eq('Could not apply clear_health_status command.')
end
end
end
end
context 'issuable health_status unlicensed' do
before do
stub_licensed_features(issuable_health_status: false)
end
it 'does not recognise /health_status X' do
_, updates = service.execute('/health_status needs_attention', issue)
expect(updates).to be_empty
end
it 'does not recognise /clear_health_status' do
_, updates = service.execute('/clear_health_status', issue)
expect(updates).to be_empty
end
end
context 'issuable health_status not supported by type' do
let_it_be(:incident) { create(:incident, project: project) }
before do
stub_licensed_features(issuable_health_status: true)
end
it 'does not recognise /health_status X' do
_, updates = service.execute('/health_status on_track', incident)
expect(updates).to be_empty
end
it 'does not recognise /clear_health_status' do
_, updates = service.execute('/clear_health_status', incident)
expect(updates).to be_empty
end
end
shared_examples 'empty command' do shared_examples 'empty command' do
it 'populates {} if content contains an unsupported command' do it 'populates {} if content contains an unsupported command' do
_, updates = service.execute(content, issuable) _, updates = service.execute(content, issuable)
...@@ -1095,6 +1216,21 @@ RSpec.describe QuickActions::InterpretService do ...@@ -1095,6 +1216,21 @@ RSpec.describe QuickActions::InterpretService do
end end
describe '#explain' do describe '#explain' do
describe 'health_status command' do
let(:content) { '/health_status on_track' }
context 'issuable health statuses licensed' do
before do
stub_licensed_features(issuable_health_status: true)
end
it 'includes the value' do
_, explanations = service.explain(content, issue)
expect(explanations).to eq(['Sets health status to on_track.'])
end
end
end
describe 'unassign command' do describe 'unassign command' do
let(:content) { '/unassign' } let(:content) { '/unassign' }
let(:issue) { create(:issue, project: project, assignees: [user, user2]) } let(:issue) { create(:issue, project: project, assignees: [user, user2]) }
......
...@@ -39,6 +39,10 @@ ...@@ -39,6 +39,10 @@
category: quickactions category: quickactions
redis_slot: quickactions redis_slot: quickactions
aggregation: weekly aggregation: weekly
- name: i_quickactions_clear_health_status
category: quickactions
redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_clone - name: i_quickactions_clone
category: quickactions category: quickactions
redis_slot: quickactions redis_slot: quickactions
...@@ -263,6 +267,10 @@ ...@@ -263,6 +267,10 @@
category: quickactions category: quickactions
redis_slot: quickactions redis_slot: quickactions
aggregation: weekly aggregation: weekly
- name: i_quickactions_health_status
category: quickactions
redis_slot: quickactions
aggregation: weekly
- name: i_quickactions_wip - name: i_quickactions_wip
category: quickactions category: quickactions
redis_slot: quickactions redis_slot: quickactions
......
...@@ -7326,6 +7326,9 @@ msgstr "" ...@@ -7326,6 +7326,9 @@ msgstr ""
msgid "Clear due date" msgid "Clear due date"
msgstr "" msgstr ""
msgid "Clear health status"
msgstr ""
msgid "Clear recent searches" msgid "Clear recent searches"
msgstr "" msgstr ""
...@@ -7344,9 +7347,15 @@ msgstr "" ...@@ -7344,9 +7347,15 @@ msgstr ""
msgid "Clear weight" msgid "Clear weight"
msgstr "" msgstr ""
msgid "Cleared health status."
msgstr ""
msgid "Cleared weight." msgid "Cleared weight."
msgstr "" msgstr ""
msgid "Clears health status."
msgstr ""
msgid "Clears weight." msgid "Clears weight."
msgstr "" msgstr ""
...@@ -32275,6 +32284,12 @@ msgstr "" ...@@ -32275,6 +32284,12 @@ msgstr ""
msgid "Set due date" msgid "Set due date"
msgstr "" msgstr ""
msgid "Set health status"
msgstr ""
msgid "Set health status to %{health_status}."
msgstr ""
msgid "Set iteration" msgid "Set iteration"
msgstr "" msgstr ""
...@@ -32431,6 +32446,9 @@ msgstr "" ...@@ -32431,6 +32446,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic." msgid "Sets %{epic_ref} as parent epic."
msgstr "" msgstr ""
msgid "Sets health status to %{health_status}."
msgstr ""
msgid "Sets target branch to %{branch_name}." msgid "Sets target branch to %{branch_name}."
msgstr "" msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment