Removed macro event for TicketCreateFormHandler. This is not needed, because there are no macros when creating tickets.
This commit is contained in:
parent
7e2f55d91f
commit
feac4bb938
|
@ -87,9 +87,9 @@ class App.TicketOverview extends App.Controller
|
||||||
|
|
||||||
startDragItem: (event) =>
|
startDragItem: (event) =>
|
||||||
return if !@batchSupport
|
return if !@batchSupport
|
||||||
@grabbedItem = $(event.currentTarget)
|
@grabbedItem = $(event.currentTarget)
|
||||||
offset = @grabbedItem.offset()
|
offset = @grabbedItem.offset()
|
||||||
@batchDragger = $(App.view('ticket_overview/batch_dragger')())
|
@batchDragger = $(App.view('ticket_overview/batch_dragger')())
|
||||||
@grabbedItemClone = @grabbedItem.clone()
|
@grabbedItemClone = @grabbedItem.clone()
|
||||||
@grabbedItemClone.data('offset', @grabbedItem.offset())
|
@grabbedItemClone.data('offset', @grabbedItem.offset())
|
||||||
@grabbedItemClone.addClass('batch-dragger-item js-main-item')
|
@grabbedItemClone.addClass('batch-dragger-item js-main-item')
|
||||||
|
@ -642,10 +642,35 @@ class App.TicketOverview extends App.Controller
|
||||||
))
|
))
|
||||||
|
|
||||||
renderOptionsMacros: =>
|
renderOptionsMacros: =>
|
||||||
macros = App.Macro.search(filter: { active: true }, sortBy:'name', order:'DESC')
|
|
||||||
|
@possibleMacros = []
|
||||||
|
macros = App.Macro.search(filter: { active: true }, sortBy:'name', order:'DESC')
|
||||||
|
|
||||||
|
items = @el.find('[name="bulk"]:checked')
|
||||||
|
|
||||||
|
group_ids =[]
|
||||||
|
for item in items
|
||||||
|
ticket = App.Ticket.find($(item).val())
|
||||||
|
group_ids.push ticket.group_id
|
||||||
|
|
||||||
|
group_ids = _.uniq(group_ids)
|
||||||
|
|
||||||
|
for macro in macros
|
||||||
|
|
||||||
|
# push if no group_ids exists
|
||||||
|
if _.isEmpty(macro.group_ids) && !_.includes(@possibleMacros, macro)
|
||||||
|
@possibleMacros.push macro
|
||||||
|
|
||||||
|
# push if group_ids are equal
|
||||||
|
if _.isEqual(macro.group_ids, group_ids) && !_.includes(@possibleMacros, macro)
|
||||||
|
@possibleMacros.push macro
|
||||||
|
|
||||||
|
# push if all group_ids of tickets are in macro.group_ids
|
||||||
|
if !_.isEmpty(macro.group_ids) && _.isEmpty(_.difference(group_ids,macro.group_ids)) && !_.includes(@possibleMacros, macro)
|
||||||
|
@possibleMacros.push macro
|
||||||
|
|
||||||
@batchMacro.html $(App.view('ticket_overview/batch_overlay_macro')(
|
@batchMacro.html $(App.view('ticket_overview/batch_overlay_macro')(
|
||||||
macros: macros
|
macros: @possibleMacros
|
||||||
))
|
))
|
||||||
|
|
||||||
active: (state) =>
|
active: (state) =>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
class App.TicketZoomAttributeBar extends App.Controller
|
class App.TicketZoomAttributeBar extends App.Controller
|
||||||
elements:
|
elements:
|
||||||
'.js-submitDropdown': 'buttonDropdown'
|
'.js-submitDropdown': 'buttonDropdown'
|
||||||
'.js-reset': 'resetButton'
|
'.js-reset': 'resetButton'
|
||||||
|
|
||||||
events:
|
events:
|
||||||
'mousedown .js-openDropdownMacro': 'toggleMacroMenu'
|
'mousedown .js-openDropdownMacro': 'toggleMacroMenu'
|
||||||
|
@ -11,6 +11,7 @@ class App.TicketZoomAttributeBar extends App.Controller
|
||||||
'mouseleave .js-dropdownActionMacro': 'onActionMacroMouseLeave'
|
'mouseleave .js-dropdownActionMacro': 'onActionMacroMouseLeave'
|
||||||
'click .js-secondaryAction': 'chooseSecondaryAction'
|
'click .js-secondaryAction': 'chooseSecondaryAction'
|
||||||
|
|
||||||
|
searchCondition: {}
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
|
|
||||||
|
@ -24,6 +25,12 @@ class App.TicketZoomAttributeBar extends App.Controller
|
||||||
@render()
|
@render()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@bind('MacroPreconditionUpdate', (data) =>
|
||||||
|
return if data.taskKey isnt @taskKey
|
||||||
|
@searchCondition = data.params
|
||||||
|
@render()
|
||||||
|
)
|
||||||
|
|
||||||
release: =>
|
release: =>
|
||||||
App.Macro.unsubscribe(@subscribeId)
|
App.Macro.unsubscribe(@subscribeId)
|
||||||
|
|
||||||
|
@ -34,16 +41,24 @@ class App.TicketZoomAttributeBar extends App.Controller
|
||||||
if @resetButton.get(0) && !@resetButton.hasClass('hide')
|
if @resetButton.get(0) && !@resetButton.hasClass('hide')
|
||||||
resetButtonShown = true
|
resetButtonShown = true
|
||||||
|
|
||||||
macros = App.Macro.findAllByAttribute('active', true)
|
macros = App.Macro.search(filter: { active: true }, sortBy:'name', order:'DESC')
|
||||||
|
|
||||||
@macroLastUpdated = App.Macro.lastUpdatedAt()
|
@macroLastUpdated = App.Macro.lastUpdatedAt()
|
||||||
|
@possibleMacros = []
|
||||||
|
|
||||||
if _.isEmpty(macros) || !@permissionCheck('ticket.agent')
|
if _.isEmpty(macros) || !@permissionCheck('ticket.agent')
|
||||||
macroDisabled = true
|
macroDisabled = true
|
||||||
|
else
|
||||||
|
for macro in macros
|
||||||
|
if !_.isEmpty(macro.group_ids) && @searchCondition.group_id && !_.includes(macro.group_ids, parseInt(@searchCondition.group_id))
|
||||||
|
continue
|
||||||
|
|
||||||
|
@possibleMacros.push macro
|
||||||
|
|
||||||
localeEl = $(App.view('ticket_zoom/attribute_bar')(
|
localeEl = $(App.view('ticket_zoom/attribute_bar')(
|
||||||
macros: macros
|
macros: @possibleMacros
|
||||||
macroDisabled: macroDisabled
|
macroDisabled: macroDisabled
|
||||||
overview_id: @overview_id
|
overview_id: @overview_id
|
||||||
resetButtonShown: resetButtonShown
|
resetButtonShown: resetButtonShown
|
||||||
))
|
))
|
||||||
@setSecondaryAction(@secondaryAction, localeEl)
|
@setSecondaryAction(@secondaryAction, localeEl)
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
class TicketZoomFormHandlerMacro
|
||||||
|
|
||||||
|
# central method, is getting called on every ticket form change
|
||||||
|
# but only trigger event for group_id changes
|
||||||
|
@run: (params, attribute, attributes, classname, form, ui) ->
|
||||||
|
|
||||||
|
return if attribute.name isnt 'group_id'
|
||||||
|
|
||||||
|
App.Event.trigger('MacroPreconditionUpdate', { taskKey: ui.taskKey, params: params })
|
||||||
|
|
||||||
|
App.Config.set('120-ticketFormMacro', TicketZoomFormHandlerMacro, 'TicketZoomFormHandler')
|
|
@ -1,57 +1,26 @@
|
||||||
class App.Macro extends App.Model
|
class App.Macro extends App.Model
|
||||||
@configure 'Macro', 'name', 'perform', 'ux_flow_next_up', 'note', 'active'
|
@configure 'Macro', 'name', 'perform', 'ux_flow_next_up', 'note', 'group_ids', 'active'
|
||||||
@extend Spine.Model.Ajax
|
@extend Spine.Model.Ajax
|
||||||
@url: @apiPath + '/macros'
|
@url: @apiPath + '/macros'
|
||||||
@configure_attributes = [
|
@configure_attributes = [
|
||||||
{
|
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
|
||||||
name: 'name',
|
{ name: 'perform', display: 'Actions', tag: 'ticket_perform_action', null: true
|
||||||
display: 'Name',
|
|
||||||
tag: 'input',
|
|
||||||
type: 'text',
|
|
||||||
limit: 100,
|
|
||||||
null: false
|
|
||||||
},
|
},
|
||||||
{
|
{ name: 'ux_flow_next_up', display: 'Once completed...', tag: 'select', default: 'none', options: {
|
||||||
name: 'perform',
|
none: 'Stay on tab', next_task: 'Close tab', next_from_overview: 'Advance to next ticket from overview'
|
||||||
display: 'Actions',
|
|
||||||
tag: 'ticket_perform_action',
|
|
||||||
null: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'ux_flow_next_up',
|
|
||||||
display: 'Once completed...',
|
|
||||||
tag: 'select',
|
|
||||||
default: 'none',
|
|
||||||
options: {
|
|
||||||
none: 'Stay on tab',
|
|
||||||
next_task: 'Close tab',
|
|
||||||
next_from_overview: 'Advance to next ticket from overview'
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{ name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
|
||||||
name: 'updated_at',
|
{ name: 'note', display: 'Note', tag: 'textarea', limit: 250, null: true },
|
||||||
display: 'Updated',
|
{ name: 'group_ids', display: 'Groups', tag: 'column_select', relation: 'Group', null: true },
|
||||||
tag: 'datetime',
|
{ name: 'active', display: 'Active', tag: 'active', default: true },
|
||||||
readonly: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'note',
|
|
||||||
display: 'Note',
|
|
||||||
tag: 'textarea',
|
|
||||||
limit: 250,
|
|
||||||
null: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'active',
|
|
||||||
display: 'Active',
|
|
||||||
tag: 'active',
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
@configure_delete = true
|
@configure_delete = true
|
||||||
@configure_clone = true
|
@configure_clone = true
|
||||||
@configure_overview = [
|
@configure_overview = [
|
||||||
'name',
|
'name',
|
||||||
|
'note',
|
||||||
|
'group_ids',
|
||||||
]
|
]
|
||||||
|
|
||||||
@description = '''
|
@description = '''
|
||||||
|
|
|
@ -8,4 +8,6 @@ class Macro < ApplicationModel
|
||||||
store :perform
|
store :perform
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
validates :ux_flow_next_up, inclusion: { in: %w[none next_task next_from_overview] }
|
validates :ux_flow_next_up, inclusion: { in: %w[none next_task next_from_overview] }
|
||||||
|
|
||||||
|
has_and_belongs_to_many :groups, after_add: :cache_update, after_remove: :cache_update, class_name: 'Group'
|
||||||
end
|
end
|
||||||
|
|
18
db/migrate/20190713000001_group_dependent_macros.rb
Normal file
18
db/migrate/20190713000001_group_dependent_macros.rb
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
class GroupDependentMacros < ActiveRecord::Migration[4.2]
|
||||||
|
def up
|
||||||
|
|
||||||
|
create_table :groups_macros, id: false do |t| # rubocop:disable Rails/CreateTableWithTimestamps
|
||||||
|
t.references :macro, null: false
|
||||||
|
t.references :group, null: false
|
||||||
|
end
|
||||||
|
add_index :groups_macros, [:macro_id]
|
||||||
|
add_index :groups_macros, [:group_id]
|
||||||
|
add_foreign_key :groups_macros, :macros
|
||||||
|
add_foreign_key :groups_macros, :groups
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
drop_table :groups_macros
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,7 +1,7 @@
|
||||||
FactoryBot.define do
|
FactoryBot.define do
|
||||||
factory :macro do
|
factory :macro do
|
||||||
sequence(:name) { |n| "Macro #{n}" }
|
sequence(:name) { |n| "Macro #{n}" }
|
||||||
perform { {} }
|
perform { { 'ticket.state_id' => { 'value' => 1 } } }
|
||||||
ux_flow_next_up { 'next_task' }
|
ux_flow_next_up { 'next_task' }
|
||||||
note { '' }
|
note { '' }
|
||||||
active { true }
|
active { true }
|
||||||
|
|
|
@ -27,6 +27,37 @@ module BrowserTestHelper
|
||||||
Waiter.new(wait_handle)
|
Waiter.new(wait_handle)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Moves the mouse from its current position by the given offset.
|
||||||
|
# If the coordinates provided are outside the viewport (the mouse will end up outside the browser window)
|
||||||
|
# then the viewport is scrolled to match.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# move_mouse_by(x, y)
|
||||||
|
# move_mouse_by(100, 200)
|
||||||
|
#
|
||||||
|
def move_mouse_by(x_axis, y_axis)
|
||||||
|
page.driver.browser.action.move_by(x_axis, y_axis).perform
|
||||||
|
end
|
||||||
|
|
||||||
|
# Clicks and hold (without releasing) in the middle of the given element.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# click_and_hold(ticket)
|
||||||
|
# click_and_hold(tr[data-id='1'])
|
||||||
|
#
|
||||||
|
def click_and_hold(element)
|
||||||
|
page.driver.browser.action.click_and_hold(element).perform
|
||||||
|
end
|
||||||
|
|
||||||
|
# Releases the depressed left mouse button at the current mouse location.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# release_mouse
|
||||||
|
#
|
||||||
|
def release_mouse
|
||||||
|
page.driver.browser.action.release.perform
|
||||||
|
end
|
||||||
|
|
||||||
class Waiter < SimpleDelegator
|
class Waiter < SimpleDelegator
|
||||||
|
|
||||||
# This method is a derivation of Selenium::WebDriver::Wait#until
|
# This method is a derivation of Selenium::WebDriver::Wait#until
|
||||||
|
|
|
@ -173,6 +173,16 @@ module CommonActions
|
||||||
page.driver.browser.navigate.refresh
|
page.driver.browser.navigate.refresh
|
||||||
attribute
|
attribute
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# opens the macro list in the ticket view via click
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# open_macro_list
|
||||||
|
#
|
||||||
|
def open_macro_list
|
||||||
|
click '.js-openDropdownMacro'
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
|
|
|
@ -23,3 +23,15 @@ end
|
||||||
Capybara.add_selector(:text_module) do
|
Capybara.add_selector(:text_module) do
|
||||||
css { |id| %(.shortcut > ul > li[data-id="#{id}"]) }
|
css { |id| %(.shortcut > ul > li[data-id="#{id}"]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Capybara.add_selector(:macro) do
|
||||||
|
css { |id| %(.js-submitDropdown > ul > li[data-id="#{id}"]) }
|
||||||
|
end
|
||||||
|
|
||||||
|
Capybara.add_selector(:macro_batch) do
|
||||||
|
css { |id| %(.batch-overlay-macro-entry[data-id='#{id}']) }
|
||||||
|
end
|
||||||
|
|
||||||
|
Capybara.add_selector(:table_row) do
|
||||||
|
css { |id| %(tr[data-id='#{id}']) }
|
||||||
|
end
|
||||||
|
|
45
spec/system/examples/macros_examples.rb
Normal file
45
spec/system/examples/macros_examples.rb
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
RSpec.shared_examples 'macros' do |path:|
|
||||||
|
|
||||||
|
let!(:group1) { create :group }
|
||||||
|
let!(:group2) { create :group }
|
||||||
|
let!(:macro_without_group) { create :macro }
|
||||||
|
let!(:macro_group1) { create :macro, groups: [group1] }
|
||||||
|
let!(:macro_group2) { create :macro, groups: [group2] }
|
||||||
|
|
||||||
|
it 'supports group-dependent macros' do
|
||||||
|
|
||||||
|
# give user access to all groups including those created
|
||||||
|
# by using FactoryBot outside of the example
|
||||||
|
group_names_access_map = Group.all.pluck(:name).each_with_object({}) do |group_name, result|
|
||||||
|
result[group_name] = 'full'.freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
current_user do |user|
|
||||||
|
user.group_names_access_map = group_names_access_map
|
||||||
|
user.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
# refresh browser to get macro accessable
|
||||||
|
refresh
|
||||||
|
visit path
|
||||||
|
|
||||||
|
within(:active_content) do
|
||||||
|
|
||||||
|
# select group
|
||||||
|
find('select[name="group_id"]').select(group1.name)
|
||||||
|
|
||||||
|
open_macro_list
|
||||||
|
expect(page).to have_selector(:macro, macro_without_group.id)
|
||||||
|
expect(page).to have_selector(:macro, macro_group1.id)
|
||||||
|
expect(page).to have_no_selector(:macro, macro_group2.id)
|
||||||
|
|
||||||
|
# select group
|
||||||
|
find('select[name="group_id"]').select(group2.name)
|
||||||
|
|
||||||
|
open_macro_list
|
||||||
|
expect(page).to have_selector(:macro, macro_without_group.id)
|
||||||
|
expect(page).to have_no_selector(:macro, macro_group1.id)
|
||||||
|
expect(page).to have_selector(:macro, macro_group2.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,7 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
require 'system/examples/text_modules_examples'
|
require 'system/examples/text_modules_examples'
|
||||||
|
require 'system/examples/macros_examples'
|
||||||
|
|
||||||
RSpec.describe 'Ticket Update', type: :system do
|
RSpec.describe 'Ticket Update', type: :system do
|
||||||
|
|
||||||
|
@ -141,4 +142,8 @@ RSpec.describe 'Ticket Update', type: :system do
|
||||||
context 'when using text modules' do
|
context 'when using text modules' do
|
||||||
include_examples 'text modules', path: "#ticket/zoom/#{Ticket.first.id}"
|
include_examples 'text modules', path: "#ticket/zoom/#{Ticket.first.id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when using macros' do
|
||||||
|
include_examples 'macros', path: "#ticket/zoom/#{Ticket.first.id}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
88
spec/system/ticket/view_spec.rb
Normal file
88
spec/system/ticket/view_spec.rb
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Ticket views', type: :system do
|
||||||
|
|
||||||
|
let!(:group1) { create :group }
|
||||||
|
let!(:group2) { create :group }
|
||||||
|
let!(:macro_without_group) { create :macro }
|
||||||
|
let!(:macro_group1) { create :macro, groups: [group1] }
|
||||||
|
let!(:macro_group2) { create :macro, groups: [group2] }
|
||||||
|
|
||||||
|
it 'supports group-dependent macros' do
|
||||||
|
|
||||||
|
ticket1 = create :ticket, group: group1
|
||||||
|
ticket2 = create :ticket, group: group2
|
||||||
|
|
||||||
|
# give user access to all groups including those created
|
||||||
|
# by using FactoryBot outside of the example
|
||||||
|
group_names_access_map = Group.all.pluck(:name).each_with_object({}) do |group_name, result|
|
||||||
|
result[group_name] = 'full'.freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
current_user do |user|
|
||||||
|
user.group_names_access_map = group_names_access_map
|
||||||
|
user.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
# refresh browser to get macro accessable
|
||||||
|
refresh
|
||||||
|
visit '#ticket/view/all_open'
|
||||||
|
|
||||||
|
within(:active_content) do
|
||||||
|
|
||||||
|
ticket = page.find(:table_row, 1).native
|
||||||
|
|
||||||
|
# click and hold first ticket in table
|
||||||
|
click_and_hold(ticket)
|
||||||
|
|
||||||
|
# move ticket to y -ticket.location.y
|
||||||
|
move_mouse_by(0, -ticket.location.y + 5)
|
||||||
|
|
||||||
|
# move a bit to the left to display macro batches
|
||||||
|
move_mouse_by(-250, 0)
|
||||||
|
|
||||||
|
expect(page).to have_selector(:macro_batch, macro_without_group.id, visible: true)
|
||||||
|
expect(page).to have_no_selector(:macro_batch, macro_group1.id)
|
||||||
|
expect(page).to have_no_selector(:macro_batch, macro_group2.id)
|
||||||
|
|
||||||
|
release_mouse
|
||||||
|
|
||||||
|
refresh
|
||||||
|
|
||||||
|
ticket = page.find(:table_row, ticket1.id).native
|
||||||
|
|
||||||
|
# click and hold first ticket in table
|
||||||
|
click_and_hold(ticket)
|
||||||
|
|
||||||
|
# move ticket to y -ticket.location.y
|
||||||
|
move_mouse_by(0, -ticket.location.y + 5)
|
||||||
|
|
||||||
|
# move a bit to the left to display macro batches
|
||||||
|
move_mouse_by(-250, 0)
|
||||||
|
|
||||||
|
expect(page).to have_selector(:macro_batch, macro_without_group.id, visible: true)
|
||||||
|
expect(page).to have_selector(:macro_batch, macro_group1.id)
|
||||||
|
expect(page).to have_no_selector(:macro_batch, macro_group2.id)
|
||||||
|
|
||||||
|
release_mouse
|
||||||
|
|
||||||
|
refresh
|
||||||
|
|
||||||
|
ticket = page.find(:table_row, ticket2.id).native
|
||||||
|
|
||||||
|
# click and hold first ticket in table
|
||||||
|
click_and_hold(ticket)
|
||||||
|
|
||||||
|
# move ticket to y -ticket.location.y
|
||||||
|
move_mouse_by(0, -ticket.location.y + 5)
|
||||||
|
|
||||||
|
# move a bit to the left to display macro batches
|
||||||
|
move_mouse_by(-250, 0)
|
||||||
|
|
||||||
|
expect(page).to have_selector(:macro_batch, macro_without_group.id, visible: true)
|
||||||
|
expect(page).to have_no_selector(:macro_batch, macro_group1.id)
|
||||||
|
expect(page).to have_selector(:macro_batch, macro_group2.id)
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue