Implement ux_flow_next_up feature for macros (soft fix for #641)

This commit is contained in:
Ryan Lue 2018-06-11 15:28:03 +08:00
parent 82acddc420
commit 14fb64ba0a
8 changed files with 207 additions and 35 deletions

View file

@ -138,6 +138,12 @@ class App.Controller extends Spine.Controller
App.Event.trigger('menu:render')
@delay(delay, 150)
closeTab: (key = @taskKey, dest) =>
return if !key?
App.TaskManager.remove(key)
dest ?= App.TaskManager.nextTaskUrl() || '#'
@navigate dest
scrollTo: (x = 0, y = 0, delay = 0) ->
a = ->
window.scrollTo(x, y)

View file

@ -421,7 +421,7 @@ class App.TicketZoom extends App.Controller
object_id: @ticket_id
overview_id: @overview_id
el: elLocal.find('.js-ticketTitleContainer')
taskKey: @taskKey
taskKey: @taskKey
)
new App.TicketZoomMeta(
@ -434,7 +434,7 @@ class App.TicketZoom extends App.Controller
el: elLocal.find('.js-attributeBar')
overview_id: @overview_id
callback: @submit
taskKey: @taskKey
taskKey: @taskKey
)
#if @shown
# @attributeBar.start()
@ -448,7 +448,7 @@ class App.TicketZoom extends App.Controller
formMeta: @formMeta
form_id: @form_id
defaults: @taskGet('article')
taskKey: @taskKey
taskKey: @taskKey
ui: @
)

View file

@ -4,7 +4,7 @@ class App.TicketZoomAttributeBar extends App.Controller
'.js-reset': 'resetButton'
events:
'mousedown .js-openDropdownMacro': 'toggleDropdownMacro'
'mousedown .js-openDropdownMacro': 'toggleMacroMenu'
'click .js-openDropdownMacro': 'stopPropagation'
'mouseup .js-dropdownActionMacro': 'performTicketMacro'
'mouseenter .js-dropdownActionMacro': 'onActionMacroMouseEnter'
@ -69,24 +69,54 @@ class App.TicketZoomAttributeBar extends App.Controller
return if macroLastUpdated is @macroLastUpdated
@render()
toggleDropdownMacro: =>
if @buttonDropdown.hasClass 'is-open'
@closeMacroDropdown()
else
@buttonDropdown.addClass 'is-open'
$(document).bind 'click.buttonDropdown', @closeMacroDropdown
toggleMacroMenu: =>
if @buttonDropdown.hasClass('is-open') then @closeMacroMenu() else @openMacroMenu()
closeMacroDropdown: =>
openMacroMenu: =>
@buttonDropdown.addClass 'is-open'
$(document).bind 'click.buttonDropdown', @closeMacroMenu
closeMacroMenu: =>
@buttonDropdown.removeClass 'is-open'
$(document).unbind 'click.buttonDropdown'
performTicketMacro: (e) =>
macroId = $(e.currentTarget).data('id')
console.log 'perform action', @$(e.currentTarget).text(), macroId
macro = App.Macro.find(macroId)
@callback(e, macro.perform)
@closeMacroDropdown()
@closeMacroMenu()
@replaceTabWith(macro.ux_flow_next_up)
replaceTabWith: (dest) =>
switch dest
when 'none'
return
when 'next_task'
@closeTab()
when 'next_from_overview'
@closeTab()
@openNextTicketInOverview()
openNextTicketInOverview: (overview = @overview_id, ticket = @ticket.id) =>
# coerce ids to objects
overview = App.Overview.find(overview) if !(overview instanceof App.Overview)
ticket = App.Ticket.find(ticket) if !(ticket instanceof App.Ticket)
return if !overview? || !ticket?
nextTicket = overview.nextTicket(ticket.id)
return if !nextTicket?
# open task via task manager to preserve overview information
App.TaskManager.execute(
key: "Ticket-#{nextTicket.id}"
controller: 'TicketZoom'
params:
ticket_id: nextTicket.id
overview_id: overview.id
)
@navigate "ticket/zoom/#{nextTicket.id}"
onActionMacroMouseEnter: (e) =>
@$(e.currentTarget).addClass('is-active')

View file

@ -1,13 +1,52 @@
class App.Macro extends App.Model
@configure 'Macro', 'name', 'perform', 'note', 'active'
@configure 'Macro', 'name', 'perform', 'ux_flow_next_up', 'note', 'active'
@extend Spine.Model.Ajax
@url: @apiPath + '/macros'
@configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
{ name: 'perform', display: 'Execute changes on objects.', tag: 'ticket_perform_action', null: true },
{ 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: 'name',
display: 'Name',
tag: 'input',
type: 'text',
limit: 100,
null: false
},
{
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: '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
},
]
@configure_delete = true
@configure_clone = true
@ -18,4 +57,4 @@ class App.Macro extends App.Model
@description = '''
Macros are....
'''
'''

View file

@ -76,6 +76,14 @@ You can also create overvies and limit them to specific agents or to groups of a
uiUrl: ->
"#ticket/view/#{@link}"
nextTicket: (startTicket) =>
# coerce id to Ticket object
startTicket = App.Ticket.find(startTicket) if !(startTicket instanceof App.Ticket)
tickets = App.OverviewListCollection.get(@link).tickets
currentIndex = _.findIndex(tickets, (t) -> t.id == startTicket.id)
tickets[currentIndex + 1]
@groupByAttributes: ->
groupByAttributes = {}
for key, attribute of App.Ticket.attributesGet()

View file

@ -7,4 +7,5 @@ class Macro < ApplicationModel
store :perform
validates :name, presence: true
validates :ux_flow_next_up, inclusion: { in: %w[none next_task next_from_overview] }
end

View file

@ -0,0 +1,5 @@
class AddUxFlowNextUpToMacros < ActiveRecord::Migration[5.1]
def change
add_column :macros, :ux_flow_next_up, :string, default: 'none', null: false
end
end

View file

@ -2,33 +2,116 @@
require 'browser_test_helper'
class AgentTicketMacroTest < TestCase
def test_macro
# def test_macro
# @browser = browser_instance
# login(
# username: 'agent1@example.com',
# password: 'test',
# url: browser_url,
# )
# tasks_close_all()
# ticket1 = ticket_create(
# data: {
# customer: 'nico',
# group: 'Users',
# title: 'some subject - macro#1',
# body: 'some body - macro#1',
# },
# )
# click(css: '.active.content .js-submitDropdown .js-openDropdownMacro')
# click(css: '.active.content .js-submitDropdown .js-dropdownActionMacro')
# # verify tags
# tags_verify(
# tags: {
# 'spam' => true,
# 'tag1' => false,
# }
# )
# end
def test_macro_ux_flow_next_up
@browser = browser_instance
login(
username: 'agent1@example.com',
username: 'master@example.com',
password: 'test',
url: browser_url,
)
tasks_close_all()
ticket1 = ticket_create(
# Setup: Create two tickets
ticket_create(
data: {
customer: 'nico',
customer: 'nicole.braun',
group: 'Users',
title: 'some subject - macro#1',
body: 'some body - macro#1',
title: 'Sample Ticket 1',
body: 'Lorem ipsum dolor sit amet consectetur adipisicing elit.',
},
)
click(css: '.active.content .js-submitDropdown .js-openDropdownMacro')
click(css: '.active.content .js-submitDropdown .js-dropdownActionMacro')
# verify tags
tags_verify(
tags: {
'spam' => true,
'tag1' => false,
}
ticket_create(
data: {
customer: 'nicole.braun',
group: 'Users',
title: 'Sample Ticket 2',
body: 'Suspendisse volutpat lectus sem, in fermentum orci semper sit amet.',
},
)
# Setup: Create three macros (one for each ux_flow_next_up option)
click(css: 'a[href="#manage"]')
click(css: '.sidebar a[href="#manage/macros"]')
macro_options = ['Stay on tab', 'Close tab', 'Advance to next ticket from overview']
macro_options.each.with_index do |o, i|
click(css: '.page-header-meta > a[data-type="new"]')
sendkey(css: '.modal-body input[name="name"]', value: "Test Macro #{i + 1}")
select(css: '.modal-body select[name="ux_flow_next_up"]', value: o)
click(css: '.modal-footer button[type="submit"]')
end
click(css: 'a[title$="Sample Ticket 1"]')
# Assert: Run the first macro and verify the tab is still open
click(css: '.active.content .js-submitDropdown .js-openDropdownMacro')
click(css: '.active.content .js-submitDropdown .js-dropdownActionMacro[data-id="2"]')
match(css: '.tasks > a.is-active > .nav-tab-name', value: 'Sample Ticket 1',)
# Setup: Close all tabs and reopen only the first ticket
tasks_close_all()
click(css: 'a[href="#ticket/view"]')
begin
remaining_retries = 1
click(css: 'a[href="#ticket/view/all_unassigned"]')
# responsive design means some elements are un-clickable at certain viewport sizes
rescue Selenium::WebDriver::Error::WebDriverError => e
raise e if remaining_retries.zero?
(remaining_retries -= 1) && click(css: 'a.tab.js-tab[href="#ticket/view/all_unassigned"]')
end
click(css: 'td[title="Sample Ticket 1"]')
# Assert: Run the second macro and verify the tab is closed
click(css: '.active.content .js-submitDropdown .js-openDropdownMacro')
click(css: '.active.content .js-submitDropdown .js-dropdownActionMacro[data-id="3"]')
exists_not(css: '.tasks > a')
# Setup: Reopen the first ticket via a Ticket Overview
click(css: 'a[href="#ticket/view"]')
begin
remaining_retries = 1
click(css: 'a[href="#ticket/view/all_unassigned"]')
# responsive design means some elements are un-clickable at certain viewport sizes
rescue Selenium::WebDriver::Error::WebDriverError => e
raise e if remaining_retries.zero?
(remaining_retries -= 1) && click(css: 'a.tab.js-tab[href="#ticket/view/all_unassigned"]')
end
click(css: 'td[title="Sample Ticket 1"]')
# Assert: Run the third macro and verify the second ticket opens
click(css: '.active.content .js-submitDropdown .js-openDropdownMacro')
click(css: '.active.content .js-submitDropdown .js-dropdownActionMacro[data-id="4"]')
match_not(css: '.tasks > a.task > .nav-tab-name', value: 'Sample Ticket 1',)
match(css: '.tasks > a.is-active > .nav-tab-name', value: 'Sample Ticket 2',)
end
end