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
13 changed files with 284 additions and 53 deletions
|
@ -87,9 +87,9 @@ class App.TicketOverview extends App.Controller
|
|||
|
||||
startDragItem: (event) =>
|
||||
return if !@batchSupport
|
||||
@grabbedItem = $(event.currentTarget)
|
||||
offset = @grabbedItem.offset()
|
||||
@batchDragger = $(App.view('ticket_overview/batch_dragger')())
|
||||
@grabbedItem = $(event.currentTarget)
|
||||
offset = @grabbedItem.offset()
|
||||
@batchDragger = $(App.view('ticket_overview/batch_dragger')())
|
||||
@grabbedItemClone = @grabbedItem.clone()
|
||||
@grabbedItemClone.data('offset', @grabbedItem.offset())
|
||||
@grabbedItemClone.addClass('batch-dragger-item js-main-item')
|
||||
|
@ -642,10 +642,35 @@ class App.TicketOverview extends App.Controller
|
|||
))
|
||||
|
||||
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')(
|
||||
macros: macros
|
||||
macros: @possibleMacros
|
||||
))
|
||||
|
||||
active: (state) =>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class App.TicketZoomAttributeBar extends App.Controller
|
||||
elements:
|
||||
'.js-submitDropdown': 'buttonDropdown'
|
||||
'.js-reset': 'resetButton'
|
||||
'.js-reset': 'resetButton'
|
||||
|
||||
events:
|
||||
'mousedown .js-openDropdownMacro': 'toggleMacroMenu'
|
||||
|
@ -11,6 +11,7 @@ class App.TicketZoomAttributeBar extends App.Controller
|
|||
'mouseleave .js-dropdownActionMacro': 'onActionMacroMouseLeave'
|
||||
'click .js-secondaryAction': 'chooseSecondaryAction'
|
||||
|
||||
searchCondition: {}
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
|
@ -24,6 +25,12 @@ class App.TicketZoomAttributeBar extends App.Controller
|
|||
@render()
|
||||
)
|
||||
|
||||
@bind('MacroPreconditionUpdate', (data) =>
|
||||
return if data.taskKey isnt @taskKey
|
||||
@searchCondition = data.params
|
||||
@render()
|
||||
)
|
||||
|
||||
release: =>
|
||||
App.Macro.unsubscribe(@subscribeId)
|
||||
|
||||
|
@ -34,16 +41,24 @@ class App.TicketZoomAttributeBar extends App.Controller
|
|||
if @resetButton.get(0) && !@resetButton.hasClass('hide')
|
||||
resetButtonShown = true
|
||||
|
||||
macros = App.Macro.findAllByAttribute('active', true)
|
||||
macros = App.Macro.search(filter: { active: true }, sortBy:'name', order:'DESC')
|
||||
|
||||
@macroLastUpdated = App.Macro.lastUpdatedAt()
|
||||
@possibleMacros = []
|
||||
|
||||
if _.isEmpty(macros) || !@permissionCheck('ticket.agent')
|
||||
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')(
|
||||
macros: macros
|
||||
macroDisabled: macroDisabled
|
||||
overview_id: @overview_id
|
||||
macros: @possibleMacros
|
||||
macroDisabled: macroDisabled
|
||||
overview_id: @overview_id
|
||||
resetButtonShown: resetButtonShown
|
||||
))
|
||||
@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
|
||||
@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
|
||||
@url: @apiPath + '/macros'
|
||||
@configure_attributes = [
|
||||
{
|
||||
name: 'name',
|
||||
display: 'Name',
|
||||
tag: 'input',
|
||||
type: 'text',
|
||||
limit: 100,
|
||||
null: false
|
||||
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
|
||||
{ name: 'perform', display: 'Actions', tag: 'ticket_perform_action', null: true
|
||||
},
|
||||
{
|
||||
name: 'perform',
|
||||
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: '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: 'note',
|
||||
display: 'Note',
|
||||
tag: 'textarea',
|
||||
limit: 250,
|
||||
null: true
|
||||
},
|
||||
{
|
||||
name: 'active',
|
||||
display: 'Active',
|
||||
tag: 'active',
|
||||
default: true
|
||||
},
|
||||
{ name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
|
||||
{ name: 'note', display: 'Note', tag: 'textarea', limit: 250, null: true },
|
||||
{ name: 'group_ids', display: 'Groups', tag: 'column_select', relation: 'Group', null: true },
|
||||
{ name: 'active', display: 'Active', tag: 'active', default: true },
|
||||
]
|
||||
@configure_delete = true
|
||||
@configure_clone = true
|
||||
@configure_overview = [
|
||||
'name',
|
||||
'note',
|
||||
'group_ids',
|
||||
]
|
||||
|
||||
@description = '''
|
||||
|
|
|
@ -8,4 +8,6 @@ class Macro < ApplicationModel
|
|||
store :perform
|
||||
validates :name, presence: true
|
||||
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
|
||||
|
|
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
|
||||
factory :macro do
|
||||
sequence(:name) { |n| "Macro #{n}" }
|
||||
perform { {} }
|
||||
perform { { 'ticket.state_id' => { 'value' => 1 } } }
|
||||
ux_flow_next_up { 'next_task' }
|
||||
note { '' }
|
||||
active { true }
|
||||
|
|
|
@ -27,6 +27,37 @@ module BrowserTestHelper
|
|||
Waiter.new(wait_handle)
|
||||
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
|
||||
|
||||
# This method is a derivation of Selenium::WebDriver::Wait#until
|
||||
|
|
|
@ -173,6 +173,16 @@ module CommonActions
|
|||
page.driver.browser.navigate.refresh
|
||||
attribute
|
||||
end
|
||||
|
||||
# opens the macro list in the ticket view via click
|
||||
#
|
||||
# @example
|
||||
# open_macro_list
|
||||
#
|
||||
def open_macro_list
|
||||
click '.js-openDropdownMacro'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
|
|
|
@ -23,3 +23,15 @@ end
|
|||
Capybara.add_selector(:text_module) do
|
||||
css { |id| %(.shortcut > ul > li[data-id="#{id}"]) }
|
||||
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 'system/examples/text_modules_examples'
|
||||
require 'system/examples/macros_examples'
|
||||
|
||||
RSpec.describe 'Ticket Update', type: :system do
|
||||
|
||||
|
@ -141,4 +142,8 @@ RSpec.describe 'Ticket Update', type: :system do
|
|||
context 'when using text modules' do
|
||||
include_examples 'text modules', path: "#ticket/zoom/#{Ticket.first.id}"
|
||||
end
|
||||
|
||||
context 'when using macros' do
|
||||
include_examples 'macros', path: "#ticket/zoom/#{Ticket.first.id}"
|
||||
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