Merge branch 'develop' of github.com:martini/zammad into develop

This commit is contained in:
Felix Niklas 2016-03-22 16:07:15 +01:00
commit f0ebc5ac54
17 changed files with 100 additions and 55 deletions

View file

@ -469,7 +469,9 @@ class App.Controller extends Spine.Controller
@userTicketPopupsList.popover('destroy') @userTicketPopupsList.popover('destroy')
anyPopoversDestroy: -> anyPopoversDestroy: ->
$('.popover').remove()
# do not remove permanent .popover--notifications widget
$('.popover:not(.popover--notifications)').remove()
recentView: (object, o_id) => recentView: (object, o_id) =>
params = params =

View file

@ -49,6 +49,11 @@ class App.Navigation extends App.ControllerWidgetPermanent
else else
@$('.bell').removeClass('show') @$('.bell').removeClass('show')
release: =>
if @notificationWidget
@notificationWidget.remove()
@notificationWidget = undefined
renderMenu: => renderMenu: =>
items = @getItems( navbar: @Config.get( 'NavBar' ) ) items = @getItems( navbar: @Config.get( 'NavBar' ) )
@ -205,6 +210,8 @@ class App.Navigation extends App.ControllerWidgetPermanent
@emptyAndClose() @emptyAndClose()
) )
if @notificationWidget
@notificationWidget.remove()
@notificationWidget = new App.OnlineNotificationWidget() @notificationWidget = new App.OnlineNotificationWidget()
$('#app').append @notificationWidget.el $('#app').append @notificationWidget.el

View file

@ -83,7 +83,7 @@ App.Config.set(
$('#global-search').focus() $('#global-search').focus()
} }
{ {
key: 'y' key: 'a'
hotkeys: true hotkeys: true
description: 'Notifications' description: 'Notifications'
callback: (e) -> callback: (e) ->

View file

@ -44,10 +44,12 @@ class App.OnlineNotificationWidget extends App.Controller
@bind 'auth', (user) => @bind 'auth', (user) =>
if !user if !user
@counterUpdate(0) @counterUpdate(0)
else return
if !@access() if !@access()
@counterUpdate(0) @counterUpdate(0)
return return
if !@subscribeId
@subscribeId = App.OnlineNotification.subscribe(@updateContent)
if @access() if @access()
@subscribeId = App.OnlineNotification.subscribe(@updateContent) @subscribeId = App.OnlineNotification.subscribe(@updateContent)
@ -69,9 +71,7 @@ class App.OnlineNotificationWidget extends App.Controller
access: -> access: ->
return false if !@Session.get() return false if !@Session.get()
return true if @isRole('Agent') return true
return true if @isRole('Admin')
return false
listNavigate: (e) => listNavigate: (e) =>
if e.keyCode is 27 # close on esc if e.keyCode is 27 # close on esc
@ -140,7 +140,9 @@ class App.OnlineNotificationWidget extends App.Controller
heightPopoverSpacer = 22 heightPopoverSpacer = 22
heightPopoverHeader = @header.outerHeight(true) heightPopoverHeader = @header.outerHeight(true)
isOverflowing = false isOverflowing = false
heightPopoverContent = 0
@item.each (i, el) => @item.each (i, el) =>
# accumulate height of items # accumulate height of items
heightPopoverContent += el.clientHeight heightPopoverContent += el.clientHeight
@ -206,6 +208,7 @@ class App.OnlineNotificationWidget extends App.Controller
@show() @show()
show: => show: =>
return if !@access()
$(window).on 'keydown.notifications', @listNavigate $(window).on 'keydown.notifications', @listNavigate
@shown = true @shown = true
@el.show() @el.show()
@ -230,3 +233,6 @@ class App.OnlineNotificationWidget extends App.Controller
id = row.data('id') id = row.data('id')
App.OnlineNotification.destroy(id) App.OnlineNotification.destroy(id)
@updateHeight() @updateHeight()
remove: =>
@el.remove()

View file

@ -15,6 +15,11 @@ class App.Track
_instance ?= new _trackSingleton _instance ?= new _trackSingleton
_instance.send() _instance.send()
@force: (value) ->
if _instance == undefined
_instance ?= new _trackSingleton
_instance.force(value)
@_all: -> @_all: ->
if _instance == undefined if _instance == undefined
_instance ?= new _trackSingleton _instance ?= new _trackSingleton
@ -28,6 +33,8 @@ class _trackSingleton
# @url = 'http://localhost:3005/api/v1/ui' # @url = 'http://localhost:3005/api/v1/ui'
@url = 'https://log.zammad.com/api/v1/ui' @url = 'https://log.zammad.com/api/v1/ui'
@forceSending = false
@log('start', 'notice', {}) @log('start', 'notice', {})
# start initial submit 30 sec. later to avoid ie10 cookie issues # start initial submit 30 sec. later to avoid ie10 cookie issues
@ -104,11 +111,10 @@ class _trackSingleton
return return
) )
log: (facility, level, args) -> log: (facility, level, args) =>
return if App.Config.get('developer_mode') return if !@shouldSend()
return if !App.Config.get('ui_send_client_stats')
info = info =
time: Math.round( new Date().getTime() / 1000 ) time: Math.round(new Date().getTime() / 1000)
facility: facility facility: facility
level: level level: level
location: window.location.pathname + window.location.hash location: window.location.pathname + window.location.hash
@ -116,8 +122,7 @@ class _trackSingleton
@data.push info @data.push info
send: (async = true) => send: (async = true) =>
return if App.Config.get('developer_mode') return if !@shouldSend()
return if !App.Config.get('ui_send_client_stats')
return if _.isEmpty @data return if _.isEmpty @data
newData = _.clone(@data) newData = _.clone(@data)
@data = [] @data = []
@ -155,6 +160,15 @@ class _trackSingleton
@data.push item @data.push item
) )
force: (value = true) ->
@forceSending = value
shouldSend: ->
return true if @forceSending
return false if App.Config.get('developer_mode')
return false if !App.Config.get('ui_send_client_stats')
true
_all: -> _all: ->
@data @data

View file

@ -2,7 +2,7 @@ Your <%= c 'product_name' %> password has been changed
<p>Hi <%= d 'user.firstname' %>,</p> <p>Hi <%= d 'user.firstname' %>,</p>
<br> <br>
<p>the password for your <%= c 'product_name' %> account <b><%= d 'user.login' %></b> has been changed recently.</p> <p>The password for your <%= c 'product_name' %> account <b><%= d 'user.login' %></b> has been changed recently.</p>
<br> <br>
<p>This activity is not known to you? If not, contact your system administrator.</p> <p>This activity is not known to you? If not, contact your system administrator.</p>
<br> <br>

View file

@ -10,6 +10,6 @@ Reset your <%= c 'product_name' %> password
<br> <br>
<p>This link takes you to a page where you can change your password.</p> <p>This link takes you to a page where you can change your password.</p>
<br> <br>
<p>If you don't want to reset your password, please ignore this message. Your password will not be reset.</p> <p>If you don't want to reset your password, please ignore this message. Your password will not be reseted.</p>
<br> <br>
<p>Your <%= c 'product_name' %> Team</p> <p>Your <%= c 'product_name' %> Team</p>

View file

@ -2,7 +2,7 @@ Confirm your <%= c 'product_name' %> account, <%= d 'user.firstname' %> <%= d 'u
<p>Hi <%= d 'user.firstname' %>,</p> <p>Hi <%= d 'user.firstname' %>,</p>
<br> <br>
<p>confirm your email address to complete your <%= c 'product_name' %> account. It's easy, just click the link below.</p> <p>Confirm your email address to complete your <%= c 'product_name' %> account. It's easy, just click the link below.</p>
<br> <br>
<p><a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#email_verify/<%= d 'token.name' %>"><%= c 'http_type' %>://<%= c 'fqdn' %>/#email_verify/<%= d 'token.name' %></a></p> <p><a href="<%= c 'http_type' %>://<%= c 'fqdn' %>/#email_verify/<%= d 'token.name' %>"><%= c 'http_type' %>://<%= c 'fqdn' %>/#email_verify/<%= d 'token.name' %></a></p>
<br> <br>

View file

@ -2,7 +2,7 @@ Test Ticket!
<p>Dear <%= d 'agent.firstname' %>,</p> <p>Dear <%= d 'agent.firstname' %>,</p>
<br> <br>
<p>this is a <b>Test Ticket</b>. I'm a customer and I need some help! :)</p> <p>This is a <b>test ticket</b>. I'm a customer and I need some help! :)</p>
<br> <br>
<p><%= d 'customer.fullname' %></p> <p><%= d 'customer.fullname' %></p>
<br> <br>

View file

@ -2,7 +2,7 @@ New Ticket (<%= d 'ticket.title' %>)
<p>Hi <%= d 'recipient.firstname' %>,</p> <p>Hi <%= d 'recipient.firstname' %>,</p>
<br> <br>
<p>a new Ticket (<%= d 'ticket.title' %>) has been created by "<b><%= d 'ticket.updated_by.longname' %></b>".</p> <p>A new ticket (<%= d 'ticket.title' %>) has been created by "<b><%= d 'ticket.updated_by.longname' %></b>".</p>
<br> <br>
<p> <p>
<%= t 'Group' %>: <%= d 'ticket.group.name' %><br> <%= t 'Group' %>: <%= d 'ticket.group.name' %><br>

View file

@ -2,7 +2,7 @@ Ticket is escalated (<%= d 'ticket.title' %>)
<p>Hi <%= d 'recipient.firstname' %>,</p> <p>Hi <%= d 'recipient.firstname' %>,</p>
<br> <br>
<p>Ticket (<%= d 'ticket.title' %>) from "<b><%= d 'ticket.customer.longname' %></b>" is escalated since "<%= d 'ticket.escalation_time' %>"!</p> <p>A ticket (<%= d 'ticket.title' %>) from "<b><%= d 'ticket.customer.longname' %></b>" is escalated since "<%= d 'ticket.escalation_time' %>"!</p>
<br> <br>
<% if @objects[:article] %> <% if @objects[:article] %>
<p> <p>

View file

@ -2,7 +2,7 @@ Ticket will escalated (<%= d 'ticket.title' %>)
<p>Hi <%= d 'recipient.firstname' %>,</p> <p>Hi <%= d 'recipient.firstname' %>,</p>
<br> <br>
<p>Ticket (<%= d 'ticket.title' %>) from "<b><%= d 'ticket.customer.longname' %></b>" will escalated at "<%= d 'ticket.escalation_time' %>"!</p> <p>a ticket (<%= d 'ticket.title' %>) from "<b><%= d 'ticket.customer.longname' %></b>" will escalate at "<%= d 'ticket.escalation_time' %>"!</p>
<br> <br>
<% if @objects[:article] %> <% if @objects[:article] %>
<p> <p>

View file

@ -2,7 +2,7 @@ Reminder reached (<%= d 'ticket.title' %>)
<p>Hi <%= d 'recipient.firstname' %>,</p> <p>Hi <%= d 'recipient.firstname' %>,</p>
<br> <br>
<p>ticket needs attachen, reminder reached for Ticket (<%= d 'ticket.title' %>) with customer "<b><%= d 'ticket.customer.longname' %></b>".</p> <p>Ticket needs attention, reminder reached for ticket (<%= d 'ticket.title' %>) with customer "<b><%= d 'ticket.customer.longname' %></b>".</p>
<br> <br>
<% if @objects[:article] %> <% if @objects[:article] %>
<p> <p>

View file

@ -2,10 +2,10 @@
<p>Hi <%= d 'user.firstname' %>,</p> <p>Hi <%= d 'user.firstname' %>,</p>
<br> <br>
<p>it looks like you signed into your <%= c 'product_name' %> account using a new device on "<%= d 'user_device.created_at' %>":</p> <p>It looks like you signed into your <%= c 'product_name' %> account using a new device on "<%= d 'user_device.created_at' %>":</p>
<br> <br>
<p> <p>
Your Location: <%= d 'user_device.location' %><br> Your location: <%= d 'user_device.location' %><br>
Your IP: <%= d 'user_device.ip' %><br Your IP: <%= d 'user_device.ip' %><br
</p> </p>
<br> <br>

View file

@ -11,8 +11,8 @@ class CustomerTicketCreateTest < TestCase
) )
# customer ticket create # customer ticket create
click( css: 'a[href="#new"]' ) click(css: 'a[href="#new"]')
click( css: 'a[href="#customer_ticket_new"]' ) click(css: 'a[href="#customer_ticket_new"]')
sleep 2 sleep 2
select( select(
@ -28,11 +28,11 @@ class CustomerTicketCreateTest < TestCase
css: '.newTicket [data-name="body"]', css: '.newTicket [data-name="body"]',
value: 'some body 123äöü', value: 'some body 123äöü',
) )
click( css: '.newTicket button.js-submit' ) click(css: '.newTicket button.js-submit')
sleep 5 sleep 5
# check if ticket is shown # check if ticket is shown
location_check( url: '#ticket/zoom/' ) location_check(url: '#ticket/zoom/')
match( match(
css: '.active div.ticket-article', css: '.active div.ticket-article',
@ -51,7 +51,7 @@ class CustomerTicketCreateTest < TestCase
type: 'stayOnTab', type: 'stayOnTab',
) )
click( css: '.active .js-submit' ) click(css: '.active .js-submit')
watch_for( watch_for(
css: '.active div.ticket-article', css: '.active div.ticket-article',

View file

@ -35,6 +35,21 @@ class KeyboardShortcutsTest < TestCase
timeout: 2, timeout: 2,
) )
# show notifications
shortcut(key: 'a')
watch_for(
css: '.js-notificationsContainer .js-header',
value: 'Notification',
timeout: 10,
)
shortcut(key: 'a')
watch_for_disappear(
css: '.js-notificationsContainer .js-header',
value: 'Notification',
timeout: 2,
)
# go to overviews # go to overviews
shortcut(key: 'o') shortcut(key: 'o')
watch_for( watch_for(
@ -172,7 +187,7 @@ class KeyboardShortcutsTest < TestCase
}, },
) )
sleep 5 sleep 5
shortcut(key: 'y') shortcut(key: 'a')
watch_for( watch_for(
css: '.js-notificationsContainer', css: '.js-notificationsContainer',
value: 'Test Ticket for Shortcuts II', value: 'Test Ticket for Shortcuts II',
@ -183,7 +198,7 @@ class KeyboardShortcutsTest < TestCase
watch_for( watch_for(
css: '.active.content', css: '.active.content',
value: ticket2[:number], value: ticket2[:number],
timeout: 2, timeout: 3,
) )
shortcut(key: 'e') shortcut(key: 'e')

View file

@ -139,6 +139,9 @@ class TestCase < Test::Unit::TestCase
instance.get(params[:url]) instance.get(params[:url])
end end
# submit logs anyway
instance.execute_script('App.Track.force()')
element = instance.find_elements(css: '#login input[name="username"]')[0] element = instance.find_elements(css: '#login input[name="username"]')[0]
if !element if !element
@ -363,7 +366,6 @@ class TestCase < Test::Unit::TestCase
#if element #if element
# instance.mouse.move_to(element) # instance.mouse.move_to(element)
#end #end
sleep 0.2
element.click element.click
rescue => e rescue => e
sleep 0.5 sleep 0.5
@ -374,15 +376,14 @@ class TestCase < Test::Unit::TestCase
#if element #if element
# instance.mouse.move_to(element) # instance.mouse.move_to(element)
#end #end
sleep 0.2
element.click element.click
end end
else else
sleep 1 sleep 0.5
instance.find_elements(partial_link_text: params[:text])[0].click instance.find_elements(partial_link_text: params[:text])[0].click
end end
sleep 0.4 if !params[:fast] sleep 0.2 if !params[:fast]
sleep params[:wait] if params[:wait] sleep params[:wait] if params[:wait]
end end
@ -517,7 +518,7 @@ class TestCase < Test::Unit::TestCase
instance.execute_script("$('#{params[:css]}').blur()") instance.execute_script("$('#{params[:css]}').blur()")
end end
sleep 0.5 sleep 0.2
end end
=begin =begin
@ -543,11 +544,11 @@ class TestCase < Test::Unit::TestCase
element = instance.find_elements(css: "#{params[:css]}.js-shadow + .js-input")[0] element = instance.find_elements(css: "#{params[:css]}.js-shadow + .js-input")[0]
element.click element.click
element.clear element.clear
sleep 1 sleep 0.5
element.send_keys(params[:value]) element.send_keys(params[:value])
sleep 0.5 sleep 0.2
element.send_keys(:enter) element.send_keys(:enter)
sleep 0.5 sleep 0.2
return return
end end
@ -573,7 +574,7 @@ class TestCase < Test::Unit::TestCase
dropdown.select_by(:text, params[:value]) dropdown.select_by(:text, params[:value])
#puts "select2 - #{params.inspect}" #puts "select2 - #{params.inspect}"
end end
sleep 0.8 sleep 0.5
end end
=begin =begin
@ -668,9 +669,9 @@ class TestCase < Test::Unit::TestCase
end end
instance.action.send_keys(params[:value]).perform instance.action.send_keys(params[:value]).perform
if params[:slow] if params[:slow]
sleep 2 sleep 1.5
else else
sleep 0.3 sleep 0.2
end end
end end
@ -757,7 +758,7 @@ class TestCase < Test::Unit::TestCase
elsif !params[:should_not_match] elsif !params[:should_not_match]
raise "not matching '#{params[:value]}' in content '#{text}' but should!" raise "not matching '#{params[:value]}' in content '#{text}' but should!"
end end
sleep 0.8 sleep 0.2
match match
end end
@ -1215,7 +1216,7 @@ wait untill text in selector disabppears
# accept task close warning # accept task close warning
if instance.find_elements(css: '.modal button.js-submit')[0] if instance.find_elements(css: '.modal button.js-submit')[0]
sleep 0.5 sleep 0.4
instance.find_elements(css: '.modal button.js-submit')[0].click instance.find_elements(css: '.modal button.js-submit')[0].click
end end
end end
@ -1284,16 +1285,16 @@ wait untill text in selector disabppears
# workaround, sometimes focus is not triggered # workaround, sometimes focus is not triggered
element.send_keys(params[:customer]) element.send_keys(params[:customer])
sleep 3.5 sleep 2.5
# check if pulldown is open, it's not working stable via selenium # check if pulldown is open, it's not working stable via selenium
#instance.execute_script("$('#{params[:css]} .js-recipientDropdown').addClass('open')") #instance.execute_script("$('#{params[:css]} .js-recipientDropdown').addClass('open')")
#sleep 0.5 #sleep 0.5
element.send_keys(:arrow_down) element.send_keys(:arrow_down)
sleep 0.3 sleep 0.2
element.send_keys(:enter) element.send_keys(:enter)
#instance.find_elements(css: params[:css] + ' .recipientList-entry.js-user.is-active')[0].click #instance.find_elements(css: params[:css] + ' .recipientList-entry.js-user.is-active')[0].click
sleep 0.6 sleep 0.4
assert(true, 'ticket_customer_select') assert(true, 'ticket_customer_select')
end end
@ -1545,7 +1546,7 @@ wait untill text in selector disabppears
screenshot(browser: instance, comment: 'ticket_create_failed') screenshot(browser: instance, comment: 'ticket_create_failed')
raise 'no ticket create screen found!' raise 'no ticket create screen found!'
end end
sleep 1 sleep 0.4
if data[:group] if data[:group]
if data[:group] == '-NONE-' if data[:group] == '-NONE-'
@ -1613,16 +1614,16 @@ wait untill text in selector disabppears
# workaround, sometimes focus is not triggered # workaround, sometimes focus is not triggered
element.send_keys(data[:customer]) element.send_keys(data[:customer])
sleep 3.5 sleep 2.5
# check if pulldown is open, it's not working stable via selenium # check if pulldown is open, it's not working stable via selenium
#instance.execute_script("$('.active .newTicket .js-recipientDropdown').addClass('open')") #instance.execute_script("$('.active .newTicket .js-recipientDropdown').addClass('open')")
#sleep 0.5 #sleep 0.5
element.send_keys(:arrow_down) element.send_keys(:arrow_down)
sleep 0.3 sleep 0.2
element.send_keys(:enter) element.send_keys(:enter)
#instance.find_elements(css: '.active .newTicket .recipientList-entry.js-user.is-active')[0].click #instance.find_elements(css: '.active .newTicket .recipientList-entry.js-user.is-active')[0].click
sleep 0.6 sleep 0.4
end end
if data[:attachment] if data[:attachment]
@ -1742,16 +1743,16 @@ wait untill text in selector disabppears
# workaround, sometimes focus is not triggered # workaround, sometimes focus is not triggered
element.send_keys(data[:customer]) element.send_keys(data[:customer])
sleep 3.5 sleep 2.5
# check if pulldown is open, it's not working stable via selenium # check if pulldown is open, it's not working stable via selenium
#instance.execute_script("$('.modal .user_autocompletion .js-recipientDropdown').addClass('open')") #instance.execute_script("$('.modal .user_autocompletion .js-recipientDropdown').addClass('open')")
#sleep 0.5 #sleep 0.5
element.send_keys(:arrow_down) element.send_keys(:arrow_down)
sleep 0.6 sleep 0.4
element.send_keys(:enter) element.send_keys(:enter)
#instance.find_elements(css: '.modal .user_autocompletion .recipientList-entry.js-user.is-active')[0].click #instance.find_elements(css: '.modal .user_autocompletion .recipientList-entry.js-user.is-active')[0].click
sleep 0.3 sleep 0.2
click(browser: instance, css: '.modal .js-submit') click(browser: instance, css: '.modal .js-submit')