Commit ea090291 authored by Eric Eastwood's avatar Eric Eastwood

Rename "Slash commands" to "Quick actions"

Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/27070

Deprecate "chat commands" in favor of "slash commands"

We looked for things like:

 - `slash commmand`
 - `slash_command`
 - `slash-command`
 - `SlashCommand`
parent 42aaae99
...@@ -34,7 +34,7 @@ class GfmAutoComplete { ...@@ -34,7 +34,7 @@ class GfmAutoComplete {
const $input = $(input); const $input = $(input);
$input.off('focus.setupAtWho').on('focus.setupAtWho', this.setupAtWho.bind(this, $input)); $input.off('focus.setupAtWho').on('focus.setupAtWho', this.setupAtWho.bind(this, $input));
// This triggers at.js again // This triggers at.js again
// Needed for slash commands with suffixes (ex: /label ~) // Needed for quick actions with suffixes (ex: /label ~)
$input.on('inserted-commands.atwho', $input.trigger.bind($input, 'keyup')); $input.on('inserted-commands.atwho', $input.trigger.bind($input, 'keyup'));
$input.on('clear-commands-cache.atwho', () => this.clearCache()); $input.on('clear-commands-cache.atwho', () => this.clearCache());
}); });
...@@ -48,8 +48,8 @@ class GfmAutoComplete { ...@@ -48,8 +48,8 @@ class GfmAutoComplete {
if (this.enableMap.mergeRequests) this.setupMergeRequests($input); if (this.enableMap.mergeRequests) this.setupMergeRequests($input);
if (this.enableMap.labels) this.setupLabels($input); if (this.enableMap.labels) this.setupLabels($input);
// We don't instantiate the slash commands autocomplete for note and issue/MR edit forms // We don't instantiate the quick actions autocomplete for note and issue/MR edit forms
$input.filter('[data-supports-slash-commands="true"]').atwho({ $input.filter('[data-supports-quick-actions="true"]').atwho({
at: '/', at: '/',
alias: 'commands', alias: 'commands',
searchKey: 'search', searchKey: 'search',
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
<textarea <textarea
id="issue-description" id="issue-description"
class="note-textarea js-gfm-input js-autosize markdown-area" class="note-textarea js-gfm-input js-autosize markdown-area"
data-supports-slash-commands="false" data-supports-quick-actionss="false"
aria-label="Description" aria-label="Description"
v-model="formState.description" v-model="formState.description"
ref="textarea" ref="textarea"
......
...@@ -32,7 +32,7 @@ const normalizeNewlines = function(str) { ...@@ -32,7 +32,7 @@ const normalizeNewlines = function(str) {
(function() { (function() {
this.Notes = (function() { this.Notes = (function() {
const MAX_VISIBLE_COMMIT_LIST_COUNT = 3; const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
const REGEX_SLASH_COMMANDS = /^\/\w+.*$/gm; const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm;
Notes.interval = null; Notes.interval = null;
...@@ -280,7 +280,7 @@ const normalizeNewlines = function(str) { ...@@ -280,7 +280,7 @@ const normalizeNewlines = function(str) {
return this.initRefresh(); return this.initRefresh();
}; };
Notes.prototype.handleSlashCommands = function(noteEntity) { Notes.prototype.handleQuickActions = function(noteEntity) {
var votesBlock; var votesBlock;
if (noteEntity.commands_changes) { if (noteEntity.commands_changes) {
if ('merge' in noteEntity.commands_changes) { if ('merge' in noteEntity.commands_changes) {
...@@ -1198,27 +1198,27 @@ const normalizeNewlines = function(str) { ...@@ -1198,27 +1198,27 @@ const normalizeNewlines = function(str) {
}; };
/** /**
* Identify if comment has any slash commands * Identify if comment has any quick actions
*/ */
Notes.prototype.hasSlashCommands = function(formContent) { Notes.prototype.hasQuickActions = function(formContent) {
return REGEX_SLASH_COMMANDS.test(formContent); return REGEX_QUICK_ACTIONS.test(formContent);
}; };
/** /**
* Remove slash commands and leave comment with pure message * Remove quick actions and leave comment with pure message
*/ */
Notes.prototype.stripSlashCommands = function(formContent) { Notes.prototype.stripQuickActions = function(formContent) {
return formContent.replace(REGEX_SLASH_COMMANDS, '').trim(); return formContent.replace(REGEX_QUICK_ACTIONS, '').trim();
}; };
/** /**
* Gets appropriate description from slash commands found in provided `formContent` * Gets appropriate description from quick actions found in provided `formContent`
*/ */
Notes.prototype.getSlashCommandDescription = function (formContent, availableSlashCommands = []) { Notes.prototype.getQuickActionDescription = function (formContent, availableQuickActions = []) {
let tempFormContent; let tempFormContent;
// Identify executed slash commands from `formContent` // Identify executed quick actions from `formContent`
const executedCommands = availableSlashCommands.filter((command, index) => { const executedCommands = availableQuickActions.filter((command, index) => {
const commandRegex = new RegExp(`/${command.name}`); const commandRegex = new RegExp(`/${command.name}`);
return commandRegex.test(formContent); return commandRegex.test(formContent);
}); });
...@@ -1276,7 +1276,7 @@ const normalizeNewlines = function(str) { ...@@ -1276,7 +1276,7 @@ const normalizeNewlines = function(str) {
}; };
/** /**
* Create Placeholder System Note DOM element populated with slash command description * Create Placeholder System Note DOM element populated with quick action description
*/ */
Notes.prototype.createPlaceholderSystemNote = function ({ formContent, uniqueId }) { Notes.prototype.createPlaceholderSystemNote = function ({ formContent, uniqueId }) {
const $tempNote = $( const $tempNote = $(
...@@ -1325,7 +1325,7 @@ const normalizeNewlines = function(str) { ...@@ -1325,7 +1325,7 @@ const normalizeNewlines = function(str) {
const { formData, formContent, formAction } = this.getFormData($form); const { formData, formContent, formAction } = this.getFormData($form);
let noteUniqueId; let noteUniqueId;
let systemNoteUniqueId; let systemNoteUniqueId;
let hasSlashCommands = false; let hasQuickActions = false;
let $notesContainer; let $notesContainer;
let tempFormContent; let tempFormContent;
...@@ -1344,9 +1344,9 @@ const normalizeNewlines = function(str) { ...@@ -1344,9 +1344,9 @@ const normalizeNewlines = function(str) {
} }
tempFormContent = formContent; tempFormContent = formContent;
if (this.hasSlashCommands(formContent)) { if (this.hasQuickActions(formContent)) {
tempFormContent = this.stripSlashCommands(formContent); tempFormContent = this.stripQuickActions(formContent);
hasSlashCommands = true; hasQuickActions = true;
} }
// Show placeholder note // Show placeholder note
...@@ -1363,10 +1363,10 @@ const normalizeNewlines = function(str) { ...@@ -1363,10 +1363,10 @@ const normalizeNewlines = function(str) {
} }
// Show placeholder system note // Show placeholder system note
if (hasSlashCommands) { if (hasQuickActions) {
systemNoteUniqueId = _.uniqueId('tempSystemNote_'); systemNoteUniqueId = _.uniqueId('tempSystemNote_');
$notesContainer.append(this.createPlaceholderSystemNote({ $notesContainer.append(this.createPlaceholderSystemNote({
formContent: this.getSlashCommandDescription(formContent, AjaxCache.get(gl.GfmAutoComplete.dataSources.commands)), formContent: this.getQuickActionDescription(formContent, AjaxCache.get(gl.GfmAutoComplete.dataSources.commands)),
uniqueId: systemNoteUniqueId, uniqueId: systemNoteUniqueId,
})); }));
} }
...@@ -1388,7 +1388,7 @@ const normalizeNewlines = function(str) { ...@@ -1388,7 +1388,7 @@ const normalizeNewlines = function(str) {
$notesContainer.find(`#${noteUniqueId}`).remove(); $notesContainer.find(`#${noteUniqueId}`).remove();
// Reset cached commands list when command is applied // Reset cached commands list when command is applied
if (hasSlashCommands) { if (hasQuickActions) {
$form.find('textarea.js-note-text').trigger('clear-commands-cache.atwho'); $form.find('textarea.js-note-text').trigger('clear-commands-cache.atwho');
} }
...@@ -1422,7 +1422,7 @@ const normalizeNewlines = function(str) { ...@@ -1422,7 +1422,7 @@ const normalizeNewlines = function(str) {
} }
if (note.commands_changes) { if (note.commands_changes) {
this.handleSlashCommands(note); this.handleQuickActions(note);
} }
$form.trigger('ajax:success', [note]); $form.trigger('ajax:success', [note]);
...@@ -1430,7 +1430,7 @@ const normalizeNewlines = function(str) { ...@@ -1430,7 +1430,7 @@ const normalizeNewlines = function(str) {
// Submission failed, remove placeholder note and show Flash error message // Submission failed, remove placeholder note and show Flash error message
$notesContainer.find(`#${noteUniqueId}`).remove(); $notesContainer.find(`#${noteUniqueId}`).remove();
if (hasSlashCommands) { if (hasQuickActions) {
$notesContainer.find(`#${systemNoteUniqueId}`).remove(); $notesContainer.find(`#${systemNoteUniqueId}`).remove();
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
// MarkdownPreview // MarkdownPreview
// //
// Handles toggling the "Write" and "Preview" tab clicks, rendering the preview // Handles toggling the "Write" and "Preview" tab clicks, rendering the preview
// (including the explanation of slash commands), and showing a warning when // (including the explanation of quick actions), and showing a warning when
// more than `x` users are referenced. // more than `x` users are referenced.
// //
(function () { (function () {
......
...@@ -15,10 +15,10 @@ export default { ...@@ -15,10 +15,10 @@ export default {
<div class="time-tracking-help-state"> <div class="time-tracking-help-state">
<div class="time-tracking-info"> <div class="time-tracking-info">
<h4> <h4>
Track time with slash commands Track time with quick actions
</h4> </h4>
<p> <p>
Slash commands can be used in the issues description and comment boxes. Quick actions can be used in the issues description and comment boxes.
</p> </p>
<p> <p>
<code> <code>
......
...@@ -16,10 +16,10 @@ export default { ...@@ -16,10 +16,10 @@ export default {
'issuable-time-tracker': timeTracker, 'issuable-time-tracker': timeTracker,
}, },
methods: { methods: {
listenForSlashCommands() { listenForQuickActions() {
$(document).on('ajax:success', '.gfm-form', this.slashCommandListened); $(document).on('ajax:success', '.gfm-form', this.quickActionListened);
}, },
slashCommandListened(e, data) { quickActionListened(e, data) {
const subscribedCommands = ['spend_time', 'time_estimate']; const subscribedCommands = ['spend_time', 'time_estimate'];
let changedCommands; let changedCommands;
if (data !== undefined) { if (data !== undefined) {
...@@ -35,7 +35,7 @@ export default { ...@@ -35,7 +35,7 @@ export default {
}, },
}, },
mounted() { mounted() {
this.listenForSlashCommands(); this.listenForQuickActions();
}, },
template: ` template: `
<div class="block"> <div class="block">
......
...@@ -10,8 +10,8 @@ module NotesHelper ...@@ -10,8 +10,8 @@ module NotesHelper
Ability.can_edit_note?(current_user, note) Ability.can_edit_note?(current_user, note)
end end
def note_supports_slash_commands?(note) def note_supports_quick_actions?(note)
Notes::SlashCommandsService.supported?(note, current_user) Notes::QuickActionsService.supported?(note, current_user)
end end
def noteable_json(noteable) def noteable_json(noteable)
......
...@@ -889,7 +889,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -889,7 +889,7 @@ class MergeRequest < ActiveRecord::Base
!has_commits? !has_commits?
end end
def mergeable_with_slash_command?(current_user, autocomplete_precheck: false, last_diff_sha: nil) def mergeable_with_quick_action?(current_user, autocomplete_precheck: false, last_diff_sha: nil)
return false unless can_be_merged_by?(current_user) return false unless can_be_merged_by?(current_user)
return true if autocomplete_precheck return true if autocomplete_precheck
......
...@@ -32,7 +32,7 @@ class Note < ActiveRecord::Base ...@@ -32,7 +32,7 @@ class Note < ActiveRecord::Base
# Banzai::ObjectRenderer # Banzai::ObjectRenderer
attr_accessor :user_visible_reference_count attr_accessor :user_visible_reference_count
# Attribute used to store the attributes that have ben changed by slash commands. # Attribute used to store the attributes that have ben changed by quick actions.
attr_accessor :commands_changes attr_accessor :commands_changes
default_value_for :system, false default_value_for :system, false
......
class MattermostSlashCommandsService < ChatSlashCommandsService class MattermostSlashCommandsService < SlashCommandsService
include TriggersHelper include TriggersHelper
prop_accessor :token prop_accessor :token
......
class SlackSlashCommandsService < ChatSlashCommandsService class SlackSlashCommandsService < SlashCommandsService
include TriggersHelper include TriggersHelper
def title def title
......
# Base class for Chat services # Base class for Chat services
# This class is not meant to be used directly, but only to inherrit from. # This class is not meant to be used directly, but only to inherrit from.
class ChatSlashCommandsService < Service class SlashCommandsService < Service
default_value_for :category, 'chat' default_value_for :category, 'chat'
prop_accessor :token prop_accessor :token
...@@ -33,10 +33,10 @@ class ChatSlashCommandsService < Service ...@@ -33,10 +33,10 @@ class ChatSlashCommandsService < Service
user = find_chat_user(params) user = find_chat_user(params)
if user if user
Gitlab::ChatCommands::Command.new(project, user, params).execute Gitlab::SlashCommands::Command.new(project, user, params).execute
else else
url = authorize_chat_name_url(params) url = authorize_chat_name_url(params)
Gitlab::ChatCommands::Presenters::Access.new(url).authorize Gitlab::SlashCommands::Presenters::Access.new(url).authorize
end end
end end
......
...@@ -10,7 +10,7 @@ class GlobalPolicy < BasePolicy ...@@ -10,7 +10,7 @@ class GlobalPolicy < BasePolicy
can! :access_api can! :access_api
can! :access_git can! :access_git
can! :receive_notifications can! :receive_notifications
can! :use_slash_commands can! :use_quick_actions
end end
end end
end end
...@@ -142,9 +142,9 @@ class IssuableBaseService < BaseService ...@@ -142,9 +142,9 @@ class IssuableBaseService < BaseService
LabelsFinder.new(current_user, project_id: @project.id).execute LabelsFinder.new(current_user, project_id: @project.id).execute
end end
def merge_slash_commands_into_params!(issuable) def merge_quick_actions_into_params!(issuable)
description, command_params = description, command_params =
SlashCommands::InterpretService.new(project, current_user). QuickActions::InterpretService.new(project, current_user).
execute(params[:description], issuable) execute(params[:description], issuable)
# Avoid a description already set on an issuable to be overwritten by a nil # Avoid a description already set on an issuable to be overwritten by a nil
...@@ -162,7 +162,7 @@ class IssuableBaseService < BaseService ...@@ -162,7 +162,7 @@ class IssuableBaseService < BaseService
end end
def create(issuable) def create(issuable)
merge_slash_commands_into_params!(issuable) merge_quick_actions_into_params!(issuable)
filter_params(issuable) filter_params(issuable)
params.delete(:state_event) params.delete(:state_event)
......
...@@ -7,7 +7,7 @@ module MergeRequests ...@@ -7,7 +7,7 @@ module MergeRequests
params.except!(:target_project_id) params.except!(:target_project_id)
params.except!(:source_branch) params.except!(:source_branch)
merge_from_slash_command(merge_request) if params[:merge] merge_from_quick_action(merge_request) if params[:merge]
if merge_request.closed_without_fork? if merge_request.closed_without_fork?
params.except!(:target_branch, :force_remove_source_branch) params.except!(:target_branch, :force_remove_source_branch)
...@@ -74,9 +74,9 @@ module MergeRequests ...@@ -74,9 +74,9 @@ module MergeRequests
end end
end end
def merge_from_slash_command(merge_request) def merge_from_quick_action(merge_request)
last_diff_sha = params.delete(:merge) last_diff_sha = params.delete(:merge)
return unless merge_request.mergeable_with_slash_command?(current_user, last_diff_sha: last_diff_sha) return unless merge_request.mergeable_with_quick_action?(current_user, last_diff_sha: last_diff_sha)
merge_request.update(merge_error: nil) merge_request.update(merge_error: nil)
......
...@@ -9,11 +9,11 @@ module Notes ...@@ -9,11 +9,11 @@ module Notes
# We execute commands (extracted from `params[:note]`) on the noteable # We execute commands (extracted from `params[:note]`) on the noteable
# **before** we save the note because if the note consists of commands # **before** we save the note because if the note consists of commands
# only, there is no need be create a note! # only, there is no need be create a note!
slash_commands_service = SlashCommandsService.new(project, current_user) quick_actions_service = QuickActionsService.new(project, current_user)
if slash_commands_service.supported?(note) if quick_actions_service.supported?(note)
options = { merge_request_diff_head_sha: merge_request_diff_head_sha } options = { merge_request_diff_head_sha: merge_request_diff_head_sha }
content, command_params = slash_commands_service.extract_commands(note, options) content, command_params = quick_actions_service.extract_commands(note, options)
only_commands = content.empty? only_commands = content.empty?
...@@ -30,7 +30,7 @@ module Notes ...@@ -30,7 +30,7 @@ module Notes
end end
if command_params.present? if command_params.present?
slash_commands_service.execute(command_params, note) quick_actions_service.execute(command_params, note)
# We must add the error after we call #save because errors are reset # We must add the error after we call #save because errors are reset
# when #save is called # when #save is called
......
module Notes module Notes
class SlashCommandsService < BaseService class QuickActionsService < BaseService
UPDATE_SERVICES = { UPDATE_SERVICES = {
'Issue' => Issues::UpdateService, 'Issue' => Issues::UpdateService,
'MergeRequest' => MergeRequests::UpdateService 'MergeRequest' => MergeRequests::UpdateService
...@@ -22,7 +22,7 @@ module Notes ...@@ -22,7 +22,7 @@ module Notes
def extract_commands(note, options = {}) def extract_commands(note, options = {})
return [note.note, {}] unless supported?(note) return [note.note, {}] unless supported?(note)
SlashCommands::InterpretService.new(project, current_user, options). QuickActions::InterpretService.new(project, current_user, options).
execute(note.note, note.noteable) execute(note.note, note.noteable)
end end
......
class PreviewMarkdownService < BaseService class PreviewMarkdownService < BaseService
def execute def execute
text, commands = explain_slash_commands(params[:text]) text, commands = explain_quick_actions(params[:text])
users = find_user_references(text) users = find_user_references(text)
success( success(
...@@ -12,11 +12,11 @@ class PreviewMarkdownService < BaseService ...@@ -12,11 +12,11 @@ class PreviewMarkdownService < BaseService
private private
def explain_slash_commands(text) def explain_quick_actions(text)
return text, [] unless %w(Issue MergeRequest).include?(commands_target_type) return text, [] unless %w(Issue MergeRequest).include?(commands_target_type)
slash_commands_service = SlashCommands::InterpretService.new(project, current_user) quick_actions_service = QuickActions::InterpretService.new(project, current_user)
slash_commands_service.explain(text, find_commands_target) quick_actions_service.explain(text, find_commands_target)
end end
def find_user_references(text) def find_user_references(text)
...@@ -36,10 +36,10 @@ class PreviewMarkdownService < BaseService ...@@ -36,10 +36,10 @@ class PreviewMarkdownService < BaseService
end end
def commands_target_type def commands_target_type
params[:slash_commands_target_type] params[:quick_actions_target_type]
end end
def commands_target_id def commands_target_id
params[:slash_commands_target_id] params[:quick_actions_target_id]
end end
end end
...@@ -32,7 +32,7 @@ module Projects ...@@ -32,7 +32,7 @@ module Projects
issuable: noteable, issuable: noteable,
current_user: current_user current_user: current_user
} }
SlashCommands::InterpretService.command_definitions.map do |definition| QuickActions::InterpretService.command_definitions.map do |definition|
next unless definition.available?(opts) next unless definition.available?(opts)
definition.to_h(opts) definition.to_h(opts)
......
module SlashCommands module QuickActions
class InterpretService < BaseService class InterpretService < BaseService
include Gitlab::SlashCommands::Dsl include Gitlab::QuickActions::Dsl
attr_reader :issuable attr_reader :issuable
# Takes a text and interprets the commands that are extracted from it. # Takes a text and interprets the commands that are extracted from it.
# Returns the content without commands, and hash of changes to be applied to a record. # Returns the content without commands, and hash of changes to be applied to a record.
def execute(content, issuable) def execute(content, issuable)
return [content, {}] unless current_user.can?(:use_slash_commands) return [content, {}] unless current_user.can?(:use_quick_actions)
@issuable = issuable @issuable = issuable
@updates = {} @updates = {}
...@@ -20,7 +20,7 @@ module SlashCommands ...@@ -20,7 +20,7 @@ module SlashCommands
# Takes a text and interprets the commands that are extracted from it. # Takes a text and interprets the commands that are extracted from it.
# Returns the content without commands, and array of changes explained. # Returns the content without commands, and array of changes explained.
def explain(content, issuable) def explain(content, issuable)
return [content, []] unless current_user.can?(:use_slash_commands) return [content, []] unless current_user.can?(:use_quick_actions)
@issuable = issuable @issuable = issuable
...@@ -32,7 +32,7 @@ module SlashCommands ...@@ -32,7 +32,7 @@ module SlashCommands
private private
def extractor def extractor
Gitlab::SlashCommands::Extractor.new(self.class.command_definitions) Gitlab::QuickActions::Extractor.new(self.class.command_definitions)
end end
desc do desc do
...@@ -71,7 +71,7 @@ module SlashCommands ...@@ -71,7 +71,7 @@ module SlashCommands
last_diff_sha = params && params[:merge_request_diff_head_sha] last_diff_sha = params && params[:merge_request_diff_head_sha]
issuable.is_a?(MergeRequest) && issuable.is_a?(MergeRequest) &&
issuable.persisted? && issuable.persisted? &&
issuable.mergeable_with_slash_command?(current_user, autocomplete_precheck: !last_diff_sha, last_diff_sha: last_diff_sha) issuable.mergeable_with_quick_action?(current_user, autocomplete_precheck: !last_diff_sha, last_diff_sha: last_diff_sha)
end end
command :merge do command :merge do
@updates[:merge] = params[:merge_request_diff_head_sha] @updates[:merge] = params[:merge_request_diff_head_sha]
......
- @gfm_form = true - @gfm_form = true
- current_text ||= nil - current_text ||= nil
- supports_slash_commands = local_assigns.fetch(:supports_slash_commands, false) - supports_quick_actions = local_assigns.fetch(:supports_quick_actions, false)
.zen-backdrop .zen-backdrop
- classes << ' js-gfm-input js-autosize markdown-area' - classes << ' js-gfm-input js-autosize markdown-area'
- if defined?(f) && f - if defined?(f) && f
= f.text_area attr, class: classes, placeholder: placeholder, data: { supports_slash_commands: supports_slash_commands } = f.text_area attr, class: classes, placeholder: placeholder, data: { supports_quick_actions: supports_quick_actions }
- else - else
= text_area_tag attr, current_text, class: classes, placeholder: placeholder = text_area_tag attr, current_text, class: classes, placeholder: placeholder
%a.zen-control.zen-control-leave.js-zen-leave{ href: "#" } %a.zen-control.zen-control-leave.js-zen-leave{ href: "#" }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
%p %p
The subject will be used as the title of the new issue, and the message will be the description. The subject will be used as the title of the new issue, and the message will be the description.
= link_to 'Slash commands', help_page_path('user/project/slash_commands'), target: '_blank', tabindex: -1 = link_to 'Quick actions', help_page_path('user/project/quick_actions'), target: '_blank', tabindex: -1
and styling with and styling with
= link_to 'Markdown', help_page_path('user/markdown'), target: '_blank', tabindex: -1 = link_to 'Markdown', help_page_path('user/markdown'), target: '_blank', tabindex: -1
are supported. are supported.
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
- model = local_assigns.fetch(:model) - model = local_assigns.fetch(:model)
- form = local_assigns.fetch(:form) - form = local_assigns.fetch(:form)
- supports_slash_commands = model.new_record? - supports_quick_actions = model.new_record?
- if supports_slash_commands - if supports_quick_actions
- preview_url = preview_markdown_path(project, slash_commands_target_type: model.class.name) - preview_url = preview_markdown_path(project, quick_actions_target_type: model.class.name)
- else - else
- preview_url = preview_markdown_path(project) - preview_url = preview_markdown_path(project)
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
= render 'projects/zen', f: form, attr: :description, = render 'projects/zen', f: form, attr: :description,
classes: 'note-textarea', classes: 'note-textarea',
placeholder: "Write a comment or drag your files here...", placeholder: "Write a comment or drag your files here...",
supports_slash_commands: supports_slash_commands supports_quick_actions: supports_quick_actions
= render 'shared/notes/hints', supports_slash_commands: supports_slash_commands = render 'shared/notes/hints', supports_quick_actions: supports_quick_actions
.clearfix .clearfix
.error-alert .error-alert
- supports_slash_commands = note_supports_slash_commands?(@note) - supports_quick_actions = note_supports_quick_actions?(@note)
- if supports_slash_commands - if supports_quick_actions
- preview_url = preview_markdown_path(@project, slash_commands_target_type: @note.noteable_type, slash_commands_target_id: @note.noteable_id) - preview_url = preview_markdown_path(@project, quick_actions_target_type: @note.noteable_type, quick_actions_target_id: @note.noteable_id)
- else - else
- preview_url = preview_markdown_path(@project) - preview_url = preview_markdown_path(@project)
...@@ -27,8 +27,8 @@ ...@@ -27,8 +27,8 @@
attr: :note, attr: :note,
classes: 'note-textarea js-note-text', classes: 'note-textarea js-note-text',
placeholder: "Write a comment or drag your files here...", placeholder: "Write a comment or drag your files here...",
supports_slash_commands: supports_slash_commands supports_quick_actions: supports_quick_actions
= render 'shared/notes/hints', supports_slash_commands: supports_slash_commands = render 'shared/notes/hints', supports_quick_actions: supports_quick_actions
.error-alert .error-alert
.note-form-actions.clearfix .note-form-actions.clearfix
......
- supports_slash_commands = local_assigns.fetch(:supports_slash_commands, false) - supports_quick_actions = local_assigns.fetch(:supports_quick_actions, false)
.comment-toolbar.clearfix .comment-toolbar.clearfix
.toolbar-text .toolbar-text
= link_to 'Markdown', help_page_path('user/markdown'), target: '_blank', tabindex: -1 = link_to 'Markdown', help_page_path('user/markdown'), target: '_blank', tabindex: -1
- if supports_slash_commands - if supports_quick_actions
and and
= link_to 'slash commands', help_page_path('user/project/slash_commands'), target: '_blank', tabindex: -1 = link_to 'quick actions', help_page_path('user/project/quick_actions'), target: '_blank', tabindex: -1
are are
- else - else
is is
......
---
title: Rename "Slash commands" to "Quick actions" and deprecate "chat commands" in favor
of "slash commands"
merge_request:
author:
...@@ -24,7 +24,7 @@ Shortcuts to GitLab's most visited docs: ...@@ -24,7 +24,7 @@ Shortcuts to GitLab's most visited docs:
- [GitLab Workflow](workflow/README.md): Enhance your workflow with the best of GitLab Workflow. - [GitLab Workflow](workflow/README.md): Enhance your workflow with the best of GitLab Workflow.
- See also [GitLab Workflow - an overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/). - See also [GitLab Workflow - an overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/).
- [GitLab Markdown](user/markdown.md): GitLab's advanced formatting system (GitLab Flavored Markdown). - [GitLab Markdown](user/markdown.md): GitLab's advanced formatting system (GitLab Flavored Markdown).
- [GitLab Slash Commands](user/project/slash_commands.md): Textual shortcuts for common actions on issues or merge requests that are usually done by clicking buttons or dropdowns in GitLab's UI. - [GitLab Quick Actions](user/project/quick_actions.md): Textual shortcuts for common actions on issues or merge requests that are usually done by clicking buttons or dropdowns in GitLab's UI.
### User account ### User account
......
...@@ -166,8 +166,8 @@ For instance this kind of thing: ...@@ -166,8 +166,8 @@ For instance this kind of thing:
= render 'projects/zen', f: form, attr: :description, = render 'projects/zen', f: form, attr: :description,
classes: 'note-textarea', classes: 'note-textarea',
placeholder: "Write a comment or drag your files here...", placeholder: "Write a comment or drag your files here...",
supports_slash_commands: !issuable.persisted? supports_quick_actions: !issuable.persisted?
= render 'projects/notes/hints', supports_slash_commands: !issuable.persisted? = render 'projects/notes/hints', supports_quick_actions: !issuable.persisted?
.clearfix .clearfix
.error-alert .error-alert
- if issuable.is_a?(Issue) - if issuable.is_a?(Issue)
......
# Chat Commands This document was moved to [integration/slash_commands.md](slash_commands.md).
Chat commands in Mattermost and Slack (also called Slack slash commands) allow you to control GitLab and view GitLab content right inside your chat client, without having to leave it. For Slack, this requires a [project service configuration](../user/project/integrations/slack_slash_commands.md). Simply type the command as a message in your chat client to activate it.
Commands are scoped to a project, with a trigger term that is specified during configuration. (We suggest you use the project name as the trigger term for simplicty and clarity.) Taking the trigger term as `project-name`, the commands are:
| Command | Effect |
| ------- | ------ |
| `/project-name help` | Shows all available chat commands |
| `/project-name issue new <title> <shift+return> <description>` | Creates a new issue with title `<title>` and description `<description>` |
| `/project-name issue show <id>` | Shows the issue with id `<id>` |
| `/project-name issue search <query>` | Shows up to 5 issues matching `<query>` |
| `/project-name deploy <from> to <to>` | Deploy from the `<from>` environment to the `<to>` environment |
\ No newline at end of file
# Slash Commands
Slash commands in Mattermost and Slack allow you to control GitLab and view GitLab content right inside your chat client, without having to leave it. For Slack, this requires a [project service configuration](../user/project/integrations/slack_slash_commands.md). Simply type the command as a message in your chat client to activate it.
Commands are scoped to a project, with a trigger term that is specified during configuration. (We suggest you use the project name as the trigger term for simplicty and clarity.) Taking the trigger term as `project-name`, the commands are:
| Command | Effect |
| ------- | ------ |
| `/project-name help` | Shows all available slash commands |
| `/project-name issue new <title> <shift+return> <description>` | Creates a new issue with title `<title>` and description `<description>` |
| `/project-name issue show <id>` | Shows the issue with id `<id>` |
| `/project-name issue search <query>` | Shows up to 5 issues matching `<query>` |
| `/project-name deploy <from> to <to>` | Deploy from the `<from>` environment to the `<to>` environment |
...@@ -10,7 +10,7 @@ You can leave a comment in the following places: ...@@ -10,7 +10,7 @@ You can leave a comment in the following places:
- commits - commits
- commit diffs - commit diffs
The comment area supports [Markdown] and [slash commands]. One can edit their The comment area supports [Markdown] and [quick actions]. One can edit their
own comment at any time, and anyone with [Master access level][permissions] or own comment at any time, and anyone with [Master access level][permissions] or
higher can also edit a comment made by someone else. higher can also edit a comment made by someone else.
...@@ -146,5 +146,5 @@ comments in greater detail. ...@@ -146,5 +146,5 @@ comments in greater detail.
[discussion-view]: img/discussion_view.png [discussion-view]: img/discussion_view.png
[discussions-resolved]: img/discussions_resolved.png [discussions-resolved]: img/discussions_resolved.png
[markdown]: ../markdown.md [markdown]: ../markdown.md
[slash commands]: ../project/slash_commands.md [quick actions]: ../project/quick_actions.md
[permissions]: ../permissions.md [permissions]: ../permissions.md
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
> Introduced in GitLab 8.15 > Introduced in GitLab 8.15
Slack slash commands (also known as chat commmands) allow you to control GitLab and view content right inside Slack, without having to leave it. This requires configurations in both Slack and GitLab. Slack slash commands allow you to control GitLab and view content right inside Slack, without having to leave it. This requires configurations in both Slack and GitLab.
> Note: GitLab can also send events (e.g. issue created) to Slack as notifications. This is the separately configured [Slack Notifications Service](slack.md). > Note: GitLab can also send events (e.g. issue created) to Slack as notifications. This is the separately configured [Slack Notifications Service](slack.md).
...@@ -20,4 +20,4 @@ Slack slash commands (also known as chat commmands) allow you to control GitLab ...@@ -20,4 +20,4 @@ Slack slash commands (also known as chat commmands) allow you to control GitLab
## Usage ## Usage
You can now use the [Slack slash commands](../../../integration/chat_commands.md). You can now use the [Slack slash commands](../../../integration/slash_commands.md).
\ No newline at end of file
...@@ -68,7 +68,7 @@ This feature is available only in [GitLab Enterprise Edition](https://about.gitl ...@@ -68,7 +68,7 @@ This feature is available only in [GitLab Enterprise Edition](https://about.gitl
- Spend: add the time spent on the implementation of that issue - Spend: add the time spent on the implementation of that issue
> **Note:** > **Note:**
both estimate and spend times are set via [GitLab Slash Commands](../slash_commands.md). both estimate and spend times are set via [GitLab Quick Actions](../quick_actions.md).
Learn more on the [Time Tracking documentation](https://docs.gitlab.com/ee/workflow/time_tracking.html). Learn more on the [Time Tracking documentation](https://docs.gitlab.com/ee/workflow/time_tracking.html).
...@@ -147,7 +147,7 @@ or in the issue thread. ...@@ -147,7 +147,7 @@ or in the issue thread.
#### 15. Award emoji #### 15. Award emoji
- Award an emoji to that issue. - Award an emoji to that issue.
> **Tip:** > **Tip:**
Posting "+1" as comments in threads spam all Posting "+1" as comments in threads spam all
......
# GitLab quick actions
Quick actions are textual shortcuts for common actions on issues or merge
requests that are usually done by clicking buttons or dropdowns in GitLab's UI.
You can enter these commands while creating a new issue or merge request, and
in comments. Each command should be on a separate line in order to be properly
detected and executed. The commands are removed from the issue, merge request or
comment body before it is saved and will not be visible to anyone else.
Below is a list of all of the available commands and descriptions about what they
do.
| Command | Action |
|:---------------------------|:-------------|
| `/close` | Close the issue or merge request |
| `/reopen` | Reopen the issue or merge request |
| `/merge` | Merge (when pipeline succeeds) |
| `/title <New title>` | Change title |
| `/assign @username` | Assign |
| `/unassign` | Remove assignee |
| `/milestone %milestone` | Set milestone |
| `/remove_milestone` | Remove milestone |
| `/label ~foo ~"bar baz"` | Add label(s) |
| `/unlabel ~foo ~"bar baz"` | Remove all or specific label(s) |
| `/relabel ~foo ~"bar baz"` | Replace all label(s) |
| `/todo` | Add a todo |
| `/done` | Mark todo as done |
| `/subscribe` | Subscribe |
| `/unsubscribe` | Unsubscribe |
| <code>/due &lt;in 2 days &#124; this Friday &#124; December 31st&gt;</code> | Set due date |
| `/remove_due_date` | Remove due date |
| `/wip` | Toggle the Work In Progress status |
| <code>/estimate &lt;1w 3d 2h 14m&gt;</code> | Set time estimate |
| `/remove_estimate` | Remove estimated time |
| <code>/spend &lt;1h 30m &#124; -1h 5m&gt;</code> | Add or subtract spent time |
| `/remove_time_spent` | Remove time spent |
| `/target_branch <Branch Name>` | Set target branch for current merge request |
| `/award :emoji:` | Toggle award for :emoji: |
| `/board_move ~column` | Move issue to column on the board |
# GitLab slash commands This document was moved to [user/project/quick_actions.md](quick_actions.md).
Slash commands are textual shortcuts for common actions on issues or merge
requests that are usually done by clicking buttons or dropdowns in GitLab's UI.
You can enter these commands while creating a new issue or merge request, and
in comments. Each command should be on a separate line in order to be properly
detected and executed. The commands are removed from the issue, merge request or
comment body before it is saved and will not be visible to anyone else.
Below is a list of all of the available commands and descriptions about what they
do.
| Command | Action |
|:---------------------------|:-------------|
| `/close` | Close the issue or merge request |
| `/reopen` | Reopen the issue or merge request |
| `/merge` | Merge (when pipeline succeeds) |
| `/title <New title>` | Change title |
| `/assign @username` | Assign |
| `/unassign` | Remove assignee |
| `/milestone %milestone` | Set milestone |
| `/remove_milestone` | Remove milestone |
| `/label ~foo ~"bar baz"` | Add label(s) |
| `/unlabel ~foo ~"bar baz"` | Remove all or specific label(s) |
| `/relabel ~foo ~"bar baz"` | Replace all label(s) |
| `/todo` | Add a todo |
| `/done` | Mark todo as done |
| `/subscribe` | Subscribe |
| `/unsubscribe` | Unsubscribe |
| <code>/due &lt;in 2 days &#124; this Friday &#124; December 31st&gt;</code> | Set due date |
| `/remove_due_date` | Remove due date |
| `/wip` | Toggle the Work In Progress status |
| <code>/estimate &lt;1w 3d 2h 14m&gt;</code> | Set time estimate |
| `/remove_estimate` | Remove estimated time |
| <code>/spend &lt;1h 30m &#124; -1h 5m&gt;</code> | Add or subtract spent time |
| `/remove_time_spent` | Remove time spent |
| `/target_branch <Branch Name>` | Set target branch for current merge request |
| `/award :emoji:` | Toggle award for :emoji: |
| `/board_move ~column` | Move issue to column on the board |
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
- [Project users](add-user/add-user.md) - [Project users](add-user/add-user.md)
- [Protected branches](../user/project/protected_branches.md) - [Protected branches](../user/project/protected_branches.md)
- [Protected tags](../user/project/protected_tags.md) - [Protected tags](../user/project/protected_tags.md)
- [Slash commands](../user/project/slash_commands.md) - [Quick Actions](../user/project/quick_actions.md)
- [Sharing a project with a group](share_with_group.md) - [Sharing a project with a group](share_with_group.md)
- [Share projects with other groups](share_projects_with_other_groups.md) - [Share projects with other groups](share_projects_with_other_groups.md)
- [Time tracking](time_tracking.md) - [Time tracking](time_tracking.md)
......
...@@ -21,13 +21,13 @@ below. ...@@ -21,13 +21,13 @@ below.
## How to enter data ## How to enter data
Time Tracking uses two [slash commands] that GitLab introduced with this new Time Tracking uses two [quick actions] that GitLab introduced with this new
feature: `/spend` and `/estimate`. feature: `/spend` and `/estimate`.
Slash commands can be used in the body of an issue or a merge request, but also Quick actions can be used in the body of an issue or a merge request, but also
in a comment in both an issue or a merge request. in a comment in both an issue or a merge request.
Below is an example of how you can use those new slash commands inside a comment. Below is an example of how you can use those new quick actions inside a comment.
![Time tracking example in a comment](time-tracking/time-tracking-example.png) ![Time tracking example in a comment](time-tracking/time-tracking-example.png)
...@@ -70,4 +70,4 @@ The following time units are available: ...@@ -70,4 +70,4 @@ The following time units are available:
Default conversion rates are 1w = 5d and 1d = 8h. Default conversion rates are 1w = 5d and 1d = 8h.
[landing]: https://about.gitlab.com/features/time-tracking [landing]: https://about.gitlab.com/features/time-tracking
[slash-commands]: ../user/project/slash_commands.md [quick actions]: ../user/project/quick_actions.md
...@@ -685,7 +685,7 @@ module API ...@@ -685,7 +685,7 @@ module API
trigger_services.each do |service_slug, settings| trigger_services.each do |service_slug, settings|
helpers do helpers do
def chat_command_service(project, service_slug, params) def slash_command_service(project, service_slug, params)
project.services.active.where(template: false).find do |service| project.services.active.where(template: false).find do |service|
service.try(:token) == params[:token] && service.to_param == service_slug.underscore service.try(:token) == params[:token] && service.to_param == service_slug.underscore
end end
...@@ -710,7 +710,7 @@ module API ...@@ -710,7 +710,7 @@ module API
# This is not accurate, but done to prevent leakage of the project names # This is not accurate, but done to prevent leakage of the project names
not_found!('Service') unless project not_found!('Service') unless project
service = chat_command_service(project, service_slug, params) service = slash_command_service(project, service_slug, params)
result = service.try(:trigger, params) result = service.try(:trigger, params)
if result if result
......
...@@ -608,7 +608,7 @@ module API ...@@ -608,7 +608,7 @@ module API
trigger_services.each do |service_slug, settings| trigger_services.each do |service_slug, settings|
helpers do helpers do
def chat_command_service(project, service_slug, params) def slash_command_service(project, service_slug, params)
project.services.active.where(template: false).find do |service| project.services.active.where(template: false).find do |service|
service.try(:token) == params[:token] && service.to_param == service_slug.underscore service.try(:token) == params[:token] && service.to_param == service_slug.underscore
end end
...@@ -633,7 +633,7 @@ module API ...@@ -633,7 +633,7 @@ module API
# This is not accurate, but done to prevent leakage of the project names # This is not accurate, but done to prevent leakage of the project names
not_found!('Service') unless project not_found!('Service') unless project
service = chat_command_service(project, service_slug, params) service = slash_command_service(project, service_slug, params)
result = service.try(:trigger, params) result = service.try(:trigger, params)
if result if result
......
module Gitlab module Gitlab
module SlashCommands module QuickActions
class CommandDefinition class CommandDefinition
attr_accessor :name, :aliases, :description, :explanation, :params, attr_accessor :name, :aliases, :description, :explanation, :params,
:condition_block, :parse_params_block, :action_block :condition_block, :parse_params_block, :action_block
......
module Gitlab module Gitlab
module SlashCommands module QuickActions
module Dsl module Dsl
extend ActiveSupport::Concern extend ActiveSupport::Concern
...@@ -14,7 +14,7 @@ module Gitlab ...@@ -14,7 +14,7 @@ module Gitlab
end end
class_methods do class_methods do
# Allows to give a description to the next slash command. # Allows to give a description to the next quick action.
# This description is shown in the autocomplete menu. # This description is shown in the autocomplete menu.
# It accepts a block that will be evaluated with the context given to # It accepts a block that will be evaluated with the context given to
# `CommandDefintion#to_h`. # `CommandDefintion#to_h`.
...@@ -31,7 +31,7 @@ module Gitlab ...@@ -31,7 +31,7 @@ module Gitlab
@description = block_given? ? block : text @description = block_given? ? block : text
end end
# Allows to define params for the next slash command. # Allows to define params for the next quick action.
# These params are shown in the autocomplete menu. # These params are shown in the autocomplete menu.
# #
# Example: # Example:
......
module Gitlab module Gitlab
module SlashCommands module QuickActions
# This class takes an array of commands that should be extracted from a # This class takes an array of commands that should be extracted from a
# given text. # given text.
# #
# ``` # ```
# extractor = Gitlab::SlashCommands::Extractor.new([:open, :assign, :labels]) # extractor = Gitlab::QuickActions::Extractor.new([:open, :assign, :labels])
# ``` # ```
class Extractor class Extractor
attr_reader :command_definitions attr_reader :command_definitions
...@@ -24,7 +24,7 @@ module Gitlab ...@@ -24,7 +24,7 @@ module Gitlab
# #
# Usage: # Usage:
# ``` # ```
# extractor = Gitlab::SlashCommands::Extractor.new([:open, :assign, :labels]) # extractor = Gitlab::QuickActions::Extractor.new([:open, :assign, :labels])
# msg = %(hello\n/labels ~foo ~"bar baz"\nworld) # msg = %(hello\n/labels ~foo ~"bar baz"\nworld)
# commands = extractor.extract_commands(msg) #=> [['labels', '~foo ~"bar baz"']] # commands = extractor.extract_commands(msg) #=> [['labels', '~foo ~"bar baz"']]
# msg #=> "hello\nworld" # msg #=> "hello\nworld"
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
class BaseCommand class BaseCommand
QUERY_LIMIT = 5 QUERY_LIMIT = 5
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
class Command < BaseCommand class Command < BaseCommand
COMMANDS = [ COMMANDS = [
Gitlab::ChatCommands::IssueShow, Gitlab::SlashCommands::IssueShow,
Gitlab::ChatCommands::IssueNew, Gitlab::SlashCommands::IssueNew,
Gitlab::ChatCommands::IssueSearch, Gitlab::SlashCommands::IssueSearch,
Gitlab::ChatCommands::Deploy Gitlab::SlashCommands::Deploy
].freeze ].freeze
def execute def execute
...@@ -15,10 +15,10 @@ module Gitlab ...@@ -15,10 +15,10 @@ module Gitlab
if command.allowed?(project, current_user) if command.allowed?(project, current_user)
command.new(project, current_user, params).execute(match) command.new(project, current_user, params).execute(match)
else else
Gitlab::ChatCommands::Presenters::Access.new.access_denied Gitlab::SlashCommands::Presenters::Access.new.access_denied
end end
else else
Gitlab::ChatCommands::Help.new(project, current_user, params).execute(available_commands, params[:text]) Gitlab::SlashCommands::Help.new(project, current_user, params).execute(available_commands, params[:text])
end end
end end
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
class Deploy < BaseCommand class Deploy < BaseCommand
def self.match(text) def self.match(text)
/\Adeploy\s+(?<from>\S+.*)\s+to+\s+(?<to>\S+.*)\z/.match(text) /\Adeploy\s+(?<from>\S+.*)\s+to+\s+(?<to>\S+.*)\z/.match(text)
...@@ -24,12 +24,12 @@ module Gitlab ...@@ -24,12 +24,12 @@ module Gitlab
actions = find_actions(from, to) actions = find_actions(from, to)
if actions.none? if actions.none?
Gitlab::ChatCommands::Presenters::Deploy.new(nil).no_actions Gitlab::SlashCommands::Presenters::Deploy.new(nil).no_actions
elsif actions.one? elsif actions.one?
action = play!(from, to, actions.first) action = play!(from, to, actions.first)
Gitlab::ChatCommands::Presenters::Deploy.new(action).present(from, to) Gitlab::SlashCommands::Presenters::Deploy.new(action).present(from, to)
else else
Gitlab::ChatCommands::Presenters::Deploy.new(actions).too_many_actions Gitlab::SlashCommands::Presenters::Deploy.new(actions).too_many_actions
end end
end end
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
class Help < BaseCommand class Help < BaseCommand
# This class has to be used last, as it always matches. It has to match # This class has to be used last, as it always matches. It has to match
# because other commands were not triggered and we want to show the help # because other commands were not triggered and we want to show the help
...@@ -17,7 +17,7 @@ module Gitlab ...@@ -17,7 +17,7 @@ module Gitlab
end end
def execute(commands, text) def execute(commands, text)
Gitlab::ChatCommands::Presenters::Help.new(commands).present(trigger, text) Gitlab::SlashCommands::Presenters::Help.new(commands).present(trigger, text)
end end
def trigger def trigger
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
class IssueCommand < BaseCommand class IssueCommand < BaseCommand
def self.available?(project) def self.available?(project)
project.issues_enabled? && project.default_issues_tracker? project.issues_enabled? && project.default_issues_tracker?
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
class IssueNew < IssueCommand class IssueNew < IssueCommand
def self.match(text) def self.match(text)
# we can not match \n with the dot by passing the m modifier as than # we can not match \n with the dot by passing the m modifier as than
...@@ -35,7 +35,7 @@ module Gitlab ...@@ -35,7 +35,7 @@ module Gitlab
end end
def presenter(issue) def presenter(issue)
Gitlab::ChatCommands::Presenters::IssueNew.new(issue) Gitlab::SlashCommands::Presenters::IssueNew.new(issue)
end end
end end
end end
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
class IssueSearch < IssueCommand class IssueSearch < IssueCommand
def self.match(text) def self.match(text)
/\Aissue\s+search\s+(?<query>.*)/.match(text) /\Aissue\s+search\s+(?<query>.*)/.match(text)
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
class IssueShow < IssueCommand class IssueShow < IssueCommand
def self.match(text) def self.match(text)
/\Aissue\s+show\s+#{Issue.reference_prefix}?(?<iid>\d+)/.match(text) /\Aissue\s+show\s+#{Issue.reference_prefix}?(?<iid>\d+)/.match(text)
...@@ -13,9 +13,9 @@ module Gitlab ...@@ -13,9 +13,9 @@ module Gitlab
issue = find_by_iid(match[:iid]) issue = find_by_iid(match[:iid])
if issue if issue
Gitlab::ChatCommands::Presenters::IssueShow.new(issue).present Gitlab::SlashCommands::Presenters::IssueShow.new(issue).present
else else
Gitlab::ChatCommands::Presenters::Access.new.not_found Gitlab::SlashCommands::Presenters::Access.new.not_found
end end
end end
end end
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
module Presenters module Presenters
class Access < Presenters::Base class Access < Presenters::Base
def access_denied def access_denied
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
module Presenters module Presenters
class Base class Base
include Gitlab::Routing.url_helpers include Gitlab::Routing.url_helpers
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
module Presenters module Presenters
class Deploy < Presenters::Base class Deploy < Presenters::Base
def present(from, to) def present(from, to)
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
module Presenters module Presenters
class Help < Presenters::Base class Help < Presenters::Base
def present(trigger, text) def present(trigger, text)
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
module Presenters module Presenters
module IssueBase module IssueBase
def color(issuable) def color(issuable)
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
module Presenters module Presenters
class IssueNew < Presenters::Base class IssueNew < Presenters::Base
include Presenters::IssueBase include Presenters::IssueBase
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
module Presenters module Presenters
class IssueSearch < Presenters::Base class IssueSearch < Presenters::Base
include Presenters::IssueBase include Presenters::IssueBase
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
module Presenters module Presenters
class IssueShow < Presenters::Base class IssueShow < Presenters::Base
include Presenters::IssueBase include Presenters::IssueBase
......
module Gitlab module Gitlab
module ChatCommands module SlashCommands
Result = Struct.new(:type, :message) Result = Struct.new(:type, :message)
end end
end end
...@@ -702,7 +702,7 @@ describe Projects::IssuesController do ...@@ -702,7 +702,7 @@ describe Projects::IssuesController do
end end
end end
context 'when description has slash commands' do context 'when description has quick actions' do
before do before do
sign_in(user) sign_in(user)
end end
......
...@@ -81,13 +81,13 @@ describe 'Awards Emoji', feature: true do ...@@ -81,13 +81,13 @@ describe 'Awards Emoji', feature: true do
end end
end end
context 'execute /award slash command' do context 'execute /award quick action' do
it 'toggles the emoji award on noteable', js: true do it 'toggles the emoji award on noteable', js: true do
execute_slash_command('/award :100:') execute_quick_action('/award :100:')
expect(find(noteable_award_counter)).to have_text("1") expect(find(noteable_award_counter)).to have_text("1")
execute_slash_command('/award :100:') execute_quick_action('/award :100:')
expect(page).not_to have_selector(noteable_award_counter) expect(page).not_to have_selector(noteable_award_counter)
end end
...@@ -105,7 +105,7 @@ describe 'Awards Emoji', feature: true do ...@@ -105,7 +105,7 @@ describe 'Awards Emoji', feature: true do
end end
end end
def execute_slash_command(cmd) def execute_quick_action(cmd)
within('.js-main-target-form') do within('.js-main-target-form') do
fill_in 'note[note]', with: cmd fill_in 'note[note]', with: cmd
click_button 'Comment' click_button 'Comment'
......
...@@ -208,7 +208,7 @@ feature 'GFM autocomplete', feature: true, js: true do ...@@ -208,7 +208,7 @@ feature 'GFM autocomplete', feature: true, js: true do
expect(page).not_to have_selector('.atwho-view') expect(page).not_to have_selector('.atwho-view')
end end
it 'triggers autocomplete after selecting a slash command' do it 'triggers autocomplete after selecting a quick action' do
note = find('#note_note') note = find('#note_note')
page.within '.timeline-content-form' do page.within '.timeline-content-form' do
note.native.send_keys('') note.native.send_keys('')
......
require 'rails_helper' require 'rails_helper'
feature 'Issues > User uses slash commands', feature: true, js: true do feature 'Issues > User uses quick actions', feature: true, js: true do
include SlashCommandsHelpers include QuickActionsHelpers
it_behaves_like 'issuable record that supports slash commands in its description and notes', :issue do it_behaves_like 'issuable record that supports quick actions in its description and notes', :issue do
let(:issuable) { create(:issue, project: project) } let(:issuable) { create(:issue, project: project) }
end end
......
require 'rails_helper' require 'rails_helper'
feature 'Merge Requests > User uses slash commands', feature: true, js: true do feature 'Merge Requests > User uses quick actions', feature: true, js: true do
include SlashCommandsHelpers include QuickActionsHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
let(:merge_request) { create(:merge_request, source_project: project) } let(:merge_request) { create(:merge_request, source_project: project) }
let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } let!(:milestone) { create(:milestone, project: project, title: 'ASAP') }
it_behaves_like 'issuable record that supports slash commands in its description and notes', :merge_request do it_behaves_like 'issuable record that supports quick actions in its description and notes', :merge_request do
let(:issuable) { create(:merge_request, source_project: project) } let(:issuable) { create(:merge_request, source_project: project) }
let(:new_url_opts) { { merge_request: { source_branch: 'feature', target_branch: 'master' } } } let(:new_url_opts) { { merge_request: { source_branch: 'feature', target_branch: 'master' } } }
end end
......
...@@ -550,46 +550,46 @@ import '~/notes'; ...@@ -550,46 +550,46 @@ import '~/notes';
}); });
}); });
describe('hasSlashCommands', () => { describe('hasQuickActions', () => {
beforeEach(() => { beforeEach(() => {
this.notes = new Notes('', []); this.notes = new Notes('', []);
}); });
it('should return true when comment begins with a slash command', () => { it('should return true when comment begins with a quick action', () => {
const sampleComment = '/wip\n/milestone %1.0\n/merge\n/unassign Merging this'; const sampleComment = '/wip\n/milestone %1.0\n/merge\n/unassign Merging this';
const hasSlashCommands = this.notes.hasSlashCommands(sampleComment); const hasQuickActions = this.notes.hasQuickActions(sampleComment);
expect(hasSlashCommands).toBeTruthy(); expect(hasQuickActions).toBeTruthy();
}); });
it('should return false when comment does NOT begin with a slash command', () => { it('should return false when comment does NOT begin with a quick action', () => {
const sampleComment = 'Hey, /unassign Merging this'; const sampleComment = 'Hey, /unassign Merging this';
const hasSlashCommands = this.notes.hasSlashCommands(sampleComment); const hasQuickActions = this.notes.hasQuickActions(sampleComment);
expect(hasSlashCommands).toBeFalsy(); expect(hasQuickActions).toBeFalsy();
}); });
it('should return false when comment does NOT have any slash commands', () => { it('should return false when comment does NOT have any quick actions', () => {
const sampleComment = 'Looking good, Awesome!'; const sampleComment = 'Looking good, Awesome!';
const hasSlashCommands = this.notes.hasSlashCommands(sampleComment); const hasQuickActions = this.notes.hasQuickActions(sampleComment);
expect(hasSlashCommands).toBeFalsy(); expect(hasQuickActions).toBeFalsy();
}); });
}); });
describe('stripSlashCommands', () => { describe('stripQuickActions', () => {
it('should strip slash commands from the comment which begins with a slash command', () => { it('should strip quick actions from the comment which begins with a quick action', () => {
this.notes = new Notes(); this.notes = new Notes();
const sampleComment = '/wip\n/milestone %1.0\n/merge\n/unassign Merging this'; const sampleComment = '/wip\n/milestone %1.0\n/merge\n/unassign Merging this';
const stripedComment = this.notes.stripSlashCommands(sampleComment); const stripedComment = this.notes.stripQuickActions(sampleComment);
expect(stripedComment).toBe(''); expect(stripedComment).toBe('');
}); });
it('should strip slash commands from the comment but leaves plain comment if it is present', () => { it('should strip quick actions from the comment but leaves plain comment if it is present', () => {
this.notes = new Notes(); this.notes = new Notes();
const sampleComment = '/wip\n/milestone %1.0\n/merge\n/unassign\nMerging this'; const sampleComment = '/wip\n/milestone %1.0\n/merge\n/unassign\nMerging this';
const stripedComment = this.notes.stripSlashCommands(sampleComment); const stripedComment = this.notes.stripQuickActions(sampleComment);
expect(stripedComment).toBe('Merging this'); expect(stripedComment).toBe('Merging this');
}); });
...@@ -597,14 +597,14 @@ import '~/notes'; ...@@ -597,14 +597,14 @@ import '~/notes';
it('should NOT strip string that has slashes within', () => { it('should NOT strip string that has slashes within', () => {
this.notes = new Notes(); this.notes = new Notes();
const sampleComment = 'http://127.0.0.1:3000/root/gitlab-shell/issues/1'; const sampleComment = 'http://127.0.0.1:3000/root/gitlab-shell/issues/1';
const stripedComment = this.notes.stripSlashCommands(sampleComment); const stripedComment = this.notes.stripQuickActions(sampleComment);
expect(stripedComment).toBe(sampleComment); expect(stripedComment).toBe(sampleComment);
}); });
}); });
describe('getSlashCommandDescription', () => { describe('getQuickActionDescription', () => {
const availableSlashCommands = [ const availableQuickActions = [
{ name: 'close', description: 'Close this issue', params: [] }, { name: 'close', description: 'Close this issue', params: [] },
{ name: 'title', description: 'Change title', params: [{}] }, { name: 'title', description: 'Change title', params: [{}] },
{ name: 'estimate', description: 'Set time estimate', params: [{}] } { name: 'estimate', description: 'Set time estimate', params: [{}] }
...@@ -614,19 +614,19 @@ import '~/notes'; ...@@ -614,19 +614,19 @@ import '~/notes';
this.notes = new Notes(); this.notes = new Notes();
}); });
it('should return executing slash command description when note has single slash command', () => { it('should return executing quick action description when note has single quick action', () => {
const sampleComment = '/close'; const sampleComment = '/close';
expect(this.notes.getSlashCommandDescription(sampleComment, availableSlashCommands)).toBe('Applying command to close this issue'); expect(this.notes.getQuickActionDescription(sampleComment, availableQuickActions)).toBe('Applying command to close this issue');
}); });
it('should return generic multiple slash command description when note has multiple slash commands', () => { it('should return generic multiple quick action description when note has multiple quick actions', () => {
const sampleComment = '/close\n/title [Duplicate] Issue foobar'; const sampleComment = '/close\n/title [Duplicate] Issue foobar';
expect(this.notes.getSlashCommandDescription(sampleComment, availableSlashCommands)).toBe('Applying multiple commands'); expect(this.notes.getQuickActionDescription(sampleComment, availableQuickActions)).toBe('Applying multiple commands');
}); });
it('should return generic slash command description when available slash commands list is not populated', () => { it('should return generic quick action description when available quick actions list is not populated', () => {
const sampleComment = '/close\n/title [Duplicate] Issue foobar'; const sampleComment = '/close\n/title [Duplicate] Issue foobar';
expect(this.notes.getSlashCommandDescription(sampleComment)).toBe('Applying command'); expect(this.notes.getQuickActionDescription(sampleComment)).toBe('Applying command');
}); });
}); });
......
...@@ -91,7 +91,7 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do ...@@ -91,7 +91,7 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do
end end
end end
context 'when the note contains slash commands' do context 'when the note contains quick actions' do
let!(:email_raw) { fixture_file("emails/commands_in_reply.eml") } let!(:email_raw) { fixture_file("emails/commands_in_reply.eml") }
context 'and current user cannot update noteable' do context 'and current user cannot update noteable' do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::SlashCommands::CommandDefinition do describe Gitlab::QuickActions::CommandDefinition do
subject { described_class.new(:command) } subject { described_class.new(:command) }
describe "#all_names" do describe "#all_names" do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::SlashCommands::Dsl do describe Gitlab::QuickActions::Dsl do
before :all do before :all do
DummyClass = Struct.new(:project) do DummyClass = Struct.new(:project) do
include Gitlab::SlashCommands::Dsl # rubocop:disable RSpec/DescribedClass include Gitlab::QuickActions::Dsl # rubocop:disable RSpec/DescribedClass
desc 'A command with no args' desc 'A command with no args'
command :no_args, :none do command :no_args, :none do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::SlashCommands::Extractor do describe Gitlab::QuickActions::Extractor do
let(:definitions) do let(:definitions) do
Class.new do Class.new do
include Gitlab::SlashCommands::Dsl include Gitlab::QuickActions::Dsl
command(:reopen, :open) { } command(:reopen, :open) { }
command(:assign) { } command(:assign) { }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::ChatCommands::Command, service: true do describe Gitlab::SlashCommands::Command, service: true do
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
let(:user) { create(:user) } let(:user) { create(:user) }
...@@ -93,19 +93,19 @@ describe Gitlab::ChatCommands::Command, service: true do ...@@ -93,19 +93,19 @@ describe Gitlab::ChatCommands::Command, service: true do
context 'IssueShow is triggered' do context 'IssueShow is triggered' do
let(:params) { { text: 'issue show 123' } } let(:params) { { text: 'issue show 123' } }
it { is_expected.to eq(Gitlab::ChatCommands::IssueShow) } it { is_expected.to eq(Gitlab::SlashCommands::IssueShow) }
end end
context 'IssueCreate is triggered' do context 'IssueCreate is triggered' do
let(:params) { { text: 'issue create my title' } } let(:params) { { text: 'issue create my title' } }
it { is_expected.to eq(Gitlab::ChatCommands::IssueNew) } it { is_expected.to eq(Gitlab::SlashCommands::IssueNew) }
end end
context 'IssueSearch is triggered' do context 'IssueSearch is triggered' do
let(:params) { { text: 'issue search my query' } } let(:params) { { text: 'issue search my query' } }
it { is_expected.to eq(Gitlab::ChatCommands::IssueSearch) } it { is_expected.to eq(Gitlab::SlashCommands::IssueSearch) }
end end
end end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::ChatCommands::Deploy, service: true do describe Gitlab::SlashCommands::Deploy, service: true do
describe '#execute' do describe '#execute' do
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
let(:user) { create(:user) } let(:user) { create(:user) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::ChatCommands::IssueNew, service: true do describe Gitlab::SlashCommands::IssueNew, service: true do
describe '#execute' do describe '#execute' do
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
let(:user) { create(:user) } let(:user) { create(:user) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::ChatCommands::IssueSearch, service: true do describe Gitlab::SlashCommands::IssueSearch, service: true do
describe '#execute' do describe '#execute' do
let!(:issue) { create(:issue, project: project, title: 'find me') } let!(:issue) { create(:issue, project: project, title: 'find me') }
let!(:confidential) { create(:issue, :confidential, project: project, title: 'mepmep find') } let!(:confidential) { create(:issue, :confidential, project: project, title: 'mepmep find') }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::ChatCommands::IssueShow, service: true do describe Gitlab::SlashCommands::IssueShow, service: true do
describe '#execute' do describe '#execute' do
let(:issue) { create(:issue, project: project) } let(:issue) { create(:issue, project: project) }
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::ChatCommands::Presenters::Access do describe Gitlab::SlashCommands::Presenters::Access do
describe '#access_denied' do describe '#access_denied' do
subject { described_class.new.access_denied } subject { described_class.new.access_denied }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::ChatCommands::Presenters::Deploy do describe Gitlab::SlashCommands::Presenters::Deploy do
let(:build) { create(:ci_build) } let(:build) { create(:ci_build) }
describe '#present' do describe '#present' do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::ChatCommands::Presenters::IssueNew do describe Gitlab::SlashCommands::Presenters::IssueNew do
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) } let(:issue) { create(:issue, project: project) }
let(:attachment) { subject[:attachments].first } let(:attachment) { subject[:attachments].first }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::ChatCommands::Presenters::IssueSearch do describe Gitlab::SlashCommands::Presenters::IssueSearch do
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
let(:message) { subject[:text] } let(:message) { subject[:text] }
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::ChatCommands::Presenters::IssueShow do describe Gitlab::SlashCommands::Presenters::IssueShow do
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) } let(:issue) { create(:issue, project: project) }
let(:attachment) { subject[:attachments].first } let(:attachment) { subject[:attachments].first }
......
...@@ -1397,7 +1397,7 @@ describe MergeRequest, models: true do ...@@ -1397,7 +1397,7 @@ describe MergeRequest, models: true do
end end
end end
describe '#mergeable_with_slash_command?' do describe '#mergeable_with_quick_action?' do
def create_pipeline(status) def create_pipeline(status)
pipeline = create(:ci_pipeline_with_one_job, pipeline = create(:ci_pipeline_with_one_job,
project: project, project: project,
...@@ -1421,21 +1421,21 @@ describe MergeRequest, models: true do ...@@ -1421,21 +1421,21 @@ describe MergeRequest, models: true do
context 'when autocomplete_precheck is set to true' do context 'when autocomplete_precheck is set to true' do
it 'is mergeable by developer' do it 'is mergeable by developer' do
expect(merge_request.mergeable_with_slash_command?(developer, autocomplete_precheck: true)).to be_truthy expect(merge_request.mergeable_with_quick_action?(developer, autocomplete_precheck: true)).to be_truthy
end end
it 'is not mergeable by normal user' do it 'is not mergeable by normal user' do
expect(merge_request.mergeable_with_slash_command?(user, autocomplete_precheck: true)).to be_falsey expect(merge_request.mergeable_with_quick_action?(user, autocomplete_precheck: true)).to be_falsey
end end
end end
context 'when autocomplete_precheck is set to false' do context 'when autocomplete_precheck is set to false' do
it 'is mergeable by developer' do it 'is mergeable by developer' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_truthy expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_truthy
end end
it 'is not mergeable by normal user' do it 'is not mergeable by normal user' do
expect(merge_request.mergeable_with_slash_command?(user, last_diff_sha: mr_sha)).to be_falsey expect(merge_request.mergeable_with_quick_action?(user, last_diff_sha: mr_sha)).to be_falsey
end end
context 'closed MR' do context 'closed MR' do
...@@ -1444,7 +1444,7 @@ describe MergeRequest, models: true do ...@@ -1444,7 +1444,7 @@ describe MergeRequest, models: true do
end end
it 'is not mergeable' do it 'is not mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_falsey expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_falsey
end end
end end
...@@ -1454,19 +1454,19 @@ describe MergeRequest, models: true do ...@@ -1454,19 +1454,19 @@ describe MergeRequest, models: true do
end end
it 'is not mergeable' do it 'is not mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_falsey expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_falsey
end end
end end
context 'sha differs from the MR diff_head_sha' do context 'sha differs from the MR diff_head_sha' do
it 'is not mergeable' do it 'is not mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: 'some other sha')).to be_falsey expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: 'some other sha')).to be_falsey
end end
end end
context 'sha is not provided' do context 'sha is not provided' do
it 'is not mergeable' do it 'is not mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer)).to be_falsey expect(merge_request.mergeable_with_quick_action?(developer)).to be_falsey
end end
end end
...@@ -1476,7 +1476,7 @@ describe MergeRequest, models: true do ...@@ -1476,7 +1476,7 @@ describe MergeRequest, models: true do
end end
it 'is mergeable' do it 'is mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_truthy expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_truthy
end end
end end
...@@ -1486,7 +1486,7 @@ describe MergeRequest, models: true do ...@@ -1486,7 +1486,7 @@ describe MergeRequest, models: true do
end end
it 'is not mergeable' do it 'is not mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_falsey expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_falsey
end end
end end
...@@ -1496,7 +1496,7 @@ describe MergeRequest, models: true do ...@@ -1496,7 +1496,7 @@ describe MergeRequest, models: true do
end end
it 'is mergeable' do it 'is mergeable' do
expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_truthy expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_truthy
end end
end end
end end
......
...@@ -206,9 +206,9 @@ describe Issues::CreateService, services: true do ...@@ -206,9 +206,9 @@ describe Issues::CreateService, services: true do
end end
end end
it_behaves_like 'new issuable record that supports slash commands' it_behaves_like 'new issuable record that supports quick actions'
context 'Slash commands' do context 'Quick actions' do
context 'with assignee and milestone in params and command' do context 'with assignee and milestone in params and command' do
let(:opts) do let(:opts) do
{ {
......
...@@ -108,7 +108,7 @@ describe MergeRequests::CreateService, services: true do ...@@ -108,7 +108,7 @@ describe MergeRequests::CreateService, services: true do
end end
end end
it_behaves_like 'new issuable record that supports slash commands' do it_behaves_like 'new issuable record that supports quick actions' do
let(:default_params) do let(:default_params) do
{ {
source_branch: 'feature', source_branch: 'feature',
...@@ -117,7 +117,7 @@ describe MergeRequests::CreateService, services: true do ...@@ -117,7 +117,7 @@ describe MergeRequests::CreateService, services: true do
end end
end end
context 'Slash commands' do context 'Quick actions' do
context 'with assignee and milestone in params and command' do context 'with assignee and milestone in params and command' do
let(:merge_request) { described_class.new(project, user, opts).execute } let(:merge_request) { described_class.new(project, user, opts).execute }
let(:milestone) { create(:milestone, project: project) } let(:milestone) { create(:milestone, project: project) }
......
require 'spec_helper' require 'spec_helper'
describe Notes::SlashCommandsService, services: true do describe Notes::QuickActionsService, services: true do
shared_context 'note on noteable' do shared_context 'note on noteable' do
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
let(:master) { create(:user).tap { |u| project.team << [u, :master] } } let(:master) { create(:user).tap { |u| project.team << [u, :master] } }
...@@ -11,7 +11,7 @@ describe Notes::SlashCommandsService, services: true do ...@@ -11,7 +11,7 @@ describe Notes::SlashCommandsService, services: true do
end end
end end
shared_examples 'note on noteable that does not support slash commands' do shared_examples 'note on noteable that does not support quick actions' do
include_context 'note on noteable' include_context 'note on noteable'
before do before do
...@@ -45,7 +45,7 @@ describe Notes::SlashCommandsService, services: true do ...@@ -45,7 +45,7 @@ describe Notes::SlashCommandsService, services: true do
end end
end end
shared_examples 'note on noteable that supports slash commands' do shared_examples 'note on noteable that supports quick actions' do
include_context 'note on noteable' include_context 'note on noteable'
before do before do
...@@ -210,15 +210,15 @@ describe Notes::SlashCommandsService, services: true do ...@@ -210,15 +210,15 @@ describe Notes::SlashCommandsService, services: true do
describe '#execute' do describe '#execute' do
let(:service) { described_class.new(project, master) } let(:service) { described_class.new(project, master) }
it_behaves_like 'note on noteable that supports slash commands' do it_behaves_like 'note on noteable that supports quick actions' do
let(:note) { build(:note_on_issue, project: project) } let(:note) { build(:note_on_issue, project: project) }
end end
it_behaves_like 'note on noteable that supports slash commands' do it_behaves_like 'note on noteable that supports quick actions' do
let(:note) { build(:note_on_merge_request, project: project) } let(:note) { build(:note_on_merge_request, project: project) }
end end
it_behaves_like 'note on noteable that does not support slash commands' do it_behaves_like 'note on noteable that does not support quick actions' do
let(:note) { build(:note_on_commit, project: project) } let(:note) { build(:note_on_commit, project: project) }
end end
end end
......
...@@ -19,24 +19,24 @@ describe PreviewMarkdownService do ...@@ -19,24 +19,24 @@ describe PreviewMarkdownService do
end end
end end
context 'new note with slash commands' do context 'new note with quick actions' do
let(:issue) { create(:issue, project: project) } let(:issue) { create(:issue, project: project) }
let(:params) do let(:params) do
{ {
text: "Please do it\n/assign #{user.to_reference}", text: "Please do it\n/assign #{user.to_reference}",
slash_commands_target_type: 'Issue', quick_actions_target_type: 'Issue',
slash_commands_target_id: issue.id quick_actions_target_id: issue.id
} }
end end
let(:service) { described_class.new(project, user, params) } let(:service) { described_class.new(project, user, params) }
it 'removes slash commands from text' do it 'removes quick actions from text' do
result = service.execute result = service.execute
expect(result[:text]).to eq 'Please do it' expect(result[:text]).to eq 'Please do it'
end end
it 'explains slash commands effect' do it 'explains quick actions effect' do
result = service.execute result = service.execute
expect(result[:commands]).to eq "Assigns #{user.to_reference}." expect(result[:commands]).to eq "Assigns #{user.to_reference}."
...@@ -47,21 +47,21 @@ describe PreviewMarkdownService do ...@@ -47,21 +47,21 @@ describe PreviewMarkdownService do
let(:params) do let(:params) do
{ {
text: "My work\n/estimate 2y", text: "My work\n/estimate 2y",
slash_commands_target_type: 'MergeRequest' quick_actions_target_type: 'MergeRequest'
} }
end end
let(:service) { described_class.new(project, user, params) } let(:service) { described_class.new(project, user, params) }
it 'removes slash commands from text' do it 'removes quick actions from text' do
result = service.execute result = service.execute
expect(result[:text]).to eq 'My work' expect(result[:text]).to eq 'My work'
end end
it 'explains slash commands effect' do it 'explains quick actions effect' do
result = service.execute result = service.execute
expect(result[:commands]).to eq 'Sets time estimate to 2y.' expect(result[:commands]).to eq 'Sets time estimate to 2y.'
end end
end end
end end
require 'spec_helper' require 'spec_helper'
describe SlashCommands::InterpretService, services: true do describe QuickActions::InterpretService, services: true do
let(:project) { create(:empty_project, :public) } let(:project) { create(:empty_project, :public) }
let(:developer) { create(:user) } let(:developer) { create(:user) }
let(:developer2) { create(:user) } let(:developer2) { create(:user) }
......
...@@ -87,7 +87,7 @@ RSpec.shared_examples 'chat slash commands service' do ...@@ -87,7 +87,7 @@ RSpec.shared_examples 'chat slash commands service' do
end end
it 'triggers the command' do it 'triggers the command' do
expect_any_instance_of(Gitlab::ChatCommands::Command).to receive(:execute) expect_any_instance_of(Gitlab::SlashCommands::Command).to receive(:execute)
subject.trigger(params) subject.trigger(params)
end end
......
# Specifications for behavior common to all objects with executable attributes. # Specifications for behavior common to all objects with executable attributes.
# It takes a `issuable_type`, and expect an `issuable`. # It takes a `issuable_type`, and expect an `issuable`.
shared_examples 'issuable record that supports slash commands in its description and notes' do |issuable_type| shared_examples 'issuable record that supports quick actions in its description and notes' do |issuable_type|
include SlashCommandsHelpers include QuickActionsHelpers
let(:master) { create(:user) } let(:master) { create(:user) }
let(:assignee) { create(:user, username: 'bob') } let(:assignee) { create(:user, username: 'bob') }
...@@ -260,7 +260,7 @@ shared_examples 'issuable record that supports slash commands in its description ...@@ -260,7 +260,7 @@ shared_examples 'issuable record that supports slash commands in its description
end end
describe "preview of note on #{issuable_type}" do describe "preview of note on #{issuable_type}" do
it 'removes slash commands from note and explains them' do it 'removes quick actions from note and explains them' do
visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable)
page.within('.js-main-target-form') do page.within('.js-main-target-form') do
......
module SlashCommandsHelpers module QuickActionsHelpers
def write_note(text) def write_note(text)
Sidekiq::Testing.fake! do Sidekiq::Testing.fake! do
page.within('.js-main-target-form') do page.within('.js-main-target-form') do
......
# Specifications for behavior common to all objects with executable attributes. # Specifications for behavior common to all objects with executable attributes.
# It can take a `default_params`. # It can take a `default_params`.
shared_examples 'new issuable record that supports slash commands' do shared_examples 'new issuable record that supports quick actions' do
let!(:project) { create(:project, :repository) } let!(:project) { create(:project, :repository) }
let(:user) { create(:user).tap { |u| project.team << [u, :master] } } let(:user) { create(:user).tap { |u| project.team << [u, :master] } }
let(:assignee) { create(:user) } let(:assignee) { create(:user) }
......
...@@ -54,7 +54,7 @@ shared_examples 'issuable time tracker' do ...@@ -54,7 +54,7 @@ shared_examples 'issuable time tracker' do
it 'shows the help state when icon is clicked' do it 'shows the help state when icon is clicked' do
page.within '.time-tracking-component-wrap' do page.within '.time-tracking-component-wrap' do
find('.help-button').click find('.help-button').click
expect(page).to have_content 'Track time with slash commands' expect(page).to have_content 'Track time with quick actions'
expect(page).to have_content 'Learn more' expect(page).to have_content 'Learn more'
end end
end end
...@@ -64,7 +64,7 @@ shared_examples 'issuable time tracker' do ...@@ -64,7 +64,7 @@ shared_examples 'issuable time tracker' do
find('.help-button').click find('.help-button').click
find('.close-help-button').click find('.close-help-button').click
expect(page).not_to have_content 'Track time with slash commands' expect(page).not_to have_content 'Track time with quick actions'
expect(page).not_to have_content 'Learn more' expect(page).not_to have_content 'Learn more'
end end
end end
...@@ -78,8 +78,8 @@ shared_examples 'issuable time tracker' do ...@@ -78,8 +78,8 @@ shared_examples 'issuable time tracker' do
end end
end end
def submit_time(slash_command) def submit_time(quick_action)
fill_in 'note[note]', with: slash_command fill_in 'note[note]', with: quick_action
find('.js-comment-submit-button').trigger('click') find('.js-comment-submit-button').trigger('click')
wait_for_requests wait_for_requests
end end
...@@ -20,8 +20,8 @@ describe 'shared/notes/_form' do ...@@ -20,8 +20,8 @@ describe 'shared/notes/_form' do
context "with a note on #{noteable}" do context "with a note on #{noteable}" do
let(:note) { build(:"note_on_#{noteable}", project: project) } let(:note) { build(:"note_on_#{noteable}", project: project) }
it 'says that markdown and slash commands are supported' do it 'says that markdown and quick actions are supported' do
expect(rendered).to have_content('Markdown and slash commands are supported') expect(rendered).to have_content('Markdown and quick actions are supported')
end end
end end
end end
...@@ -29,7 +29,7 @@ describe 'shared/notes/_form' do ...@@ -29,7 +29,7 @@ describe 'shared/notes/_form' do
context 'with a note on a commit' do context 'with a note on a commit' do
let(:note) { build(:note_on_commit, project: project) } let(:note) { build(:note_on_commit, project: project) }
it 'says that only markdown is supported, not slash commands' do it 'says that only markdown is supported, not quick actions' do
expect(rendered).to have_content('Markdown is supported') expect(rendered).to have_content('Markdown is supported')
end end
end end
......
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