Implemented issue #195 - Take over attachment on ticket split.
This commit is contained in:
parent
de55dbeb33
commit
75ac4252f3
7 changed files with 128 additions and 104 deletions
|
@ -1,8 +1,7 @@
|
||||||
# coffeelint: disable=camel_case_classes
|
# coffeelint: disable=camel_case_classes
|
||||||
class App.UiElement.richtext
|
class App.UiElement.richtext
|
||||||
@render: (attribute) ->
|
@render: (attribute, params) ->
|
||||||
|
item = $( App.view('generic/richtext')(attribute: attribute) )
|
||||||
item = $( App.view('generic/richtext')( attribute: attribute ) )
|
|
||||||
item.find('[contenteditable]').ce(
|
item.find('[contenteditable]').ce(
|
||||||
mode: attribute.type
|
mode: attribute.type
|
||||||
maxlength: attribute.maxlength
|
maxlength: attribute.maxlength
|
||||||
|
@ -15,42 +14,42 @@ class App.UiElement.richtext
|
||||||
new App[plugin.controller](params)
|
new App[plugin.controller](params)
|
||||||
|
|
||||||
if attribute.upload
|
if attribute.upload
|
||||||
item.append( $( App.view('generic/attachment')( attribute: attribute ) ) )
|
@attachments = []
|
||||||
|
item.append( $( App.view('generic/attachment')(attribute: attribute) ) )
|
||||||
|
|
||||||
renderAttachment = (file) =>
|
renderFile = (file) =>
|
||||||
item.find('.attachments').append( App.view('generic/attachment_item')(
|
item.find('.attachments').append(App.view('generic/attachment_item')(file))
|
||||||
fileName: file.filename
|
@attachments.push file
|
||||||
fileSize: App.Utils.humanFileSize(file.size)
|
|
||||||
store_id: file.store_id
|
if params && params.attachments
|
||||||
))
|
for file in params.attachments
|
||||||
item.on(
|
renderFile(file)
|
||||||
'click'
|
|
||||||
"[data-id=#{file.store_id}]", (e) =>
|
# remove items
|
||||||
|
item.find('.attachments').on('click', '.js-delete', (e) =>
|
||||||
|
id = $(e.currentTarget).data('id')
|
||||||
@attachments = _.filter(
|
@attachments = _.filter(
|
||||||
@attachments,
|
@attachments,
|
||||||
(item) ->
|
(item) ->
|
||||||
return if item.id isnt file.store_id
|
return if item.id.toString() is id.toString()
|
||||||
item
|
item
|
||||||
)
|
)
|
||||||
store_id = $(e.currentTarget).data('id')
|
|
||||||
|
|
||||||
# delete attachment from storage
|
# delete attachment from storage
|
||||||
App.Ajax.request(
|
App.Ajax.request(
|
||||||
type: 'DELETE'
|
type: 'DELETE'
|
||||||
url: "#{App.Config.get('api_path')}/ticket_attachment_upload"
|
url: "#{App.Config.get('api_path')}/ticket_attachment_upload"
|
||||||
data: JSON.stringify(store_id: store_id),
|
data: JSON.stringify(id: id),
|
||||||
processData: false
|
processData: false
|
||||||
)
|
)
|
||||||
|
|
||||||
# remove attachment from dom
|
# remove attachment from dom
|
||||||
element = $(e.currentTarget).closest('.attachments')
|
element = $(e.currentTarget).closest('.attachments')
|
||||||
$(e.currentTarget).closest('.attachment').remove()
|
$(e.currentTarget).closest('.attachment').remove()
|
||||||
# empty .attachment (remove spaces) to keep css working, thanks @mrflix :-o
|
|
||||||
if element.find('.attachment').length == 0
|
if element.find('.attachment').length == 0
|
||||||
element.empty()
|
element.empty()
|
||||||
)
|
)
|
||||||
|
|
||||||
@attachments = []
|
|
||||||
@progressBar = item.find('.attachmentUpload-progressBar')
|
@progressBar = item.find('.attachmentUpload-progressBar')
|
||||||
@progressText = item.find('.js-percentage')
|
@progressText = item.find('.js-percentage')
|
||||||
@attachmentPlaceholder = item.find('.attachmentPlaceholder')
|
@attachmentPlaceholder = item.find('.attachmentPlaceholder')
|
||||||
|
@ -84,7 +83,6 @@ class App.UiElement.richtext
|
||||||
# Called after received response from the server
|
# Called after received response from the server
|
||||||
onCompleted: (response) =>
|
onCompleted: (response) =>
|
||||||
response = JSON.parse(response)
|
response = JSON.parse(response)
|
||||||
@attachments.push response.data
|
|
||||||
|
|
||||||
@attachmentPlaceholder.removeClass('hide')
|
@attachmentPlaceholder.removeClass('hide')
|
||||||
@attachmentUpload.addClass('hide')
|
@attachmentUpload.addClass('hide')
|
||||||
|
@ -93,7 +91,7 @@ class App.UiElement.richtext
|
||||||
@progressBar.width(parseInt(0) + '%')
|
@progressBar.width(parseInt(0) + '%')
|
||||||
@progressText.text('')
|
@progressText.text('')
|
||||||
|
|
||||||
renderAttachment(response.data)
|
renderFile(response.data)
|
||||||
item.find('input').val('')
|
item.find('input').val('')
|
||||||
|
|
||||||
App.Log.debug 'UiElement.richtext', 'upload complete', response.data
|
App.Log.debug 'UiElement.richtext', 'upload complete', response.data
|
||||||
|
@ -111,4 +109,5 @@ class App.UiElement.richtext
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
App.Delay.set(u, 100, undefined, 'form_upload')
|
App.Delay.set(u, 100, undefined, 'form_upload')
|
||||||
|
|
||||||
item
|
item
|
||||||
|
|
|
@ -14,6 +14,8 @@ class App.TicketCreate extends App.Controller
|
||||||
# define default type
|
# define default type
|
||||||
@default_type = 'phone-in'
|
@default_type = 'phone-in'
|
||||||
|
|
||||||
|
@formId = App.ControllerForm.formId()
|
||||||
|
|
||||||
# remember split info if exists
|
# remember split info if exists
|
||||||
@split = ''
|
@split = ''
|
||||||
if @ticket_id && @article_id
|
if @ticket_id && @article_id
|
||||||
|
@ -158,7 +160,7 @@ class App.TicketCreate extends App.Controller
|
||||||
# get data / in case also ticket data for split
|
# get data / in case also ticket data for split
|
||||||
buildScreen: (params) =>
|
buildScreen: (params) =>
|
||||||
|
|
||||||
if !params.ticket_id && !params.article_id
|
if _.isEmpty(params.ticket_id) && _.isEmpty(params.article_id)
|
||||||
if !_.isEmpty(params.customer_id)
|
if !_.isEmpty(params.customer_id)
|
||||||
@render(options: { customer_id: params.customer_id })
|
@render(options: { customer_id: params.customer_id })
|
||||||
return
|
return
|
||||||
|
@ -173,6 +175,7 @@ class App.TicketCreate extends App.Controller
|
||||||
data:
|
data:
|
||||||
ticket_id: params.ticket_id
|
ticket_id: params.ticket_id
|
||||||
article_id: params.article_id
|
article_id: params.article_id
|
||||||
|
form_id: @formId
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
|
|
||||||
|
@ -194,6 +197,9 @@ class App.TicketCreate extends App.Controller
|
||||||
else
|
else
|
||||||
t.body = App.Utils.text2html(a.body)
|
t.body = App.Utils.text2html(a.body)
|
||||||
|
|
||||||
|
# add attachments
|
||||||
|
t.attachments = data.attachments
|
||||||
|
|
||||||
# render page
|
# render page
|
||||||
@render(options: t)
|
@render(options: t)
|
||||||
)
|
)
|
||||||
|
@ -206,18 +212,15 @@ class App.TicketCreate extends App.Controller
|
||||||
params = template.options
|
params = template.options
|
||||||
else if App.TaskManager.get(@task_key) && !_.isEmpty(App.TaskManager.get(@task_key).state)
|
else if App.TaskManager.get(@task_key) && !_.isEmpty(App.TaskManager.get(@task_key).state)
|
||||||
params = App.TaskManager.get(@task_key).state
|
params = App.TaskManager.get(@task_key).state
|
||||||
|
if !_.isEmpty(params['form_id'])
|
||||||
|
@formId = params['form_id']
|
||||||
|
|
||||||
if params['form_id']
|
@html(App.view('agent_ticket_create')(
|
||||||
@form_id = params['form_id']
|
|
||||||
else
|
|
||||||
@form_id = App.ControllerForm.formId()
|
|
||||||
|
|
||||||
@html App.view('agent_ticket_create')(
|
|
||||||
head: 'New Ticket'
|
head: 'New Ticket'
|
||||||
agent: @permissionCheck('ticket.agent')
|
agent: @permissionCheck('ticket.agent')
|
||||||
admin: @permissionCheck('admin')
|
admin: @permissionCheck('admin')
|
||||||
form_id: @form_id
|
form_id: @formId
|
||||||
)
|
))
|
||||||
|
|
||||||
signatureChanges = (params, attribute, attributes, classname, form, ui) =>
|
signatureChanges = (params, attribute, attributes, classname, form, ui) =>
|
||||||
if attribute && attribute.name is 'group_id'
|
if attribute && attribute.name is 'group_id'
|
||||||
|
@ -272,7 +275,7 @@ class App.TicketCreate extends App.Controller
|
||||||
}
|
}
|
||||||
new App.ControllerForm(
|
new App.ControllerForm(
|
||||||
el: @$('.ticket-form-top')
|
el: @$('.ticket-form-top')
|
||||||
form_id: @form_id
|
form_id: @formId
|
||||||
model: App.Ticket
|
model: App.Ticket
|
||||||
screen: 'create_top'
|
screen: 'create_top'
|
||||||
events:
|
events:
|
||||||
|
@ -288,14 +291,14 @@ class App.TicketCreate extends App.Controller
|
||||||
|
|
||||||
new App.ControllerForm(
|
new App.ControllerForm(
|
||||||
el: @$('.article-form-top')
|
el: @$('.article-form-top')
|
||||||
form_id: @form_id
|
form_id: @formId
|
||||||
model: App.TicketArticle
|
model: App.TicketArticle
|
||||||
screen: 'create_top'
|
screen: 'create_top'
|
||||||
params: params
|
params: params
|
||||||
)
|
)
|
||||||
new App.ControllerForm(
|
new App.ControllerForm(
|
||||||
el: @$('.ticket-form-middle')
|
el: @$('.ticket-form-middle')
|
||||||
form_id: @form_id
|
form_id: @formId
|
||||||
model: App.Ticket
|
model: App.Ticket
|
||||||
screen: 'create_middle'
|
screen: 'create_middle'
|
||||||
events:
|
events:
|
||||||
|
@ -310,7 +313,7 @@ class App.TicketCreate extends App.Controller
|
||||||
)
|
)
|
||||||
new App.ControllerForm(
|
new App.ControllerForm(
|
||||||
el: @$('.ticket-form-bottom')
|
el: @$('.ticket-form-bottom')
|
||||||
form_id: @form_id
|
form_id: @formId
|
||||||
model: App.Ticket
|
model: App.Ticket
|
||||||
screen: 'create_bottom'
|
screen: 'create_bottom'
|
||||||
events:
|
events:
|
||||||
|
@ -420,7 +423,7 @@ class App.TicketCreate extends App.Controller
|
||||||
body: params.body
|
body: params.body
|
||||||
type_id: type.id
|
type_id: type.id
|
||||||
sender_id: sender.id
|
sender_id: sender.id
|
||||||
form_id: @form_id
|
form_id: @formId
|
||||||
content_type: 'text/html'
|
content_type: 'text/html'
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -432,7 +435,7 @@ class App.TicketCreate extends App.Controller
|
||||||
body: params.body
|
body: params.body
|
||||||
type_id: type.id
|
type_id: type.id
|
||||||
sender_id: sender.id
|
sender_id: sender.id
|
||||||
form_id: @form_id
|
form_id: @formId
|
||||||
content_type: 'text/html'
|
content_type: 'text/html'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -349,7 +349,7 @@ class LayoutRefCommunicationReply extends App.ControllerContent
|
||||||
|
|
||||||
file = @uploadQueue.shift()
|
file = @uploadQueue.shift()
|
||||||
# console.log "working of", file, "from", @uploadQueue
|
# console.log "working of", file, "from", @uploadQueue
|
||||||
@fakeUpload file.name, file.size, @workOfUploadQueue
|
@fakeUpload(file.name, file.size, @workOfUploadQueue)
|
||||||
|
|
||||||
humanFileSize: (size) ->
|
humanFileSize: (size) ->
|
||||||
i = Math.floor( Math.log(size) / Math.log(1024) )
|
i = Math.floor( Math.log(size) / Math.log(1024) )
|
||||||
|
@ -363,27 +363,27 @@ class LayoutRefCommunicationReply extends App.ControllerContent
|
||||||
@attachmentPlaceholder.removeClass('hide')
|
@attachmentPlaceholder.removeClass('hide')
|
||||||
@attachmentUpload.addClass('hide')
|
@attachmentUpload.addClass('hide')
|
||||||
|
|
||||||
fakeUpload: (fileName, fileSize, callback) ->
|
fakeUpload: (filename, size, callback) ->
|
||||||
@attachmentPlaceholder.addClass('hide')
|
@attachmentPlaceholder.addClass('hide')
|
||||||
@attachmentUpload.removeClass('hide')
|
@attachmentUpload.removeClass('hide')
|
||||||
|
|
||||||
progress = 0
|
progress = 0
|
||||||
duration = fileSize / 1024
|
duration = size / 1024
|
||||||
|
|
||||||
for i in [0..100]
|
for i in [0..100]
|
||||||
setTimeout @updateUploadProgress, i*duration/100 , i
|
setTimeout @updateUploadProgress, i*duration/100 , i
|
||||||
|
|
||||||
setTimeout (=>
|
setTimeout (=>
|
||||||
callback()
|
callback()
|
||||||
@renderAttachment(fileName, fileSize)
|
@renderAttachment(filename, size)
|
||||||
), duration
|
), duration
|
||||||
|
|
||||||
renderAttachment: (fileName, fileSize) =>
|
renderAttachment: (filename, size) =>
|
||||||
@attachments.push([fileName, fileSize])
|
@attachments.push([filename, size])
|
||||||
@attachmentsHolder.append App.view('generic/attachment_item')
|
@attachmentsHolder.append(App.view('generic/attachment_item')
|
||||||
fileName: fileName
|
filename: filename
|
||||||
fileSize: @humanFileSize(fileSize)
|
size: @humanFileSize(size)
|
||||||
|
)
|
||||||
|
|
||||||
App.Config.set( 'layout_ref/communication_reply/:content', LayoutRefCommunicationReply, 'Routes' )
|
App.Config.set( 'layout_ref/communication_reply/:content', LayoutRefCommunicationReply, 'Routes' )
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,7 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||||
controller = new App.ControllerForm(
|
controller = new App.ControllerForm(
|
||||||
el: @$('.recipients')
|
el: @$('.recipients')
|
||||||
model:
|
model:
|
||||||
configure_attributes: configure_attributes,
|
configure_attributes: configure_attributes
|
||||||
)
|
)
|
||||||
|
|
||||||
@$('[data-name="body"]').ce({
|
@$('[data-name="body"]').ce({
|
||||||
|
@ -255,12 +255,13 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||||
})
|
})
|
||||||
|
|
||||||
html5Upload.initialize(
|
html5Upload.initialize(
|
||||||
uploadUrl: App.Config.get('api_path') + '/ticket_attachment_upload',
|
uploadUrl: App.Config.get('api_path') + '/ticket_attachment_upload'
|
||||||
dropContainer: @$('.article-add').get(0),
|
dropContainer: @$('.article-add').get(0)
|
||||||
cancelContainer: @cancelContainer,
|
cancelContainer: @cancelContainer
|
||||||
inputField: @$('.article-attachment input').get(0),
|
inputField: @$('.article-attachment input').get(0)
|
||||||
key: 'File',
|
key: 'File'
|
||||||
data: { form_id: @form_id },
|
data:
|
||||||
|
form_id: @form_id
|
||||||
maxSimultaneousUploads: 1,
|
maxSimultaneousUploads: 1,
|
||||||
onFileAdded: (file) =>
|
onFileAdded: (file) =>
|
||||||
|
|
||||||
|
@ -303,6 +304,8 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@bindAttachmentDelete()
|
||||||
|
|
||||||
# show text module UI
|
# show text module UI
|
||||||
if !@permissionCheck('ticket.customer')
|
if !@permissionCheck('ticket.customer')
|
||||||
textModule = new App.WidgetTextModule(
|
textModule = new App.WidgetTextModule(
|
||||||
|
@ -737,33 +740,29 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||||
@articleNewEdit.parent().removeClass('is-dropTarget') if @dragEventCounter is 0
|
@articleNewEdit.parent().removeClass('is-dropTarget') if @dragEventCounter is 0
|
||||||
|
|
||||||
renderAttachment: (file) =>
|
renderAttachment: (file) =>
|
||||||
@attachmentsHolder.append App.view('generic/attachment_item')
|
@attachmentsHolder.append(App.view('generic/attachment_item')(file))
|
||||||
fileName: file.filename
|
|
||||||
fileSize: @humanFileSize( file.size )
|
bindAttachmentDelete: =>
|
||||||
store_id: file.store_id
|
@attachmentsHolder.on('click', '.js-delete', (e) =>
|
||||||
@attachmentsHolder.on(
|
id = $(e.currentTarget).data('id')
|
||||||
'click'
|
|
||||||
"[data-id=#{file.store_id}]", (e) =>
|
|
||||||
@attachments = _.filter(
|
@attachments = _.filter(
|
||||||
@attachments,
|
@attachments,
|
||||||
(item) ->
|
(item) ->
|
||||||
return if item.id isnt file.store_id
|
return if item.id.toString() is id.toString()
|
||||||
item
|
item
|
||||||
)
|
)
|
||||||
store_id = $(e.currentTarget).data('id')
|
|
||||||
|
|
||||||
# delete attachment from storage
|
# delete attachment from storage
|
||||||
App.Ajax.request(
|
App.Ajax.request(
|
||||||
type: 'DELETE'
|
type: 'DELETE'
|
||||||
url: App.Config.get('api_path') + '/ticket_attachment_upload'
|
url: App.Config.get('api_path') + '/ticket_attachment_upload'
|
||||||
data: JSON.stringify(store_id: store_id)
|
data: JSON.stringify(id: id)
|
||||||
processData: false
|
processData: false
|
||||||
)
|
)
|
||||||
|
|
||||||
# remove attachment from dom
|
# remove attachment from dom
|
||||||
element = $(e.currentTarget).closest('.attachments')
|
element = $(e.currentTarget).closest('.attachments')
|
||||||
$(e.currentTarget).closest('.attachment').remove()
|
$(e.currentTarget).closest('.attachment').remove()
|
||||||
# empty .attachment (remove spaces) to keep css working, thanks @mrflix :-o
|
|
||||||
if element.find('.attachment').length == 0
|
if element.find('.attachment').length == 0
|
||||||
element.empty()
|
element.empty()
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="attachment">
|
<div class="attachment">
|
||||||
<div class="attachment-name"><%= @fileName %></div>
|
<div class="attachment-name"><%= @filename %></div>
|
||||||
<div class="attachment-size"><%= @fileSize %></div>
|
<div class="attachment-size"><%= @humanFileSize(@size) %></div>
|
||||||
<div class="attachment-delete js-delete" data-id="<%= @store_id %>">
|
<div class="attachment-delete js-delete" data-id="<%= @id %>">
|
||||||
<%- @Icon('diagonal-cross') %><%- @T('Delete File') %>
|
<%- @Icon('diagonal-cross') %><%- @T('Delete File') %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -150,13 +150,16 @@ class TicketArticlesController < ApplicationController
|
||||||
|
|
||||||
# DELETE /ticket_attachment_upload
|
# DELETE /ticket_attachment_upload
|
||||||
def ticket_attachment_upload_delete
|
def ticket_attachment_upload_delete
|
||||||
if params[:store_id]
|
|
||||||
Store.remove_item(params[:store_id])
|
if params[:id].present?
|
||||||
|
Store.remove_item(params[:id])
|
||||||
render json: {
|
render json: {
|
||||||
success: true,
|
success: true,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
elsif params[:form_id]
|
end
|
||||||
|
|
||||||
|
if params[:form_id].present?
|
||||||
Store.remove(
|
Store.remove(
|
||||||
object: 'UploadCache',
|
object: 'UploadCache',
|
||||||
o_id: params[:form_id],
|
o_id: params[:form_id],
|
||||||
|
@ -167,7 +170,7 @@ class TicketArticlesController < ApplicationController
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
render json: { message: 'No such store_id or form_id!' }, status: :unprocessable_entity
|
render json: { message: 'No such id or form_id!' }, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
|
|
||||||
# POST /ticket_attachment_upload
|
# POST /ticket_attachment_upload
|
||||||
|
@ -198,7 +201,7 @@ class TicketArticlesController < ApplicationController
|
||||||
render json: {
|
render json: {
|
||||||
success: true,
|
success: true,
|
||||||
data: {
|
data: {
|
||||||
store_id: store.id,
|
id: store.id,
|
||||||
filename: file.original_filename,
|
filename: file.original_filename,
|
||||||
size: store.size,
|
size: store.size,
|
||||||
}
|
}
|
||||||
|
|
|
@ -357,8 +357,28 @@ class TicketsController < ApplicationController
|
||||||
article = Ticket::Article.find(params[:article_id])
|
article = Ticket::Article.find(params[:article_id])
|
||||||
assets = article.assets(assets)
|
assets = article.assets(assets)
|
||||||
|
|
||||||
|
attachments = []
|
||||||
|
if params[:form_id].present?
|
||||||
|
attachments = Store.list(
|
||||||
|
object: 'UploadCache',
|
||||||
|
o_id: params[:form_id],
|
||||||
|
).to_a
|
||||||
|
article.attachments.each do |attachment|
|
||||||
|
next if attachment.preferences['Content-ID'].present?
|
||||||
|
file = Store.add(
|
||||||
|
object: 'UploadCache',
|
||||||
|
o_id: params[:form_id],
|
||||||
|
data: attachment.content,
|
||||||
|
filename: attachment.filename,
|
||||||
|
preferences: attachment.preferences,
|
||||||
|
)
|
||||||
|
attachments.push file
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
render json: {
|
render json: {
|
||||||
assets: assets
|
assets: assets,
|
||||||
|
attachments: attachments,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue