Added basic tweet reply function.
This commit is contained in:
parent
79a32230fd
commit
0a20a1f906
7 changed files with 177 additions and 77 deletions
|
@ -2,8 +2,10 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||||
events:
|
events:
|
||||||
'click [data-type=public]': 'publicInternal'
|
'click [data-type=public]': 'publicInternal'
|
||||||
'click [data-type=internal]': 'publicInternal'
|
'click [data-type=internal]': 'publicInternal'
|
||||||
'click [data-type=reply]': 'reply'
|
'click [data-type=emailReply]': 'emailReply'
|
||||||
'click [data-type=replyAll]': 'replyAll'
|
'click [data-type=emailReplyAll]': 'emailReplyAll'
|
||||||
|
'click [data-type=twitterStatusReply]': 'twitterStatusReply'
|
||||||
|
'click [data-type=twitterDirectMessageReply]': 'twitterDirectMessageReply'
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
|
@ -68,7 +70,7 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||||
if article.type.name is 'email' || article.type.name is 'phone' || article.type.name is 'web'
|
if article.type.name is 'email' || article.type.name is 'phone' || article.type.name is 'web'
|
||||||
actions.push {
|
actions.push {
|
||||||
name: 'reply'
|
name: 'reply'
|
||||||
type: 'reply'
|
type: 'emailReply'
|
||||||
icon: 'reply'
|
icon: 'reply'
|
||||||
href: '#'
|
href: '#'
|
||||||
}
|
}
|
||||||
|
@ -90,10 +92,18 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||||
if recipients.length > 1
|
if recipients.length > 1
|
||||||
actions.push {
|
actions.push {
|
||||||
name: 'reply all'
|
name: 'reply all'
|
||||||
type: 'replyAll'
|
type: 'emailReplyAll'
|
||||||
icon: 'reply-all'
|
icon: 'reply-all'
|
||||||
href: '#'
|
href: '#'
|
||||||
}
|
}
|
||||||
|
if article.type.name is 'twitter status'
|
||||||
|
actions.push {
|
||||||
|
name: 'reply'
|
||||||
|
type: 'twitterStatusReply'
|
||||||
|
icon: 'reply'
|
||||||
|
href: '#'
|
||||||
|
}
|
||||||
|
|
||||||
actions.push {
|
actions.push {
|
||||||
name: 'split'
|
name: 'split'
|
||||||
type: 'split'
|
type: 'split'
|
||||||
|
@ -102,19 +112,83 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||||
}
|
}
|
||||||
actions
|
actions
|
||||||
|
|
||||||
replyAll: (e) =>
|
twitterStatusReply: (e) =>
|
||||||
@reply(e, true)
|
|
||||||
|
|
||||||
reply: (e, all = false) =>
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
# get reference article
|
# get reference article
|
||||||
article_id = $(e.target).parents('[data-id]').data('id')
|
article_id = $(e.target).parents('[data-id]').data('id')
|
||||||
article = App.TicketArticle.fullLocal( article_id )
|
article = App.TicketArticle.fullLocal(article_id)
|
||||||
type = App.TicketArticleType.find( article.type_id )
|
type = App.TicketArticleType.find(article.type_id)
|
||||||
customer = App.User.find( article.created_by_id )
|
customer = App.User.find(article.created_by_id)
|
||||||
|
|
||||||
@el.closest('.article-add').ScrollTo()
|
@scrollToCompose()
|
||||||
|
|
||||||
|
# empty form
|
||||||
|
articleNew = {
|
||||||
|
to: ''
|
||||||
|
cc: ''
|
||||||
|
body: ''
|
||||||
|
in_reply_to: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if article.message_id
|
||||||
|
articleNew.in_reply_to = article.message_id
|
||||||
|
|
||||||
|
# get current body
|
||||||
|
body = @el.closest('.ticketZoom').find('.article-add [data-name="body"]').html() || ''
|
||||||
|
articleNew.body = body
|
||||||
|
|
||||||
|
to = customer.accounts['twitter'].username || customer.accounts['twitter'].uid
|
||||||
|
recipient = "@#{to} "
|
||||||
|
|
||||||
|
if !body
|
||||||
|
articleNew.body = recipient
|
||||||
|
|
||||||
|
if body && !body.match("@#{to}")
|
||||||
|
articleNew.body = "#{recipient}#{articleNew.body}"
|
||||||
|
|
||||||
|
|
||||||
|
App.Event.trigger('ui::ticket::setArticleType', { ticket: @ticket, type: type, article: articleNew } )
|
||||||
|
|
||||||
|
twitterDirectMessageReply: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
# get reference article
|
||||||
|
article_id = $(e.target).parents('[data-id]').data('id')
|
||||||
|
article = App.TicketArticle.fullLocal(article_id)
|
||||||
|
type = App.TicketArticleType.find(article.type_id)
|
||||||
|
customer = App.User.find(article.created_by_id)
|
||||||
|
|
||||||
|
@scrollToCompose()
|
||||||
|
|
||||||
|
# empty form
|
||||||
|
articleNew = {
|
||||||
|
to: ''
|
||||||
|
cc: ''
|
||||||
|
body: ''
|
||||||
|
in_reply_to: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if article.message_id
|
||||||
|
articleNew.in_reply_to = article.message_id
|
||||||
|
|
||||||
|
articleNew.to = customer.accounts['twitter'].username || customer.accounts['twitter'].uid
|
||||||
|
|
||||||
|
App.Event.trigger('ui::ticket::setArticleType', { ticket: @ticket, type: type, article: articleNew } )
|
||||||
|
|
||||||
|
emailReplyAll: (e) =>
|
||||||
|
@emailReply(e, true)
|
||||||
|
|
||||||
|
emailReply: (e, all = false) =>
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
# get reference article
|
||||||
|
article_id = $(e.target).parents('[data-id]').data('id')
|
||||||
|
article = App.TicketArticle.fullLocal(article_id)
|
||||||
|
type = App.TicketArticleType.find(article.type_id)
|
||||||
|
customer = App.User.find(article.created_by_id)
|
||||||
|
|
||||||
|
@scrollToCompose()
|
||||||
|
|
||||||
# empty form
|
# empty form
|
||||||
articleNew = {
|
articleNew = {
|
||||||
|
@ -129,19 +203,7 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||||
if article.message_id
|
if article.message_id
|
||||||
articleNew.in_reply_to = article.message_id
|
articleNew.in_reply_to = article.message_id
|
||||||
|
|
||||||
if type.name is 'twitter status'
|
if type.name is 'email' || type.name is 'phone' || type.name is 'web'
|
||||||
|
|
||||||
# set to in body
|
|
||||||
to = customer.accounts['twitter'].username || customer.accounts['twitter'].uid
|
|
||||||
articleNew.body = '@' + to
|
|
||||||
|
|
||||||
else if type.name is 'twitter direct-message'
|
|
||||||
|
|
||||||
# show to
|
|
||||||
to = customer.accounts['twitter'].username || customer.accounts['twitter'].uid
|
|
||||||
articleNew.to = to
|
|
||||||
|
|
||||||
else if type.name is 'email' || type.name is 'phone' || type.name is 'web'
|
|
||||||
|
|
||||||
if article.sender.name is 'Agent'
|
if article.sender.name is 'Agent'
|
||||||
articleNew.to = article.to
|
articleNew.to = article.to
|
||||||
|
@ -198,10 +260,10 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||||
if selectedText
|
if selectedText
|
||||||
|
|
||||||
# clean selection
|
# clean selection
|
||||||
selectedText = App.Utils.textCleanup( selectedText )
|
selectedText = App.Utils.textCleanup(selectedText)
|
||||||
|
|
||||||
# convert to html
|
# convert to html
|
||||||
selectedText = App.Utils.text2html( selectedText )
|
selectedText = App.Utils.text2html(selectedText)
|
||||||
if selectedText
|
if selectedText
|
||||||
selectedText = "<div><br><br/></div><div><blockquote type=\"cite\">#{selectedText}</blockquote></div><div><br></div>"
|
selectedText = "<div><br><br/></div><div><blockquote type=\"cite\">#{selectedText}</blockquote></div><div><br></div>"
|
||||||
|
|
||||||
|
@ -210,4 +272,10 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||||
|
|
||||||
articleNew.body = body
|
articleNew.body = body
|
||||||
|
|
||||||
|
type = App.TicketArticleType.findByAttribute(name:'email')
|
||||||
|
|
||||||
App.Event.trigger('ui::ticket::setArticleType', { ticket: @ticket, type: type, article: articleNew } )
|
App.Event.trigger('ui::ticket::setArticleType', { ticket: @ticket, type: type, article: articleNew } )
|
||||||
|
|
||||||
|
scrollToCompose: =>
|
||||||
|
@el.closest('.content').find('.article-add').ScrollTo()
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,6 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||||
# set article type and expand text area
|
# set article type and expand text area
|
||||||
@bind('ui::ticket::setArticleType', (data) =>
|
@bind('ui::ticket::setArticleType', (data) =>
|
||||||
return if data.ticket.id isnt @ticket_id
|
return if data.ticket.id isnt @ticket_id
|
||||||
#@setArticleType(data.type.name)
|
|
||||||
|
|
||||||
@openTextarea(null, true)
|
@openTextarea(null, true)
|
||||||
for key, value of data.article
|
for key, value of data.article
|
||||||
|
@ -94,7 +93,7 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||||
@$('[name="' + key + '"]').val(value)
|
@$('[name="' + key + '"]').val(value)
|
||||||
|
|
||||||
# preselect article type
|
# preselect article type
|
||||||
@setArticleType('email')
|
@setArticleType(data.type.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
# reset new article screen
|
# reset new article screen
|
||||||
|
|
|
@ -8,12 +8,11 @@ class Avatar < ApplicationModel
|
||||||
add an avatar based on auto detection (email address)
|
add an avatar based on auto detection (email address)
|
||||||
|
|
||||||
Avatar.auto_detection(
|
Avatar.auto_detection(
|
||||||
:object => 'User',
|
object: 'User',
|
||||||
:o_id => user.id,
|
o_id: user.id,
|
||||||
:url => 'somebody@example.com',
|
url: 'somebody@example.com',
|
||||||
:source => 'web',
|
updated_by_id: 1,
|
||||||
:updated_by_id => 1,
|
created_by_id: 1,
|
||||||
:created_by_id => 1,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
@ -41,20 +40,20 @@ add an avatar based on auto detection (email address)
|
||||||
add a avatar
|
add a avatar
|
||||||
|
|
||||||
Avatar.add(
|
Avatar.add(
|
||||||
:object => 'User',
|
object: 'User',
|
||||||
:o_id => user.id,
|
o_id: user.id,
|
||||||
:default => true,
|
default: true,
|
||||||
:full => {
|
full: {
|
||||||
:content => '...',
|
content: '...',
|
||||||
:mime_type => 'image/png',
|
mime_type: 'image/png',
|
||||||
},
|
},
|
||||||
:resize => {
|
resize: {
|
||||||
:content => '...',
|
content: '...',
|
||||||
:mime_type => 'image/png',
|
mime_type: 'image/png',
|
||||||
},
|
},
|
||||||
:source => 'web',
|
source: 'web',
|
||||||
:updated_by_id => 1,
|
updated_by_id: 1,
|
||||||
:created_by_id => 1,
|
created_by_id: 1,
|
||||||
)
|
)
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
@ -214,7 +213,7 @@ add a avatar
|
||||||
|
|
||||||
set avatars as default
|
set avatars as default
|
||||||
|
|
||||||
Avatar.set_default( 'User', 123, avatar_id )
|
Avatar.set_default('User', 123, avatar_id)
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
|
@ -238,12 +237,12 @@ set avatars as default
|
||||||
|
|
||||||
remove all avatars of an object
|
remove all avatars of an object
|
||||||
|
|
||||||
Avatar.remove( 'User', 123 )
|
Avatar.remove('User', 123)
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.remove( object_name, o_id )
|
def self.remove(object_name, o_id)
|
||||||
object_id = ObjectLookup.by_name( object_name )
|
object_id = ObjectLookup.by_name(object_name)
|
||||||
Avatar.where(
|
Avatar.where(
|
||||||
object_lookup_id: object_id,
|
object_lookup_id: object_id,
|
||||||
o_id: o_id,
|
o_id: o_id,
|
||||||
|
@ -264,12 +263,12 @@ remove all avatars of an object
|
||||||
|
|
||||||
remove one avatars of an object
|
remove one avatars of an object
|
||||||
|
|
||||||
Avatar.remove_one( 'User', 123, avatar_id )
|
Avatar.remove_one('User', 123, avatar_id)
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.remove_one( object_name, o_id, avatar_id )
|
def self.remove_one(object_name, o_id, avatar_id)
|
||||||
object_id = ObjectLookup.by_name( object_name )
|
object_id = ObjectLookup.by_name(object_name)
|
||||||
Avatar.where(
|
Avatar.where(
|
||||||
object_lookup_id: object_id,
|
object_lookup_id: object_id,
|
||||||
o_id: o_id,
|
o_id: o_id,
|
||||||
|
@ -281,16 +280,16 @@ remove one avatars of an object
|
||||||
|
|
||||||
return all avatars of an user
|
return all avatars of an user
|
||||||
|
|
||||||
avatars = Avatar.list( 'User', 123 )
|
avatars = Avatar.list('User', 123)
|
||||||
|
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.list(object_name, o_id)
|
def self.list(object_name, o_id)
|
||||||
object_id = ObjectLookup.by_name( object_name )
|
object_id = ObjectLookup.by_name(object_name)
|
||||||
avatars = Avatar.where(
|
avatars = Avatar.where(
|
||||||
object_lookup_id: object_id,
|
object_lookup_id: object_id,
|
||||||
o_id: o_id,
|
o_id: o_id,
|
||||||
).order( 'initial DESC, deletable ASC, created_at ASC, id DESC' )
|
).order('initial DESC, deletable ASC, created_at ASC, id DESC')
|
||||||
|
|
||||||
# add initial avatar
|
# add initial avatar
|
||||||
add_init_avatar(object_id, o_id)
|
add_init_avatar(object_id, o_id)
|
||||||
|
@ -300,7 +299,7 @@ return all avatars of an user
|
||||||
data = avatar.attributes
|
data = avatar.attributes
|
||||||
if avatar.store_resize_id
|
if avatar.store_resize_id
|
||||||
file = Store.find(avatar.store_resize_id)
|
file = Store.find(avatar.store_resize_id)
|
||||||
data['content'] = "data:#{file.preferences['Mime-Type']};base64,#{Base64.strict_encode64( file.content )}"
|
data['content'] = "data:#{file.preferences['Mime-Type']};base64,#{Base64.strict_encode64(file.content)}"
|
||||||
end
|
end
|
||||||
avatar_list.push data
|
avatar_list.push data
|
||||||
end
|
end
|
||||||
|
@ -311,7 +310,7 @@ return all avatars of an user
|
||||||
|
|
||||||
get default avatar image of user by hash
|
get default avatar image of user by hash
|
||||||
|
|
||||||
store = Avatar.get_by_hash( hash )
|
store = Avatar.get_by_hash(hash)
|
||||||
|
|
||||||
returns:
|
returns:
|
||||||
|
|
||||||
|
@ -331,7 +330,7 @@ returns:
|
||||||
|
|
||||||
get default avatar of user by user id
|
get default avatar of user by user id
|
||||||
|
|
||||||
avatar = Avatar.get_default( 'User', user_id )
|
avatar = Avatar.get_default('User', user_id)
|
||||||
|
|
||||||
returns:
|
returns:
|
||||||
|
|
||||||
|
@ -340,7 +339,7 @@ returns:
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def self.get_default(object_name, o_id)
|
def self.get_default(object_name, o_id)
|
||||||
object_id = ObjectLookup.by_name( object_name )
|
object_id = ObjectLookup.by_name(object_name)
|
||||||
Avatar.find_by(
|
Avatar.find_by(
|
||||||
object_lookup_id: object_id,
|
object_lookup_id: object_id,
|
||||||
o_id: o_id,
|
o_id: o_id,
|
||||||
|
@ -352,7 +351,7 @@ returns:
|
||||||
avatars = Avatar.where(
|
avatars = Avatar.where(
|
||||||
object_lookup_id: object_id,
|
object_lookup_id: object_id,
|
||||||
o_id: o_id,
|
o_id: o_id,
|
||||||
).order( 'created_at ASC, id DESC' )
|
).order('created_at ASC, id DESC')
|
||||||
avatars.each do |avatar|
|
avatars.each do |avatar|
|
||||||
next if avatar.id == avatar_id
|
next if avatar.id == avatar_id
|
||||||
avatar.default = false
|
avatar.default = false
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
# http://stem.ps/rails/2015/01/25/ruby-gotcha-toplevel-constant-referenced-by.html
|
|
||||||
require 'channel/driver/twitter'
|
|
||||||
|
|
||||||
class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer
|
class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer
|
||||||
observe 'ticket::_article'
|
observe 'ticket::_article'
|
||||||
|
|
||||||
|
@ -28,9 +25,26 @@ class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer
|
||||||
tweet = channel.deliver(
|
tweet = channel.deliver(
|
||||||
type: type['name'],
|
type: type['name'],
|
||||||
to: record.to,
|
to: record.to,
|
||||||
body: record.body,
|
body: record.body.html2text,
|
||||||
in_reply_to: record.in_reply_to
|
in_reply_to: record.in_reply_to
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# fill article with tweet info
|
||||||
|
record.from = tweet.user.screen_name
|
||||||
|
if tweet.user_mentions
|
||||||
|
to = ''
|
||||||
|
twitter_mention_ids = []
|
||||||
|
tweet.user_mentions.each {|user|
|
||||||
|
if to != ''
|
||||||
|
to += ' '
|
||||||
|
end
|
||||||
|
to += "@#{user.screen_name}"
|
||||||
|
twitter_mention_ids.push user.id
|
||||||
|
}
|
||||||
|
record.to = to
|
||||||
|
record.preferences[:twitter_mention_ids] = twitter_mention_ids
|
||||||
|
end
|
||||||
|
|
||||||
record.message_id = tweet.id
|
record.message_id = tweet.id
|
||||||
record.save
|
record.save
|
||||||
end
|
end
|
||||||
|
|
26
lib/tweet.rb
26
lib/tweet.rb
|
@ -68,6 +68,24 @@ class Tweet
|
||||||
user = User.create(user_data)
|
user = User.create(user_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if user_data[:image_source]
|
||||||
|
avatar = Avatar.add(
|
||||||
|
object: 'User',
|
||||||
|
o_id: user.id,
|
||||||
|
url: user_data[:image_source],
|
||||||
|
source: 'twitter',
|
||||||
|
deletable: true,
|
||||||
|
updated_by_id: user.id,
|
||||||
|
created_by_id: user.id,
|
||||||
|
)
|
||||||
|
|
||||||
|
# update user link
|
||||||
|
if avatar && user.image != avatar.store_hash
|
||||||
|
user.image = avatar.store_hash
|
||||||
|
user.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# create or update authorization
|
# create or update authorization
|
||||||
auth_data = {
|
auth_data = {
|
||||||
uid: tweet_user.id,
|
uid: tweet_user.id,
|
||||||
|
@ -81,8 +99,6 @@ class Tweet
|
||||||
Authorization.create(auth_data)
|
Authorization.create(auth_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
UserInfo.current_user_id = user.id
|
|
||||||
|
|
||||||
user
|
user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -112,6 +128,8 @@ class Tweet
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
UserInfo.current_user_id = user.id
|
||||||
|
|
||||||
Ticket.create(
|
Ticket.create(
|
||||||
customer_id: user.id,
|
customer_id: user.id,
|
||||||
title: "#{tweet.text[0, 37]}...",
|
title: "#{tweet.text[0, 37]}...",
|
||||||
|
@ -148,12 +166,14 @@ class Tweet
|
||||||
from = tweet.sender.screen_name
|
from = tweet.sender.screen_name
|
||||||
elsif tweet.class == Twitter::Tweet
|
elsif tweet.class == Twitter::Tweet
|
||||||
article_type = 'twitter status'
|
article_type = 'twitter status'
|
||||||
from = tweet.in_reply_to_screen_name
|
from = tweet.user.screen_name
|
||||||
in_reply_to = tweet.in_reply_to_status_id
|
in_reply_to = tweet.in_reply_to_status_id
|
||||||
else
|
else
|
||||||
fail "Unknown tweet type '#{tweet.class}'"
|
fail "Unknown tweet type '#{tweet.class}'"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
UserInfo.current_user_id = user.id
|
||||||
|
|
||||||
Ticket::Article.create(
|
Ticket::Article.create(
|
||||||
from: from,
|
from: from,
|
||||||
to: to,
|
to: to,
|
||||||
|
|
|
@ -243,7 +243,7 @@ class AgentTicketActionLevel5Test < TestCase
|
||||||
|
|
||||||
# execute reply
|
# execute reply
|
||||||
click(
|
click(
|
||||||
css: '.active [data-type="reply"]',
|
css: '.active [data-type="emailReply"]',
|
||||||
)
|
)
|
||||||
|
|
||||||
# check if signature exists
|
# check if signature exists
|
||||||
|
@ -267,7 +267,7 @@ class AgentTicketActionLevel5Test < TestCase
|
||||||
# execute reply
|
# execute reply
|
||||||
sleep 5 # time to recognice form changes
|
sleep 5 # time to recognice form changes
|
||||||
click(
|
click(
|
||||||
css: '.active [data-type="reply"]',
|
css: '.active [data-type="emailReply"]',
|
||||||
)
|
)
|
||||||
|
|
||||||
# check if signature exists
|
# check if signature exists
|
||||||
|
|
|
@ -35,11 +35,11 @@ class AgentTicketActionLevel7Test < TestCase
|
||||||
# scroll to reply - needed for chrome
|
# scroll to reply - needed for chrome
|
||||||
scroll_to(
|
scroll_to(
|
||||||
position: 'botton',
|
position: 'botton',
|
||||||
css: '.content.active [data-type="reply"]',
|
css: '.content.active [data-type="emailReply"]',
|
||||||
)
|
)
|
||||||
|
|
||||||
# click reply
|
# click reply
|
||||||
click( css: '.content.active [data-type="reply"]' )
|
click( css: '.content.active [data-type="emailReply"]' )
|
||||||
|
|
||||||
# check body
|
# check body
|
||||||
watch_for(
|
watch_for(
|
||||||
|
@ -58,11 +58,11 @@ class AgentTicketActionLevel7Test < TestCase
|
||||||
# scroll to reply - needed for chrome
|
# scroll to reply - needed for chrome
|
||||||
scroll_to(
|
scroll_to(
|
||||||
position: 'botton',
|
position: 'botton',
|
||||||
css: '.content.active [data-type="reply"]',
|
css: '.content.active [data-type="emailReply"]',
|
||||||
)
|
)
|
||||||
|
|
||||||
# click reply
|
# click reply
|
||||||
click( css: '.content.active [data-type="reply"]' )
|
click( css: '.content.active [data-type="emailReply"]' )
|
||||||
|
|
||||||
# check body
|
# check body
|
||||||
watch_for(
|
watch_for(
|
||||||
|
|
Loading…
Reference in a new issue