Implemented issue#341 - optional subject for email, define if twitter initials are used and default internal state of new notes.

This commit is contained in:
Martin Edenhofer 2017-07-05 07:18:19 +02:00
parent 84ed6f6c22
commit 0065028ee6
10 changed files with 342 additions and 124 deletions

View file

@ -404,7 +404,7 @@ class App.TicketZoom extends App.Controller
) )
new App.TicketZoomOverviewNavigator( new App.TicketZoomOverviewNavigator(
el: elLocal.find('.overview-navigator') el: elLocal.find('.js-overviewNavigatorContainer')
ticket_id: @ticket_id ticket_id: @ticket_id
overview_id: @overview_id overview_id: @overview_id
) )
@ -412,13 +412,13 @@ class App.TicketZoom extends App.Controller
new App.TicketZoomTitle( new App.TicketZoomTitle(
object_id: @ticket_id object_id: @ticket_id
overview_id: @overview_id overview_id: @overview_id
el: elLocal.find('.ticket-title') el: elLocal.find('.js-ticketTitleContainer')
task_key: @task_key task_key: @task_key
) )
new App.TicketZoomMeta( new App.TicketZoomMeta(
object_id: @ticket_id object_id: @ticket_id
el: elLocal.find('.ticket-meta') el: elLocal.find('.js-ticketMetaContainer')
) )
@attributeBar = new App.TicketZoomAttributeBar( @attributeBar = new App.TicketZoomAttributeBar(
@ -445,7 +445,12 @@ class App.TicketZoom extends App.Controller
) )
@highligher = new App.TicketZoomHighlighter( @highligher = new App.TicketZoomHighlighter(
el: elLocal.find('.highlighter') el: elLocal.find('.js-highlighterContainer')
ticket_id: @ticket_id
)
new App.TicketZoomSetting(
el: elLocal.find('.js-settingContainer')
ticket_id: @ticket_id ticket_id: @ticket_id
) )
@ -557,14 +562,16 @@ class App.TicketZoom extends App.Controller
return if !@ticket return if !@ticket
currentStoreTicket = @ticket.attributes() currentStoreTicket = @ticket.attributes()
delete currentStoreTicket.article delete currentStoreTicket.article
internal = @Config.get('ui_ticket_zoom_article_note_new_internal')
currentStore = currentStore =
ticket: currentStoreTicket ticket: currentStoreTicket
article: article:
to: '' to: ''
cc: '' cc: ''
subject: ''
type: 'note' type: 'note'
body: '' body: ''
internal: 'true' internal: internal
in_reply_to: '' in_reply_to: ''
if @permissionCheck('ticket.customer') if @permissionCheck('ticket.customer')
@ -575,7 +582,7 @@ class App.TicketZoom extends App.Controller
formCurrent: => formCurrent: =>
currentParams = currentParams =
ticket: @formParam(@el.find('.edit')) ticket: @formParam(@el.find('.edit'))
article: @formParam(@el.find('.article-add')) article: @articleNew.params()
# add attachments if exist # add attachments if exist
attachmentCount = @$('.article-add .textBubble .attachments .attachment').length attachmentCount = @$('.article-add .textBubble .attachments .attachment').length

View file

@ -28,107 +28,9 @@ class App.TicketZoomArticleNew extends App.Controller
constructor: -> constructor: ->
super super
# set possble article types
possibleArticleType =
note: true
phone: true
if @ticket && @ticket.create_article_type_id
articleTypeCreate = App.TicketArticleType.find(@ticket.create_article_type_id).name
if articleTypeCreate is 'twitter status'
possibleArticleType['twitter status'] = true
else if articleTypeCreate is 'twitter direct-message'
possibleArticleType['twitter direct-message'] = true
else if articleTypeCreate is 'email'
possibleArticleType['email'] = true
else if articleTypeCreate is 'facebook feed post'
possibleArticleType['facebook feed comment'] = true
else if articleTypeCreate is 'telegram personal-message'
possibleArticleType['telegram personal-message'] = true
if @ticket && @ticket.customer_id
customer = App.User.find(@ticket.customer_id)
if customer.email
possibleArticleType['email'] = true
# gets referenced in @setArticleType
@internalSelector = true @internalSelector = true
@type = @defaults['type'] || 'note' @type = @defaults['type'] || 'note'
@articleTypes = [] @setPossibleArticleTypes()
if possibleArticleType.note
internal = @Config.get('ui_ticket_zoom_article_new_internal')
@articleTypes.push {
name: 'note'
icon: 'note'
attributes: []
internal: internal,
features: ['attachment']
}
if possibleArticleType.email
@articleTypes.push {
name: 'email'
icon: 'email'
attributes: ['to', 'cc']
internal: false,
features: ['attachment']
}
if possibleArticleType['facebook feed comment']
@articleTypes.push {
name: 'facebook feed comment'
icon: 'facebook'
attributes: []
internal: false,
features: []
}
if possibleArticleType['twitter status']
@articleTypes.push {
name: 'twitter status'
icon: 'twitter'
attributes: []
internal: false,
features: ['body:limit', 'body:initials']
maxTextLength: 140
warningTextLength: 30
}
if possibleArticleType['twitter direct-message']
@articleTypes.push {
name: 'twitter direct-message'
icon: 'twitter'
attributes: ['to']
internal: false,
features: ['body:limit', 'body:initials']
maxTextLength: 10000
warningTextLength: 500
}
if possibleArticleType.phone
@articleTypes.push {
name: 'phone'
icon: 'phone'
attributes: []
internal: false,
features: ['attachment']
}
if possibleArticleType['telegram personal-message']
@articleTypes.push {
name: 'telegram personal-message'
icon: 'telegram'
attributes: []
internal: false,
features: ['attachment']
maxTextLength: 10000
warningTextLength: 5000
}
if @permissionCheck('ticket.customer')
@type = 'note'
@articleTypes = [
{
name: 'note'
icon: 'note'
attributes: []
internal: false,
features: ['attachment']
},
]
if @permissionCheck('ticket.customer') if @permissionCheck('ticket.customer')
@internalSelector = false @internalSelector = false
@ -181,6 +83,114 @@ class App.TicketZoomArticleNew extends App.Controller
@render() @render()
) )
setPossibleArticleTypes: =>
possibleArticleType =
note: true
phone: true
if @ticket && @ticket.create_article_type_id
articleTypeCreate = App.TicketArticleType.find(@ticket.create_article_type_id).name
if articleTypeCreate is 'twitter status'
possibleArticleType['twitter status'] = true
else if articleTypeCreate is 'twitter direct-message'
possibleArticleType['twitter direct-message'] = true
else if articleTypeCreate is 'email'
possibleArticleType['email'] = true
else if articleTypeCreate is 'facebook feed post'
possibleArticleType['facebook feed comment'] = true
else if articleTypeCreate is 'telegram personal-message'
possibleArticleType['telegram personal-message'] = true
if @ticket && @ticket.customer_id
customer = App.User.find(@ticket.customer_id)
if customer.email
possibleArticleType['email'] = true
# gets referenced in @setArticleType
@articleTypes = []
if possibleArticleType.note
internal = @Config.get('ui_ticket_zoom_article_note_new_internal')
@articleTypes.push {
name: 'note'
icon: 'note'
attributes: []
internal: internal,
features: ['attachment']
}
if possibleArticleType.email
attributes = ['to', 'cc', 'subject']
if !@Config.get('ui_ticket_zoom_article_email_subject')
attributes = ['to', 'cc']
@articleTypes.push {
name: 'email'
icon: 'email'
attributes: attributes
internal: false,
features: ['attachment']
}
if possibleArticleType['facebook feed comment']
@articleTypes.push {
name: 'facebook feed comment'
icon: 'facebook'
attributes: []
internal: false,
features: []
}
if possibleArticleType['twitter status']
attributes = ['body:limit', 'body:initials']
if !@Config.get('ui_ticket_zoom_article_twitter_initials')
attributes = ['body:limit']
@articleTypes.push {
name: 'twitter status'
icon: 'twitter'
attributes: []
internal: false,
features: ['body:limit', 'body:initials']
maxTextLength: 140
warningTextLength: 30
}
if possibleArticleType['twitter direct-message']
attributes = ['body:limit', 'body:initials']
if !@Config.get('ui_ticket_zoom_article_twitter_initials')
attributes = ['body:limit']
@articleTypes.push {
name: 'twitter direct-message'
icon: 'twitter'
attributes: ['to']
internal: false,
features: ['body:limit', 'body:initials']
maxTextLength: 10000
warningTextLength: 500
}
if possibleArticleType.phone
@articleTypes.push {
name: 'phone'
icon: 'phone'
attributes: []
internal: false,
features: ['attachment']
}
if possibleArticleType['telegram personal-message']
@articleTypes.push {
name: 'telegram personal-message'
icon: 'telegram'
attributes: []
internal: false,
features: ['attachment']
maxTextLength: 10000
warningTextLength: 5000
}
if @permissionCheck('ticket.customer')
@type = 'note'
@articleTypes = [
{
name: 'note'
icon: 'note'
attributes: []
internal: false,
features: ['attachment']
},
]
placeCaretAtEnd: (el) -> placeCaretAtEnd: (el) ->
el.focus() el.focus()
if typeof window.getSelection isnt 'undefined' && typeof document.createRange isnt 'undefined' if typeof window.getSelection isnt 'undefined' && typeof document.createRange isnt 'undefined'
@ -318,9 +328,6 @@ class App.TicketZoomArticleNew extends App.Controller
params.form_id = @form_id params.form_id = @form_id
params.content_type = 'text/html' params.content_type = 'text/html'
if !params['internal']
params['internal'] = false
if @permissionCheck('ticket.customer') if @permissionCheck('ticket.customer')
sender = App.TicketArticleSender.findByAttribute('name', 'Customer') sender = App.TicketArticleSender.findByAttribute('name', 'Customer')
type = App.TicketArticleType.findByAttribute('name', 'web') type = App.TicketArticleType.findByAttribute('name', 'web')
@ -332,6 +339,11 @@ class App.TicketZoomArticleNew extends App.Controller
params.sender_id = sender.id params.sender_id = sender.id
params.type_id = type.id params.type_id = type.id
if params.internal
params.internal = true
else
params.internal = false
if params.type is 'twitter status' if params.type is 'twitter status'
App.Utils.htmlRemoveRichtext(@$('[data-name=body]'), false) App.Utils.htmlRemoveRichtext(@$('[data-name=body]'), false)
params.content_type = 'text/plain' params.content_type = 'text/plain'
@ -478,6 +490,8 @@ class App.TicketZoomArticleNew extends App.Controller
@articleNewEdit.attr('data-type', type) @articleNewEdit.attr('data-type', type)
@$('.js-selectableTypes').addClass('hide').filter("[data-type='#{type}']").removeClass('hide') @$('.js-selectableTypes').addClass('hide').filter("[data-type='#{type}']").removeClass('hide')
@setPossibleArticleTypes()
# get config # get config
config = {} config = {}
for articleTypeConfig in @articleTypes for articleTypeConfig in @articleTypes

View file

@ -0,0 +1,35 @@
class App.TicketZoomSetting extends App.Controller
events:
'click .js-setting': 'show'
constructor: ->
super
return if !@permissionCheck('admin')
@render()
render: ->
@html(App.view('ticket_zoom/setting')())
show: ->
new Modal()
class Modal extends App.ControllerModal
buttonClose: true
buttonCancel: true
buttonSubmit: false
head: 'Settings'
constructor: ->
super
render: =>
super
post: =>
new App.SettingsArea(
area: 'UI::TicketZoom'
el: @el.find('.modal-body')
)
content: ->
App.view('generic/page_loading')()

View file

@ -1,21 +1,22 @@
<div class="tabsSidebar-holder"> <div class="tabsSidebar-holder">
<div class="scrollPageHeader tabsSidebar-sidebarSpacer" style="right: <%- @scrollbarWidth %>px"> <div class="scrollPageHeader tabsSidebar-sidebarSpacer" style="right: <%- @scrollbarWidth %>px">
<small><%- @C('ticket_hook') %> <span class="ticket-number"><%- @ticket.number %></span></small> <small><%- @C('ticket_hook') %> <span class="ticket-number"><%- @ticket.number %></span></small>
<div class="ticket-title"></div> <div class="js-ticketTitleContainer ticket-title"></div>
<div class="highlighter"></div> <div class="js-highlighterContainer highlighter"></div>
<div class="overview-navigator"></div> <div class="js-overviewNavigatorContainer overview-navigator"></div>
</div> </div>
<div class="main no-padding flex tabsSidebar-sidebarSpacer tabsSidebar-tabsSpacer"> <div class="main no-padding flex tabsSidebar-sidebarSpacer tabsSidebar-tabsSpacer">
<div class="ticketZoom"> <div class="ticketZoom">
<div class="ticketZoom-controls"> <div class="ticketZoom-controls">
<div class="highlighter"></div> <div class="js-settingContainer"></div>
<div class="overview-navigator"></div> <div class="js-highlighterContainer highlighter"></div>
<div class="js-overviewNavigatorContainer overview-navigator"></div>
</div> </div>
<div class="ticketZoom-header"> <div class="ticketZoom-header">
<div class="flex vertical center"> <div class="flex vertical center">
<div class="js-avatar"></div> <div class="js-avatar"></div>
<div class="ticket-title"></div> <div class="js-ticketTitleContainer ticket-title"></div>
<div class="ticket-meta"></div> <div class="js-ticketMetaContainer"></div>
</div> </div>
</div> </div>
<div class="ticket-article"></div> <div class="ticket-article"></div>

View file

@ -41,13 +41,19 @@
<div class="formGroup-label"> <div class="formGroup-label">
<label for=""><%- @T('To') %></label> <label for=""><%- @T('To') %></label>
</div> </div>
<div class="controls"><input id="" type="text" name="to" value="<%= @article.to %>" class="form-control js-mail-inputs" required="required"></div> <div class="controls"><input type="text" name="to" value="<%= @article.to %>" class="form-control js-mail-inputs" required="required"></div>
</div> </div>
<div class="input form-group"> <div class="input form-group">
<div class="formGroup-label"> <div class="formGroup-label">
<label for=""><%- @T('Cc') %></label> <label for=""><%- @T('Cc') %></label>
</div> </div>
<div class="controls"><input id="" type="text" name="cc" value="<%= @article.cc %>" class="form-control js-mail-inputs"></div> <div class="controls"><input type="text" name="cc" value="<%= @article.cc %>" class="form-control js-mail-inputs"></div>
</div>
<div class="input form-group">
<div class="formGroup-label">
<label for=""><%- @T('Subject') %></label>
</div>
<div class="controls"><input type="text" name="subject" value="<%= @article.subject %>" class="form-control js-mail-inputs2"></div>
</div> </div>
<div class="textBubble js-writeArea"> <div class="textBubble js-writeArea">

View file

@ -0,0 +1,3 @@
<div class="btn btn--action btn--split--first js-setting centered">
<%- @Icon('cog', 'dropdown-icon') %>
</div>

View file

@ -0,0 +1,99 @@
class TicketZoomSetting < ActiveRecord::Migration
def up
# return if it's a new setup
return if !Setting.find_by(name: 'system_init_done')
setting = Setting.find_by(name: 'ui_ticket_zoom_article_new_internal')
if setting
setting.title = 'Note - default visibility'
setting.name = 'ui_ticket_zoom_article_note_new_internal'
setting.description = 'Default visibility for new articles.'
setting.preferences[:prio] = 100
setting.options[:form][0][:name] = 'ui_ticket_zoom_article_note_new_internal'
setting.save!
end
Setting.create_if_not_exists(
title: 'Note - default visibility',
name: 'ui_ticket_zoom_article_note_new_internal',
area: 'UI::TicketZoom',
description: 'Default visibility for new articles.',
options: {
form: [
{
display: '',
null: true,
name: 'ui_ticket_zoom_article_note_new_internal',
tag: 'boolean',
translate: true,
options: {
true => 'internal',
false => 'public',
},
},
],
},
state: true,
preferences: {
prio: 100,
permission: ['admin.ui'],
},
frontend: true
)
Setting.create_if_not_exists(
title: 'Email - subject field',
name: 'ui_ticket_zoom_article_email_subject',
area: 'UI::TicketZoom',
description: 'Use subject field for emails. If disabled, the ticket title will be used as subject.',
options: {
form: [
{
display: '',
null: true,
name: 'ui_ticket_zoom_article_email_subject',
tag: 'boolean',
translate: true,
options: {
true => 'yes',
false => 'no',
},
},
],
},
state: false,
preferences: {
prio: 200,
permission: ['admin.ui'],
},
frontend: true
)
Setting.create_if_not_exists(
title: 'Twitter - tweet initials',
name: 'ui_ticket_zoom_article_twitter_initials',
area: 'UI::TicketZoom',
description: 'Add sender initials to end of a tweet.',
options: {
form: [
{
display: '',
null: true,
name: 'ui_ticket_zoom_article_twitter_initials',
tag: 'boolean',
translate: true,
options: {
true => 'yes',
false => 'no',
},
},
],
},
state: true,
preferences: {
prio: 300,
permission: ['admin.ui'],
},
frontend: true
)
end
end

View file

@ -546,18 +546,17 @@ Setting.create_if_not_exists(
}, },
frontend: true frontend: true
) )
Setting.create_if_not_exists( Setting.create_if_not_exists(
title: 'Define default visibility of new a new article', title: 'Note - default visibility',
name: 'ui_ticket_zoom_article_new_internal', name: 'ui_ticket_zoom_article_note_new_internal',
area: 'UI::TicketZoom', area: 'UI::TicketZoom',
description: 'Set default visibility of new a new article.', description: 'Default visibility for new note.',
options: { options: {
form: [ form: [
{ {
display: '', display: '',
null: true, null: true,
name: 'ui_ticket_zoom_article_new_internal', name: 'ui_ticket_zoom_article_note_new_internal',
tag: 'boolean', tag: 'boolean',
translate: true, translate: true,
options: { options: {
@ -569,7 +568,61 @@ Setting.create_if_not_exists(
}, },
state: true, state: true,
preferences: { preferences: {
prio: 1, prio: 100,
permission: ['admin.ui'],
},
frontend: true
)
Setting.create_if_not_exists(
title: 'Email - subject field',
name: 'ui_ticket_zoom_article_email_subject',
area: 'UI::TicketZoom',
description: 'Use subject field for emails. If disabled, the ticket title will be used as subject.',
options: {
form: [
{
display: '',
null: true,
name: 'ui_ticket_zoom_article_email_subject',
tag: 'boolean',
translate: true,
options: {
true => 'yes',
false => 'no',
},
},
],
},
state: false,
preferences: {
prio: 200,
permission: ['admin.ui'],
},
frontend: true
)
Setting.create_if_not_exists(
title: 'Twitter - tweet initials',
name: 'ui_ticket_zoom_article_twitter_initials',
area: 'UI::TicketZoom',
description: 'Add sender initials to end of a tweet.',
options: {
form: [
{
display: '',
null: true,
name: 'ui_ticket_zoom_article_twitter_initials',
tag: 'boolean',
translate: true,
options: {
true => 'yes',
false => 'no',
},
},
],
},
state: true,
preferences: {
prio: 300,
permission: ['admin.ui'], permission: ['admin.ui'],
}, },
frontend: true frontend: true

View file

@ -2261,7 +2261,7 @@ wait untill text in selector disabppears
9.times { 9.times {
begin begin
text = instance.find_elements(css: '.content.active .js-reset')[0].text text = instance.find_elements(css: '.content.active .js-reset')[0].text
if !text || text.empty? if text.blank?
screenshot(browser: instance, comment: 'ticket_update_ok') screenshot(browser: instance, comment: 'ticket_update_ok')
sleep 1 sleep 1
return true return true