2019-07-07 11:18:12 +05:30
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
|
|
module Gitlab
|
|
|
|
|
module QuickActions
|
|
|
|
|
module IssuableActions
|
|
|
|
|
extend ActiveSupport::Concern
|
|
|
|
|
include Gitlab::QuickActions::Dsl
|
|
|
|
|
|
2019-12-04 20:38:33 +05:30
|
|
|
|
SHRUG = '¯\\_(ツ)_/¯'
|
|
|
|
|
TABLEFLIP = '(╯°□°)╯︵ ┻━┻'
|
2019-07-07 11:18:12 +05:30
|
|
|
|
|
|
|
|
|
included do
|
|
|
|
|
# Issue, MergeRequest, Epic: quick actions definitions
|
|
|
|
|
desc do
|
2023-01-13 00:05:48 +05:30
|
|
|
|
_('Close this %{quick_action_target}') % { quick_action_target: target_issuable_name }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
|
|
|
|
explanation do
|
2023-01-13 00:05:48 +05:30
|
|
|
|
_('Closes this %{quick_action_target}.') % { quick_action_target: target_issuable_name }
|
2019-10-12 21:52:04 +05:30
|
|
|
|
end
|
|
|
|
|
execution_message do
|
2023-01-13 00:05:48 +05:30
|
|
|
|
_('Closed this %{quick_action_target}.') % { quick_action_target: target_issuable_name }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
2022-08-13 15:12:31 +05:30
|
|
|
|
types ::Issuable
|
2019-07-07 11:18:12 +05:30
|
|
|
|
condition do
|
|
|
|
|
quick_action_target.persisted? &&
|
|
|
|
|
quick_action_target.open? &&
|
|
|
|
|
current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target)
|
|
|
|
|
end
|
|
|
|
|
command :close do
|
|
|
|
|
@updates[:state_event] = 'close'
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
desc do
|
2019-10-12 21:52:04 +05:30
|
|
|
|
_('Reopen this %{quick_action_target}') %
|
2023-01-13 00:05:48 +05:30
|
|
|
|
{ quick_action_target: target_issuable_name }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
|
|
|
|
explanation do
|
2019-10-12 21:52:04 +05:30
|
|
|
|
_('Reopens this %{quick_action_target}.') %
|
2023-01-13 00:05:48 +05:30
|
|
|
|
{ quick_action_target: target_issuable_name }
|
2019-10-12 21:52:04 +05:30
|
|
|
|
end
|
|
|
|
|
execution_message do
|
|
|
|
|
_('Reopened this %{quick_action_target}.') %
|
2023-01-13 00:05:48 +05:30
|
|
|
|
{ quick_action_target: target_issuable_name }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
2022-08-13 15:12:31 +05:30
|
|
|
|
types ::Issuable
|
2019-07-07 11:18:12 +05:30
|
|
|
|
condition do
|
|
|
|
|
quick_action_target.persisted? &&
|
|
|
|
|
quick_action_target.closed? &&
|
|
|
|
|
current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target)
|
|
|
|
|
end
|
|
|
|
|
command :reopen do
|
|
|
|
|
@updates[:state_event] = 'reopen'
|
|
|
|
|
end
|
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
|
desc { _('Change title') }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
explanation do |title_param|
|
2019-10-12 21:52:04 +05:30
|
|
|
|
_('Changes the title to "%{title_param}".') % { title_param: title_param }
|
|
|
|
|
end
|
|
|
|
|
execution_message do |title_param|
|
|
|
|
|
_('Changed the title to "%{title_param}".') % { title_param: title_param }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
|
|
|
|
params '<New title>'
|
2022-08-13 15:12:31 +05:30
|
|
|
|
types ::Issuable
|
2019-07-07 11:18:12 +05:30
|
|
|
|
condition do
|
|
|
|
|
quick_action_target.persisted? &&
|
|
|
|
|
current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target)
|
|
|
|
|
end
|
|
|
|
|
command :title do |title_param|
|
|
|
|
|
@updates[:title] = title_param
|
|
|
|
|
end
|
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
|
desc { _('Add label(s)') }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
explanation do |labels_param|
|
|
|
|
|
labels = find_label_references(labels_param)
|
|
|
|
|
|
2019-10-12 21:52:04 +05:30
|
|
|
|
if labels.any?
|
|
|
|
|
_("Adds %{labels} %{label_text}.") %
|
|
|
|
|
{ labels: labels.join(' '), label_text: 'label'.pluralize(labels.count) }
|
|
|
|
|
end
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
|
|
|
|
params '~label1 ~"label 2"'
|
2022-08-13 15:12:31 +05:30
|
|
|
|
types ::Issuable
|
2019-07-07 11:18:12 +05:30
|
|
|
|
condition do
|
2021-12-11 22:18:48 +05:30
|
|
|
|
current_user.can?(:"set_#{quick_action_target.to_ability_name}_metadata", quick_action_target) &&
|
2019-07-07 11:18:12 +05:30
|
|
|
|
find_labels.any?
|
|
|
|
|
end
|
2023-03-04 22:38:38 +05:30
|
|
|
|
command :label, :labels do |labels_param|
|
2019-10-12 21:52:04 +05:30
|
|
|
|
run_label_command(labels: find_labels(labels_param), command: :label, updates_key: :add_label_ids)
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
|
desc { _('Remove all or specific label(s)') }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
explanation do |labels_param = nil|
|
2019-10-12 21:52:04 +05:30
|
|
|
|
label_references = labels_param.present? ? find_label_references(labels_param) : []
|
|
|
|
|
if label_references.any?
|
|
|
|
|
_("Removes %{label_references} %{label_text}.") %
|
|
|
|
|
{ label_references: label_references.join(' '), label_text: 'label'.pluralize(label_references.count) }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
else
|
2019-07-31 22:56:46 +05:30
|
|
|
|
_('Removes all labels.')
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
params '~label1 ~"label 2"'
|
2022-08-13 15:12:31 +05:30
|
|
|
|
types ::Issuable
|
2019-07-07 11:18:12 +05:30
|
|
|
|
condition do
|
|
|
|
|
quick_action_target.persisted? &&
|
|
|
|
|
quick_action_target.labels.any? &&
|
2021-12-11 22:18:48 +05:30
|
|
|
|
current_user.can?(:"set_#{quick_action_target.to_ability_name}_metadata", quick_action_target)
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
2020-05-24 23:13:21 +05:30
|
|
|
|
command :unlabel, :remove_label do |labels_param = nil|
|
2019-07-07 11:18:12 +05:30
|
|
|
|
if labels_param.present?
|
2019-10-12 21:52:04 +05:30
|
|
|
|
labels = find_labels(labels_param)
|
|
|
|
|
label_ids = labels.map(&:id)
|
|
|
|
|
label_references = labels_to_reference(labels, :name)
|
2019-07-07 11:18:12 +05:30
|
|
|
|
|
|
|
|
|
if label_ids.any?
|
|
|
|
|
@updates[:remove_label_ids] ||= []
|
|
|
|
|
@updates[:remove_label_ids] += label_ids
|
|
|
|
|
|
|
|
|
|
@updates[:remove_label_ids].uniq!
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
@updates[:label_ids] = []
|
2019-10-12 21:52:04 +05:30
|
|
|
|
label_references = []
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
2019-10-12 21:52:04 +05:30
|
|
|
|
|
|
|
|
|
@execution_message[:unlabel] = remove_label_message(label_references)
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
|
desc { _('Replace all label(s)') }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
explanation do |labels_param|
|
|
|
|
|
labels = find_label_references(labels_param)
|
|
|
|
|
"Replaces all labels with #{labels.join(' ')} #{'label'.pluralize(labels.count)}." if labels.any?
|
|
|
|
|
end
|
|
|
|
|
params '~label1 ~"label 2"'
|
2022-08-13 15:12:31 +05:30
|
|
|
|
types ::Issuable
|
2019-07-07 11:18:12 +05:30
|
|
|
|
condition do
|
|
|
|
|
quick_action_target.persisted? &&
|
|
|
|
|
quick_action_target.labels.any? &&
|
2021-12-11 22:18:48 +05:30
|
|
|
|
current_user.can?(:"set_#{quick_action_target.to_ability_name}_metadata", quick_action_target)
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
|
|
|
|
command :relabel do |labels_param|
|
2019-10-12 21:52:04 +05:30
|
|
|
|
run_label_command(labels: find_labels(labels_param), command: :relabel, updates_key: :label_ids)
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
|
desc { _('Add a to do') }
|
|
|
|
|
explanation { _('Adds a to do.') }
|
|
|
|
|
execution_message { _('Added a to do.') }
|
2022-08-13 15:12:31 +05:30
|
|
|
|
types ::Issuable
|
2019-07-07 11:18:12 +05:30
|
|
|
|
condition do
|
|
|
|
|
quick_action_target.persisted? &&
|
|
|
|
|
!TodoService.new.todo_exist?(quick_action_target, current_user)
|
|
|
|
|
end
|
|
|
|
|
command :todo do
|
|
|
|
|
@updates[:todo_event] = 'add'
|
|
|
|
|
end
|
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
|
desc { _('Mark to do as done') }
|
|
|
|
|
explanation { _('Marks to do as done.') }
|
|
|
|
|
execution_message { _('Marked to do as done.') }
|
2022-08-13 15:12:31 +05:30
|
|
|
|
types ::Issuable
|
2019-07-07 11:18:12 +05:30
|
|
|
|
condition do
|
|
|
|
|
quick_action_target.persisted? &&
|
|
|
|
|
TodoService.new.todo_exist?(quick_action_target, current_user)
|
|
|
|
|
end
|
|
|
|
|
command :done do
|
|
|
|
|
@updates[:todo_event] = 'done'
|
|
|
|
|
end
|
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
|
desc { _('Subscribe') }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
explanation do
|
2023-01-13 00:05:48 +05:30
|
|
|
|
_('Subscribes to this %{quick_action_target}.') % { quick_action_target: target_issuable_name }
|
2019-10-12 21:52:04 +05:30
|
|
|
|
end
|
|
|
|
|
execution_message do
|
2023-01-13 00:05:48 +05:30
|
|
|
|
_('Subscribed to this %{quick_action_target}.') % { quick_action_target: target_issuable_name }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
2022-08-13 15:12:31 +05:30
|
|
|
|
types ::Issuable
|
2019-07-07 11:18:12 +05:30
|
|
|
|
condition do
|
|
|
|
|
quick_action_target.persisted? &&
|
|
|
|
|
!quick_action_target.subscribed?(current_user, project)
|
|
|
|
|
end
|
|
|
|
|
command :subscribe do
|
|
|
|
|
@updates[:subscription_event] = 'subscribe'
|
|
|
|
|
end
|
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
|
desc { _('Unsubscribe') }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
explanation do
|
2023-01-13 00:05:48 +05:30
|
|
|
|
_('Unsubscribes from this %{quick_action_target}.') % { quick_action_target: target_issuable_name }
|
2019-10-12 21:52:04 +05:30
|
|
|
|
end
|
|
|
|
|
execution_message do
|
2023-01-13 00:05:48 +05:30
|
|
|
|
_('Unsubscribed from this %{quick_action_target}.') % { quick_action_target: target_issuable_name }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
2022-08-13 15:12:31 +05:30
|
|
|
|
types ::Issuable
|
2019-07-07 11:18:12 +05:30
|
|
|
|
condition do
|
|
|
|
|
quick_action_target.persisted? &&
|
|
|
|
|
quick_action_target.subscribed?(current_user, project)
|
|
|
|
|
end
|
|
|
|
|
command :unsubscribe do
|
|
|
|
|
@updates[:subscription_event] = 'unsubscribe'
|
|
|
|
|
end
|
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
|
desc { _('Toggle emoji award') }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
explanation do |name|
|
2019-07-31 22:56:46 +05:30
|
|
|
|
_("Toggles :%{name}: emoji award.") % { name: name } if name
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
2019-10-12 21:52:04 +05:30
|
|
|
|
execution_message do |name|
|
|
|
|
|
_("Toggled :%{name}: emoji award.") % { name: name } if name
|
|
|
|
|
end
|
2019-07-07 11:18:12 +05:30
|
|
|
|
params ':emoji:'
|
2022-08-13 15:12:31 +05:30
|
|
|
|
types ::Issuable
|
2019-07-07 11:18:12 +05:30
|
|
|
|
condition do
|
|
|
|
|
quick_action_target.persisted?
|
|
|
|
|
end
|
|
|
|
|
parse_params do |emoji_param|
|
|
|
|
|
match = emoji_param.match(Banzai::Filter::EmojiFilter.emoji_pattern)
|
|
|
|
|
match[1] if match
|
|
|
|
|
end
|
|
|
|
|
command :award do |name|
|
|
|
|
|
if name && quick_action_target.user_can_award?(current_user)
|
|
|
|
|
@updates[:emoji_award] = name
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
|
desc { _("Append the comment with %{shrug}") % { shrug: SHRUG } }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
params '<Comment>'
|
2022-08-13 15:12:31 +05:30
|
|
|
|
types ::Issuable
|
2019-07-07 11:18:12 +05:30
|
|
|
|
substitution :shrug do |comment|
|
|
|
|
|
"#{comment} #{SHRUG}"
|
|
|
|
|
end
|
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
|
desc { _("Append the comment with %{tableflip}") % { tableflip: TABLEFLIP } }
|
2019-07-07 11:18:12 +05:30
|
|
|
|
params '<Comment>'
|
2022-08-13 15:12:31 +05:30
|
|
|
|
types ::Issuable
|
2019-07-07 11:18:12 +05:30
|
|
|
|
substitution :tableflip do |comment|
|
|
|
|
|
"#{comment} #{TABLEFLIP}"
|
|
|
|
|
end
|
2019-10-12 21:52:04 +05:30
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
|
desc { _('Set severity') }
|
|
|
|
|
explanation { _('Sets the severity') }
|
2021-10-27 15:23:28 +05:30
|
|
|
|
params '1 / S1 / Critical'
|
|
|
|
|
types Issue
|
|
|
|
|
condition do
|
|
|
|
|
!quick_action_target.persisted? || quick_action_target.supports_severity?
|
|
|
|
|
end
|
|
|
|
|
parse_params do |severity|
|
|
|
|
|
find_severity(severity)
|
|
|
|
|
end
|
|
|
|
|
command :severity do |severity|
|
|
|
|
|
next unless quick_action_target.supports_severity?
|
|
|
|
|
|
|
|
|
|
if severity
|
|
|
|
|
if quick_action_target.persisted?
|
2023-04-23 21:23:45 +05:30
|
|
|
|
::Issues::UpdateService.new(container: quick_action_target.project, current_user: current_user, params: { severity: severity }).execute(quick_action_target)
|
2021-10-27 15:23:28 +05:30
|
|
|
|
else
|
|
|
|
|
quick_action_target.build_issuable_severity(severity: severity)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
@execution_message[:severity] = _("Severity updated to %{severity}.") % { severity: severity.capitalize }
|
|
|
|
|
else
|
|
|
|
|
@execution_message[:severity] = _('No severity matches the provided parameter')
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2023-01-13 00:05:48 +05:30
|
|
|
|
desc { _("Make %{type} confidential") % { type: target_issuable_name } }
|
|
|
|
|
explanation { _("Makes this %{type} confidential.") % { type: target_issuable_name } }
|
|
|
|
|
types ::Issuable
|
|
|
|
|
condition { quick_action_target.supports_confidentiality? && can_make_confidential? }
|
|
|
|
|
command :confidential do
|
|
|
|
|
@updates[:confidential] = true
|
|
|
|
|
|
|
|
|
|
@execution_message[:confidential] = confidential_execution_message
|
|
|
|
|
end
|
|
|
|
|
|
2019-10-12 21:52:04 +05:30
|
|
|
|
private
|
|
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
|
def find_severity(severity_param)
|
|
|
|
|
return unless severity_param
|
|
|
|
|
|
|
|
|
|
severity_param = severity_param.downcase
|
|
|
|
|
severities = IssuableSeverity::SEVERITY_QUICK_ACTION_PARAMS.values.map { |vals| vals.map(&:downcase) }
|
|
|
|
|
|
|
|
|
|
matched_severity = severities.find do |severity_values|
|
|
|
|
|
severity_values.include?(severity_param)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return unless matched_severity
|
|
|
|
|
|
|
|
|
|
matched_severity[0]
|
|
|
|
|
end
|
|
|
|
|
|
2019-10-12 21:52:04 +05:30
|
|
|
|
def run_label_command(labels:, command:, updates_key:)
|
|
|
|
|
return if labels.empty?
|
|
|
|
|
|
|
|
|
|
@updates[updates_key] ||= []
|
|
|
|
|
@updates[updates_key] += labels.map(&:id)
|
|
|
|
|
@updates[updates_key].uniq!
|
|
|
|
|
|
|
|
|
|
label_references = labels_to_reference(labels, :name)
|
|
|
|
|
@execution_message[command] = case command
|
|
|
|
|
when :relabel
|
|
|
|
|
_('Replaced all labels with %{label_references} %{label_text}.') %
|
|
|
|
|
{
|
|
|
|
|
label_references: label_references.join(' '),
|
|
|
|
|
label_text: 'label'.pluralize(label_references.count)
|
|
|
|
|
}
|
|
|
|
|
when :label
|
|
|
|
|
_('Added %{label_references} %{label_text}.') %
|
|
|
|
|
{
|
|
|
|
|
label_references: label_references.join(' '),
|
|
|
|
|
label_text: 'label'.pluralize(labels.count)
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def remove_label_message(label_references)
|
|
|
|
|
if label_references.any?
|
|
|
|
|
_("Removed %{label_references} %{label_text}.") %
|
|
|
|
|
{ label_references: label_references.join(' '), label_text: 'label'.pluralize(label_references.count) }
|
|
|
|
|
else
|
|
|
|
|
_('Removed all labels.')
|
|
|
|
|
end
|
|
|
|
|
end
|
2023-01-13 00:05:48 +05:30
|
|
|
|
|
|
|
|
|
def target_issuable_name
|
|
|
|
|
quick_action_target.to_ability_name.humanize(capitalize: false)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def can_make_confidential?
|
|
|
|
|
confidentiality_not_supported = quick_action_target.respond_to?(:issue_type_supports?) &&
|
|
|
|
|
!quick_action_target.issue_type_supports?(:confidentiality)
|
|
|
|
|
|
|
|
|
|
return false if confidentiality_not_supported
|
|
|
|
|
|
|
|
|
|
!quick_action_target.confidential? && current_user.can?(:set_confidentiality, quick_action_target)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def confidential_execution_message
|
|
|
|
|
confidential_error_message.presence || _("Made this %{type} confidential.") % { type: target_issuable_name }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def confidential_error_message
|
|
|
|
|
return unless quick_action_target.respond_to?(:confidentiality_errors)
|
|
|
|
|
|
|
|
|
|
quick_action_target.confidentiality_errors.join("\n")
|
|
|
|
|
end
|
2019-07-07 11:18:12 +05:30
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|