Refactoring of ticket zoom (less rerendering, just rerender particular area's instant of whole view). Added live broadcasting of tag and links.
This commit is contained in:
parent
65e06eb614
commit
3d878a5547
19 changed files with 449 additions and 276 deletions
|
@ -1117,7 +1117,7 @@ class App.ObserverController extends App.Controller
|
|||
currentAttributes[key] = object[key]
|
||||
if @observeNot
|
||||
for key, value of object
|
||||
if !@observeNot[key] && !_.isFunction(value) && !_.isObject(value)
|
||||
if key isnt 'cid' && !@observeNot[key] && !_.isFunction(value) && !_.isObject(value)
|
||||
currentAttributes[key] = value
|
||||
|
||||
if !@lastAttributres
|
||||
|
@ -1128,13 +1128,13 @@ class App.ObserverController extends App.Controller
|
|||
@log 'debug', 'maybeRender no diff, no rerender'
|
||||
return
|
||||
|
||||
@log 'debug', 'maybeRender.diff', diff
|
||||
@log 'debug', 'maybeRender.diff', diff, @observe, @model
|
||||
@lastAttributres = currentAttributes
|
||||
|
||||
@render(object)
|
||||
@render(object, diff)
|
||||
|
||||
render: (object) =>
|
||||
@log 'debug', 'render', @template, object
|
||||
render: (object, diff) =>
|
||||
@log 'debug', 'render', @template, object, diff
|
||||
@html App.view(@template)(
|
||||
object: object
|
||||
)
|
||||
|
@ -1144,5 +1144,5 @@ class App.ObserverController extends App.Controller
|
|||
|
||||
release: =>
|
||||
#console.trace()
|
||||
@log 'debug', 'release', @object_id, @model
|
||||
@log 'debug', 'release', @object_id, @model, @subscribeId
|
||||
App[@model].unsubscribe(@subscribeId)
|
||||
|
|
|
@ -22,7 +22,6 @@ class App.TicketZoom extends App.Controller
|
|||
@ticket_id = params.ticket_id
|
||||
@article_id = params.article_id
|
||||
@sidebarState = {}
|
||||
@ticketLastAttributes = {}
|
||||
|
||||
# if we are in init task startup, ignore overview_id
|
||||
if !params.init
|
||||
|
@ -51,7 +50,7 @@ class App.TicketZoom extends App.Controller
|
|||
update = =>
|
||||
@fetch(@ticket_id, false)
|
||||
if !@ticketUpdatedAtLastCall || ( new Date(data.updated_at).toString() isnt new Date(@ticketUpdatedAtLastCall).toString() )
|
||||
@delay(update, 1200, "ticket-zoom-#{@ticket_id}")
|
||||
@delay(update, 1100, "ticket-zoom-#{@ticket_id}")
|
||||
)
|
||||
|
||||
# rerender view, e. g. on langauge change
|
||||
|
@ -59,6 +58,98 @@ class App.TicketZoom extends App.Controller
|
|||
@fetch(@ticket_id, true)
|
||||
)
|
||||
|
||||
fetch: (ticket_id, force) ->
|
||||
return if !@Session.get()
|
||||
|
||||
# get data
|
||||
@ajax(
|
||||
id: "ticket_zoom_#{ticket_id}"
|
||||
type: 'GET'
|
||||
url: "#{@apiPath}/tickets/#{ticket_id}?all=true"
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
# check if ticket has changed
|
||||
newTicketRaw = data.assets.Ticket[ticket_id]
|
||||
if @ticketUpdatedAtLastCall && !force
|
||||
|
||||
# return if ticket hasnt changed
|
||||
return if @ticketUpdatedAtLastCall is newTicketRaw.updated_at
|
||||
|
||||
# notify if ticket changed not by my self
|
||||
if newTicketRaw.updated_by_id isnt @Session.get('id')
|
||||
App.TaskManager.notify(@task_key)
|
||||
|
||||
# remember current data
|
||||
@ticketUpdatedAtLastCall = newTicketRaw.updated_at
|
||||
|
||||
@load(data)
|
||||
App.SessionStorage(@key, data)
|
||||
|
||||
if !@doNotLog
|
||||
@doNotLog = 1
|
||||
@recentView('Ticket', ticket_id)
|
||||
|
||||
error: (xhr) =>
|
||||
@renderDone = false
|
||||
statusText = xhr.statusText
|
||||
status = xhr.status
|
||||
detail = xhr.responseText
|
||||
|
||||
# ignore if request is aborted
|
||||
return if statusText is 'abort'
|
||||
|
||||
# if ticket is already loaded, ignore status "0" - network issues e. g. temp. not connection
|
||||
if @ticketUpdatedAtLastCall && status is 0
|
||||
console.log('network issues e. g. temp. not connection', status, statusText, detail)
|
||||
return
|
||||
|
||||
# show error message
|
||||
if status is 401 || statusText is 'Unauthorized'
|
||||
@taskHead = '» ' + App.i18n.translateInline('Unauthorized') + ' «'
|
||||
@taskIconClass = 'diagonal-cross'
|
||||
@renderScreenUnauthorized(objectName: 'Ticket')
|
||||
else if status is 404 || statusText is 'Not Found'
|
||||
@taskHead = '» ' + App.i18n.translateInline('Not Found') + ' «'
|
||||
@taskIconClass = 'diagonal-cross'
|
||||
@renderScreenNotFound(objectName: 'Ticket')
|
||||
else
|
||||
@taskHead = '» ' + App.i18n.translateInline('Error') + ' «'
|
||||
@taskIconClass = 'diagonal-cross'
|
||||
|
||||
if !detail
|
||||
detail = 'General communication error, maybe internet is not available!'
|
||||
@renderScreenError(
|
||||
status: status
|
||||
detail: detail
|
||||
objectName: 'Ticket'
|
||||
)
|
||||
)
|
||||
|
||||
load: (data) =>
|
||||
|
||||
# remember article ids
|
||||
@ticket_article_ids = data.ticket_article_ids
|
||||
|
||||
# remember link
|
||||
@links = data.links
|
||||
|
||||
# remember tags
|
||||
@tags = data.tags
|
||||
|
||||
# get edit form attributes
|
||||
@formMeta = data.form_meta
|
||||
|
||||
# load assets
|
||||
App.Collection.loadAssets(data.assets)
|
||||
|
||||
# get data
|
||||
@ticket = App.Ticket.fullLocal(@ticket_id)
|
||||
@ticket.article = undefined
|
||||
|
||||
# render page
|
||||
@render()
|
||||
|
||||
meta: =>
|
||||
|
||||
# default attributes
|
||||
|
@ -73,14 +164,14 @@ class App.TicketZoom extends App.Controller
|
|||
meta.head = @taskHead
|
||||
|
||||
# set icon and title based on ticket
|
||||
if @ticket
|
||||
@ticket = App.Ticket.fullLocal(@ticket.id)
|
||||
meta.head = @ticket.title
|
||||
meta.title = '#' + @ticket.number + ' - ' + @ticket.title
|
||||
meta.class = "task-state-#{ @ticket.getState() }"
|
||||
if @ticket_id && App.Ticket.exists(@ticket_id)
|
||||
ticket = App.Ticket.find(@ticket_id)
|
||||
meta.head = ticket.title
|
||||
meta.title = "##{ticket.number} - #{ticket.title}"
|
||||
meta.class = "task-state-#{ ticket.getState() }"
|
||||
meta.type = 'task'
|
||||
meta.iconTitle = @ticket.iconTitle()
|
||||
meta.iconClass = @ticket.iconClass()
|
||||
meta.iconTitle = ticket.iconTitle()
|
||||
meta.iconClass = ticket.iconClass()
|
||||
meta
|
||||
|
||||
url: =>
|
||||
|
@ -137,107 +228,9 @@ class App.TicketZoom extends App.Controller
|
|||
@autosaveStop()
|
||||
@positionPageHeaderStop()
|
||||
|
||||
fetch: (ticket_id, force) ->
|
||||
return if !@Session.get()
|
||||
|
||||
# get data
|
||||
@ajax(
|
||||
id: "ticket_zoom_#{ticket_id}"
|
||||
type: 'GET'
|
||||
url: "#{@apiPath}/tickets/#{ticket_id}?full=true"
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
# check if ticket has changed
|
||||
newTicketRaw = data.assets.Ticket[ticket_id]
|
||||
if @ticketUpdatedAtLastCall && !force
|
||||
|
||||
# return if ticket hasnt changed
|
||||
return if @ticketUpdatedAtLastCall is newTicketRaw.updated_at
|
||||
|
||||
# notify if ticket changed not by my self
|
||||
if newTicketRaw.updated_by_id isnt @Session.get('id')
|
||||
App.TaskManager.notify(@task_key)
|
||||
|
||||
# remember current data
|
||||
@ticketUpdatedAtLastCall = newTicketRaw.updated_at
|
||||
|
||||
@load(data, force)
|
||||
App.SessionStorage(@key, data)
|
||||
|
||||
if !@doNotLog
|
||||
@doNotLog = 1
|
||||
@recentView('Ticket', ticket_id)
|
||||
|
||||
# scroll to end of page
|
||||
if force
|
||||
@scrollToBottom()
|
||||
@positionPageHeaderUpdate()
|
||||
|
||||
error: (xhr) =>
|
||||
statusText = xhr.statusText
|
||||
status = xhr.status
|
||||
detail = xhr.responseText
|
||||
|
||||
# ignore if request is aborted
|
||||
if statusText is 'abort'
|
||||
return
|
||||
|
||||
# if ticket is already loaded, ignore status "0" - network issues e. g. temp. not connection
|
||||
if @ticketUpdatedAtLastCall && status is 0
|
||||
console.log('network issues e. g. temp. not connection', status, statusText, detail)
|
||||
return
|
||||
|
||||
# show error message
|
||||
if status is 401 || statusText is 'Unauthorized'
|
||||
@taskHead = '» ' + App.i18n.translateInline('Unauthorized') + ' «'
|
||||
@taskIconClass = 'diagonal-cross'
|
||||
@renderScreenUnauthorized(objectName: 'Ticket')
|
||||
else if status is 404 || statusText is 'Not Found'
|
||||
@taskHead = '» ' + App.i18n.translateInline('Not Found') + ' «'
|
||||
@taskIconClass = 'diagonal-cross'
|
||||
@renderScreenNotFound(objectName: 'Ticket')
|
||||
else
|
||||
@taskHead = '» ' + App.i18n.translateInline('Error') + ' «'
|
||||
@taskIconClass = 'diagonal-cross'
|
||||
|
||||
if !detail
|
||||
detail = 'General communication error, maybe internet is not available!'
|
||||
@renderScreenError(
|
||||
status: status
|
||||
detail: detail
|
||||
objectName: 'Ticket'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
muteTask: =>
|
||||
App.TaskManager.mute(@task_key)
|
||||
|
||||
load: (data, force) =>
|
||||
|
||||
# remember article ids
|
||||
@ticket_article_ids = data.ticket_article_ids
|
||||
|
||||
# remember link
|
||||
@links = data.links
|
||||
|
||||
# remember tags
|
||||
@tags = data.tags
|
||||
|
||||
# get edit form attributes
|
||||
@formMeta = data.form_meta
|
||||
|
||||
# load assets
|
||||
App.Collection.loadAssets(data.assets)
|
||||
|
||||
# get data
|
||||
@ticket = App.Ticket.fullLocal(@ticket_id)
|
||||
@ticket.article = undefined
|
||||
|
||||
# render page
|
||||
@render()
|
||||
|
||||
positionPageHeaderStart: =>
|
||||
|
||||
# init header update needed for safari, scroll event is fired
|
||||
|
@ -281,10 +274,9 @@ class App.TicketZoom extends App.Controller
|
|||
# update taskbar with new meta data
|
||||
App.TaskManager.touch(@task_key)
|
||||
|
||||
@formEnable( @$('.submit') )
|
||||
|
||||
if !@renderDone
|
||||
@renderDone = true
|
||||
@autosaveLast = {}
|
||||
elLocal = $(App.view('ticket_zoom')
|
||||
ticket: @ticket
|
||||
nav: @nav
|
||||
|
@ -294,24 +286,23 @@ class App.TicketZoom extends App.Controller
|
|||
|
||||
new App.TicketZoomOverviewNavigator(
|
||||
el: elLocal.find('.overview-navigator')
|
||||
ticket_id: @ticket.id
|
||||
ticket_id: @ticket_id
|
||||
overview_id: @overview_id
|
||||
)
|
||||
|
||||
new App.TicketZoomTitle(
|
||||
object_id: @ticket.id
|
||||
object_id: @ticket_id
|
||||
overview_id: @overview_id
|
||||
el: elLocal.find('.ticket-title')
|
||||
task_key: @task_key
|
||||
)
|
||||
|
||||
new App.TicketZoomMeta(
|
||||
object_id: @ticket.id
|
||||
object_id: @ticket_id
|
||||
el: elLocal.find('.ticket-meta')
|
||||
)
|
||||
|
||||
new App.TicketZoomAttributeBar(
|
||||
ticket: @ticket
|
||||
el: elLocal.find('.js-attributeBar')
|
||||
overview_id: @overview_id
|
||||
callback: @submit
|
||||
|
@ -322,7 +313,7 @@ class App.TicketZoom extends App.Controller
|
|||
|
||||
@articleNew = new App.TicketZoomArticleNew(
|
||||
ticket: @ticket
|
||||
ticket_id: @ticket.id
|
||||
ticket_id: @ticket_id
|
||||
el: elLocal.find('.article-new')
|
||||
formMeta: @formMeta
|
||||
form_id: @form_id
|
||||
|
@ -333,7 +324,7 @@ class App.TicketZoom extends App.Controller
|
|||
|
||||
@highligher = new App.TicketZoomHighlighter(
|
||||
el: elLocal.find('.highlighter')
|
||||
ticket_id: @ticket.id
|
||||
ticket_id: @ticket_id
|
||||
)
|
||||
|
||||
@articleView = new App.TicketZoomArticleView(
|
||||
|
@ -344,27 +335,20 @@ class App.TicketZoom extends App.Controller
|
|||
ticket_article_ids: @ticket_article_ids
|
||||
)
|
||||
|
||||
# rerender whole sidebar if customer or organization has changed
|
||||
if @ticketLastAttributes.customer_id isnt @ticket.customer_id || @ticketLastAttributes.organization_id isnt @ticket.organization_id
|
||||
if elLocal
|
||||
el = elLocal
|
||||
else
|
||||
el = @el
|
||||
new App.WidgetAvatar(
|
||||
el: el.find('.ticketZoom-header .js-avatar')
|
||||
object_id: @ticket.customer_id
|
||||
size: 50
|
||||
new App.TicketCustomerAvatar(
|
||||
object_id: @ticket_id
|
||||
el: elLocal.find('.ticketZoom-header')
|
||||
)
|
||||
|
||||
@sidebar = new App.TicketZoomSidebar(
|
||||
el: el.find('.tabsSidebar')
|
||||
el: elLocal
|
||||
sidebarState: @sidebarState
|
||||
object_id: @ticket.id
|
||||
object_id: @ticket_id
|
||||
model: 'Ticket'
|
||||
taskGet: @taskGet
|
||||
task_key: @task_key
|
||||
tags: @tags
|
||||
links: @links
|
||||
formMeta: @formMeta
|
||||
markForm: @markForm
|
||||
)
|
||||
|
||||
# render init content
|
||||
|
@ -377,24 +361,34 @@ class App.TicketZoom extends App.Controller
|
|||
ticket_article_ids: @ticket_article_ids
|
||||
)
|
||||
|
||||
if @sidebar
|
||||
|
||||
# update tags
|
||||
if @sidebar.tagWidget
|
||||
@sidebar.tagWidget.reload(@tags)
|
||||
|
||||
# update links
|
||||
if @sidebar.linkWidget
|
||||
@sidebar.linkWidget.reload(@links)
|
||||
|
||||
# scroll to article if given
|
||||
if @article_id && document.getElementById('article-' + @article_id)
|
||||
offset = document.getElementById('article-' + @article_id).offsetTop
|
||||
if @article_id && document.getElementById("article-#{@article_id}")
|
||||
offset = document.getElementById("article-#{@article_id}").offsetTop
|
||||
offset = offset - 45
|
||||
scrollTo = ->
|
||||
@scrollTo(0, offset)
|
||||
@delay(scrollTo, 100, false)
|
||||
|
||||
@ticketLastAttributes = @ticket.attributes()
|
||||
if @shown
|
||||
|
||||
if @shown && !@initDone
|
||||
@initDone = true
|
||||
|
||||
# scroll to end of page
|
||||
# scroll to end if new article has been added
|
||||
if !@last_ticket_article_ids || !_.isEqual(_.sortBy(@last_ticket_article_ids), _.sortBy(@ticket_article_ids))
|
||||
@last_ticket_article_ids = @ticket_article_ids
|
||||
@scrollToBottom()
|
||||
@positionPageHeaderUpdate()
|
||||
|
||||
# observe content header position
|
||||
@positionPageHeaderStart()
|
||||
return if @initDone
|
||||
@initDone = true
|
||||
|
||||
# trigger shown if init shown render
|
||||
App.Event.trigger('ui::ticket::shown', { ticket_id: @ticket_id })
|
||||
|
@ -403,20 +397,27 @@ class App.TicketZoom extends App.Controller
|
|||
@main.scrollTop( @main.prop('scrollHeight') )
|
||||
|
||||
autosaveStop: =>
|
||||
console.log('autosaveStop')
|
||||
@clearDelay('ticket-zoom-form-update')
|
||||
@autosaveLast = {}
|
||||
@el.off('change.local blur.local keyup.local paste.local input.local')
|
||||
|
||||
autosaveStart: =>
|
||||
console.log('autosaveStart')
|
||||
@el.on('change.local blur.local keyup.local paste.local input.local', 'form, .js-textarea', (e) =>
|
||||
@delay(@markForm, 250, 'ticket-zoom-form-update')
|
||||
)
|
||||
@delay(@markForm, 800, 'ticket-zoom-form-update')
|
||||
|
||||
markForm: (force) =>
|
||||
if !@autosaveLast
|
||||
@autosaveLast = @taskGet()
|
||||
update = =>
|
||||
return if !@ticket
|
||||
currentParams = @formCurrent()
|
||||
|
||||
# check changed between last autosave
|
||||
sameAsLastSave = _.isEqual(currentParams, @autosaveLast)
|
||||
return if sameAsLastSave
|
||||
return if !force && sameAsLastSave
|
||||
@autosaveLast = clone(currentParams)
|
||||
|
||||
# update changes in ui
|
||||
|
@ -425,11 +426,6 @@ class App.TicketZoom extends App.Controller
|
|||
@markFormDiff(modelDiff)
|
||||
@taskUpdateAll(modelDiff)
|
||||
|
||||
@el.on('change.local blur.local keyup.local paste.local input.local', 'form, .js-textarea', (e) =>
|
||||
@delay(update, 250, 'ticket-zoom-form-update')
|
||||
)
|
||||
@delay(update, 800, 'ticket-zoom-form-update')
|
||||
|
||||
currentStore: =>
|
||||
return if !@ticket
|
||||
currentStoreTicket = @ticket.attributes()
|
||||
|
@ -534,7 +530,7 @@ class App.TicketZoom extends App.Controller
|
|||
ticketParams = @formParam( @$('.edit') )
|
||||
|
||||
# validate ticket
|
||||
ticket = App.Ticket.fullLocal(@ticket.id)
|
||||
ticket = App.Ticket.find(@ticket_id)
|
||||
|
||||
# reset article - should not be resubmited on next ticket update
|
||||
ticket.article = undefined
|
||||
|
@ -550,13 +546,13 @@ class App.TicketZoom extends App.Controller
|
|||
|
||||
# apply tag changes
|
||||
if attributes[1] is 'tags'
|
||||
if @sidebar && @sidebar.tagWidget
|
||||
if @sidebar && @sidebar.edit && @sidebar.edit.tagWidget
|
||||
tags = content.value.split(',')
|
||||
for tag in tags
|
||||
if content.operator is 'remove'
|
||||
@sidebar.tagWidget.remove(tag)
|
||||
@sidebar.edit.tagWidget.remove(tag)
|
||||
else
|
||||
@sidebar.tagWidget.add(tag)
|
||||
@sidebar.edit.tagWidget.add(tag)
|
||||
|
||||
# apply user changes
|
||||
else if attributes[1] is 'owner_id'
|
||||
|
@ -671,7 +667,7 @@ class App.TicketZoom extends App.Controller
|
|||
|
||||
@autosaveStart()
|
||||
@muteTask()
|
||||
@fetch(ticket.id, true)
|
||||
@fetch(ticket.id, false)
|
||||
|
||||
# enable form
|
||||
@formEnable(e)
|
||||
|
@ -701,7 +697,7 @@ class App.TicketZoom extends App.Controller
|
|||
@$('.js-reset').addClass('hide')
|
||||
|
||||
# reset edit ticket / reset new article
|
||||
App.Event.trigger('ui::ticket::taskReset', { ticket_id: @ticket.id })
|
||||
App.Event.trigger('ui::ticket::taskReset', { ticket_id: @ticket_id })
|
||||
|
||||
# remove change flag on tab
|
||||
@$('.tabsSidebar-tab[data-tab="ticket"]').removeClass('is-changed')
|
||||
|
@ -744,7 +740,7 @@ class TicketZoomRouter extends App.ControllerPermanent
|
|||
shown: true
|
||||
|
||||
App.TaskManager.execute(
|
||||
key: 'Ticket-' + @ticket_id
|
||||
key: "Ticket-#{@ticket_id}"
|
||||
controller: 'TicketZoom'
|
||||
params: clean_params
|
||||
show: true
|
||||
|
|
|
@ -257,6 +257,7 @@ class App.TicketZoomArticleNew extends App.Controller
|
|||
ticket: ticket
|
||||
user: App.Session.get()
|
||||
)
|
||||
if !@subscribeIdTextModule
|
||||
@subscribeIdTextModule = ticket.subscribe(callback)
|
||||
|
||||
params: =>
|
||||
|
|
|
@ -86,6 +86,8 @@ class ArticleViewItem extends App.ObserverController
|
|||
@el.attr('id', "article-#{article.id}")
|
||||
if article.internal
|
||||
@el.addClass('is-internal')
|
||||
else
|
||||
@el.removeClass('is-internal')
|
||||
|
||||
# prepare html body
|
||||
if article.content_type is 'text/html'
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
class App.TicketCustomerAvatar extends App.ObserverController
|
||||
model: 'Ticket'
|
||||
observe:
|
||||
customer_id: true
|
||||
|
||||
render: (ticket) =>
|
||||
new App.WidgetAvatar(
|
||||
el: @el.find('.js-avatar')
|
||||
object_id: ticket.customer_id
|
||||
size: 50
|
||||
)
|
|
@ -1,28 +1,18 @@
|
|||
class App.TicketZoomSidebar extends App.ObserverController
|
||||
class Edit extends App.ObserverController
|
||||
model: 'Ticket'
|
||||
observeNot:
|
||||
created_at: true
|
||||
updated_at: true
|
||||
|
||||
render: (ticket) =>
|
||||
|
||||
editTicket = (el) =>
|
||||
el.append('<form class="edit"></form>')
|
||||
@editEl = el
|
||||
|
||||
show = (ticket) =>
|
||||
el.find('.edit').html('')
|
||||
|
||||
render: (ticket, diff) =>
|
||||
defaults = ticket.attributes()
|
||||
delete defaults.article # ignore article infos
|
||||
taskState = @taskGet('ticket')
|
||||
modelDiff = App.Utils.formDiff(taskState, defaults)
|
||||
|
||||
if !_.isEmpty(taskState)
|
||||
defaults = _.extend(defaults, taskState)
|
||||
|
||||
new App.ControllerForm(
|
||||
el: el.find('.edit')
|
||||
form = new App.ControllerForm(
|
||||
model: App.Ticket
|
||||
screen: 'edit'
|
||||
handlers: [
|
||||
|
@ -32,28 +22,45 @@ class App.TicketZoomSidebar extends App.ObserverController
|
|||
params: defaults
|
||||
#bookmarkable: true
|
||||
)
|
||||
#console.log('Ichanges', modelDiff, taskState, ticket.attributes(), defaults)
|
||||
#@markFormDiff( modelDiff )
|
||||
@html form.html()
|
||||
|
||||
show(ticket)
|
||||
@bind(
|
||||
'ui::ticket::taskReset'
|
||||
(data) ->
|
||||
if data.ticket_id is ticket.id
|
||||
show(ticket)
|
||||
@markForm(true)
|
||||
|
||||
return if @resetBind
|
||||
@resetBind = true
|
||||
@bind('ui::ticket::taskReset', (data) =>
|
||||
return if data.ticket_id isnt ticket.id
|
||||
@render(ticket)
|
||||
)
|
||||
|
||||
class App.TicketZoomSidebar extends App.ObserverController
|
||||
model: 'Ticket'
|
||||
observe:
|
||||
customer_id: true
|
||||
organization_id: true
|
||||
|
||||
render: (ticket) =>
|
||||
|
||||
editTicket = (el) =>
|
||||
el.append('<form><fieldset class="edit"></fieldset></form><div class="tags"></div><div class="links"></div>')
|
||||
|
||||
@edit = new Edit(
|
||||
object_id: ticket.id
|
||||
el: el.find('.edit')
|
||||
taskGet: @taskGet
|
||||
formMeta: @formMeta
|
||||
markForm: @markForm
|
||||
)
|
||||
|
||||
if !@isRole('Customer')
|
||||
el.append('<div class="tags"></div>')
|
||||
@tagWidget = new App.WidgetTag(
|
||||
el: el.find('.tags')
|
||||
el: @el.find('.tags')
|
||||
object_type: 'Ticket'
|
||||
object: ticket
|
||||
tags: @tags
|
||||
)
|
||||
el.append('<div class="links"></div>')
|
||||
@linkWidget = new App.WidgetLink(
|
||||
el: el.find('.links')
|
||||
el: @el.find('.links')
|
||||
object_type: 'Ticket'
|
||||
object: ticket
|
||||
links: @links
|
||||
|
@ -166,7 +173,7 @@ class App.TicketZoomSidebar extends App.ObserverController
|
|||
callback: showOrganization
|
||||
}
|
||||
new App.Sidebar(
|
||||
el: @el
|
||||
el: @el.find('.tabsSidebar')
|
||||
sidebarState: @sidebarState
|
||||
items: @sidebarItems
|
||||
)
|
||||
|
|
|
@ -30,7 +30,13 @@ class App.WidgetLink extends App.Controller
|
|||
@render()
|
||||
)
|
||||
|
||||
reload: (links) ->
|
||||
@links = links
|
||||
@render()
|
||||
|
||||
render: =>
|
||||
return if @lastLinks && _.isEqual(@lastLinks, @links)
|
||||
lastLinks = @links
|
||||
list = {}
|
||||
for item in @links
|
||||
if !list[ item['link_type'] ]
|
||||
|
|
|
@ -29,7 +29,7 @@ class App.WidgetTag extends App.Controller
|
|||
@ajax(
|
||||
id: @key
|
||||
type: 'GET'
|
||||
url: @apiPath + '/tags'
|
||||
url: "#{@apiPath}/tags"
|
||||
data:
|
||||
object: @object_type
|
||||
o_id: @object.id
|
||||
|
@ -39,7 +39,13 @@ class App.WidgetTag extends App.Controller
|
|||
@render()
|
||||
)
|
||||
|
||||
reload: (tags) ->
|
||||
@tags = tags
|
||||
@render()
|
||||
|
||||
render: ->
|
||||
return if @lastTags && _.isEqual(@lastTags, @tags)
|
||||
lastTags = @tags
|
||||
@html App.view('widget/tag')(
|
||||
tags: @tags || [],
|
||||
)
|
||||
|
@ -87,7 +93,7 @@ class App.WidgetTag extends App.Controller
|
|||
|
||||
@ajax(
|
||||
type: 'GET'
|
||||
url: @apiPath + '/tags/add'
|
||||
url: "#{@apiPath}/tags/add"
|
||||
data:
|
||||
object: @object_type
|
||||
o_id: @object.id
|
||||
|
@ -110,7 +116,7 @@ class App.WidgetTag extends App.Controller
|
|||
|
||||
@ajax(
|
||||
type: 'GET'
|
||||
url: @apiPath + '/tags/remove'
|
||||
url: "#{@apiPath}/tags/remove"
|
||||
data:
|
||||
object: @object_type
|
||||
o_id: @object.id
|
||||
|
|
|
@ -65,8 +65,17 @@ class _collectionSingleton extends Spine.Module
|
|||
|
||||
loadAssets: (assets) ->
|
||||
@log 'debug', 'loadAssets', assets
|
||||
|
||||
# proess not existing assets / to avoid not exising ref errors
|
||||
loadAssetsLater = []
|
||||
for type, collections of assets
|
||||
@load(type: type, data: collections)
|
||||
later = @load(type: type, data: collections, later: true)
|
||||
if later
|
||||
loadAssetsLater[type] = later
|
||||
|
||||
# proess existing assets
|
||||
for type, collections of loadAssetsLater
|
||||
App[type].refresh(collections)
|
||||
|
||||
load: (params) ->
|
||||
|
||||
|
@ -81,11 +90,13 @@ class _collectionSingleton extends Spine.Module
|
|||
|
||||
# load full array once
|
||||
if _.isArray(params.data)
|
||||
@log 'debug', 'refresh', params.data
|
||||
appObject.refresh(params.data)
|
||||
return
|
||||
|
||||
# load data from object
|
||||
listToRefresh = []
|
||||
listToRefreshLater = []
|
||||
for key, object of params.data
|
||||
if !params.refresh && appObject
|
||||
@log 'debug', 'refrest try', params.type, key
|
||||
|
@ -93,15 +104,22 @@ class _collectionSingleton extends Spine.Module
|
|||
# check if new object is newer, just load newer objects
|
||||
if object.updated_at && appObject.exists(key)
|
||||
exists = appObject.find(key)
|
||||
objectToLoad = undefined
|
||||
if exists.updated_at
|
||||
if exists.updated_at < object.updated_at
|
||||
listToRefresh.push object
|
||||
objectToLoad = object
|
||||
@log 'debug', 'refrest newser', params.type, key
|
||||
else
|
||||
listToRefresh.push object
|
||||
objectToLoad = object
|
||||
@log 'debug', 'refrest try no updated_at', params.type, key
|
||||
if objectToLoad
|
||||
if params.later
|
||||
listToRefreshLater.push objectToLoad
|
||||
else
|
||||
listToRefresh.push object
|
||||
else
|
||||
listToRefresh.push object
|
||||
@log 'debug', 'refrest new', params.type, key
|
||||
return if _.isEmpty(listToRefresh)
|
||||
return listToRefreshLater if _.isEmpty(listToRefresh)
|
||||
appObject.refresh(listToRefresh)
|
||||
listToRefreshLater
|
||||
|
|
|
@ -347,7 +347,7 @@ class App.Model extends Spine.Model
|
|||
clear: true
|
||||
)
|
||||
|
||||
'Collection::Subscribe::' + @className
|
||||
"Collection::Subscribe::#{@className}"
|
||||
)
|
||||
|
||||
key = @className + '-' + Math.floor( Math.random() * 99999 )
|
||||
|
@ -454,9 +454,9 @@ class App.Model extends Spine.Model
|
|||
if !genericObject || new Date(item.updated_at) >= new Date(genericObject.updated_at)
|
||||
App.Log.debug('Model', "request #{@className}.find(#{item.id}) from server")
|
||||
@full(item.id, false, true)
|
||||
App.Delay.set(callback, 500, item.id, "full-#{@className}")
|
||||
App.Delay.set(callback, 500, item.id, "full-#{@className}-#{item.id}")
|
||||
|
||||
'Item::Subscribe::' + @className
|
||||
"Item::Subscribe::#{@className}"
|
||||
)
|
||||
|
||||
# remember item callback
|
||||
|
|
|
@ -339,6 +339,13 @@ class ApplicationController < ActionController::Base
|
|||
false
|
||||
end
|
||||
|
||||
def article_permission(article)
|
||||
ticket = Ticket.lookup(id: article.ticket_id)
|
||||
return true if ticket.permission(current_user: current_user)
|
||||
response_access_deny
|
||||
false
|
||||
end
|
||||
|
||||
def deny_if_not_role(role_name)
|
||||
return false if role?(role_name)
|
||||
response_access_deny
|
||||
|
@ -445,6 +452,12 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
def model_show_render (object, params)
|
||||
|
||||
if params[:expand]
|
||||
generic_object = object.find(params[:id])
|
||||
model_show_render_item(generic_object)
|
||||
return
|
||||
end
|
||||
|
||||
if params[:full]
|
||||
generic_object_full = object.full(params[:id])
|
||||
render json: generic_object_full, status: :ok
|
||||
|
|
|
@ -19,19 +19,24 @@ class TicketArticlesController < ApplicationController
|
|||
|
||||
# POST /articles
|
||||
def create
|
||||
form_id = params[:ticket_article][:form_id]
|
||||
params[:ticket_article].delete(:form_id)
|
||||
@article = Ticket::Article.new(Ticket::Article.param_validation( params[:ticket_article]))
|
||||
form_id = params[:form_id]
|
||||
|
||||
clean_params = Ticket::Article.param_association_lookup(params)
|
||||
clean_params = Ticket::Article.param_cleanup(clean_params, true)
|
||||
article = Ticket::Article.new(clean_params)
|
||||
|
||||
# permission check
|
||||
return if !article_permission(article)
|
||||
|
||||
# find attachments in upload cache
|
||||
if form_id
|
||||
@article.attachments = Store.list(
|
||||
article.attachments = Store.list(
|
||||
object: 'UploadCache',
|
||||
o_id: form_id,
|
||||
)
|
||||
end
|
||||
|
||||
if @article.save
|
||||
if article.save
|
||||
|
||||
# remove attachments from upload cache
|
||||
Store.remove(
|
||||
|
@ -39,27 +44,34 @@ class TicketArticlesController < ApplicationController
|
|||
o_id: form_id,
|
||||
)
|
||||
|
||||
render json: @article, status: :created
|
||||
render json: article, status: :created
|
||||
else
|
||||
render json: @article.errors, status: :unprocessable_entity
|
||||
render json: article.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
# PUT /articles/1
|
||||
def update
|
||||
@article = Ticket::Article.find(params[:id])
|
||||
|
||||
if @article.update_attributes(Ticket::Article.param_validation(params[:ticket_article]))
|
||||
render json: @article, status: :ok
|
||||
# permission check
|
||||
article = Ticket::Article.find(params[:id])
|
||||
return if !article_permission(article)
|
||||
|
||||
clean_params = Ticket::Article.param_association_lookup(params)
|
||||
clean_params = Ticket::Article.param_cleanup(clean_params, true)
|
||||
|
||||
if article.update_attributes(clean_params)
|
||||
render json: article, status: :ok
|
||||
else
|
||||
render json: @article.errors, status: :unprocessable_entity
|
||||
render json: article.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /articles/1
|
||||
def destroy
|
||||
@article = Ticket::Article.find(params[:id])
|
||||
@article.destroy
|
||||
article = Ticket::Article.find(params[:id])
|
||||
return if !article_permission(article)
|
||||
article.destroy
|
||||
|
||||
head :ok
|
||||
end
|
||||
|
@ -121,18 +133,18 @@ class TicketArticlesController < ApplicationController
|
|||
}
|
||||
end
|
||||
|
||||
# GET /ticket_attachment/1
|
||||
# GET /ticket_attachment/:ticket_id/:article_id/:id
|
||||
def attachment
|
||||
|
||||
# permission check
|
||||
ticket = Ticket.lookup(id: params[:ticket_id])
|
||||
if !ticket_permission(ticket)
|
||||
render(json: 'No such ticket.', status: :unauthorized)
|
||||
render json: 'No such ticket.', status: :unauthorized
|
||||
return
|
||||
end
|
||||
article = Ticket::Article.find(params[:article_id])
|
||||
if ticket.id != article.ticket_id
|
||||
render(json: 'No access, article_id/ticket_id is not matching.', status: :unauthorized)
|
||||
render json: 'No access, article_id/ticket_id is not matching.', status: :unauthorized
|
||||
return
|
||||
end
|
||||
|
||||
|
@ -144,7 +156,7 @@ class TicketArticlesController < ApplicationController
|
|||
end
|
||||
}
|
||||
if !access
|
||||
render(json: 'Requested file id is not linked with article_id.', status: :unauthorized)
|
||||
render json: 'Requested file id is not linked with article_id.', status: :unauthorized
|
||||
return
|
||||
end
|
||||
|
||||
|
@ -163,7 +175,7 @@ class TicketArticlesController < ApplicationController
|
|||
|
||||
# permission check
|
||||
article = Ticket::Article.find(params[:id])
|
||||
return if !ticket_permission(article.ticket)
|
||||
return if !article_permission(article)
|
||||
|
||||
list = Store.list(
|
||||
object: 'Ticket::Article::Mail',
|
||||
|
|
|
@ -41,7 +41,13 @@ class TicketsController < ApplicationController
|
|||
return if !ticket_permission(ticket)
|
||||
|
||||
if params[:full]
|
||||
render json: ticket_full(ticket)
|
||||
full = Ticket.full(params[:id])
|
||||
render json: full
|
||||
return
|
||||
end
|
||||
|
||||
if params[:all]
|
||||
render json: ticket_all(ticket)
|
||||
return
|
||||
end
|
||||
|
||||
|
@ -555,7 +561,7 @@ class TicketsController < ApplicationController
|
|||
)
|
||||
end
|
||||
|
||||
def ticket_full(ticket)
|
||||
def ticket_all(ticket)
|
||||
|
||||
# get attributes to update
|
||||
attributes_to_change = Ticket::ScreenOptions.attributes_to_change(user: current_user, ticket: ticket)
|
||||
|
|
|
@ -1280,6 +1280,24 @@ get assets and record_ids of selector
|
|||
assets
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
touch references by params
|
||||
|
||||
Model.touch_reference_by_params(
|
||||
object: 'Ticket',
|
||||
o_id: 123,
|
||||
)
|
||||
|
||||
=end
|
||||
|
||||
def self.touch_reference_by_params(data)
|
||||
object_class = Kernel.const_get(data[:object])
|
||||
object = object_class.lookup(id: data[:o_id])
|
||||
return if !object
|
||||
object.touch
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def attachments_buffer
|
||||
|
|
|
@ -83,12 +83,20 @@ class Link < ApplicationModel
|
|||
if data.key?(:link_object_source)
|
||||
linkobject = link_object_get(name: data[:link_object_source])
|
||||
data[:link_object_source_id] = linkobject.id
|
||||
touch_reference_by_params(
|
||||
object: data[:link_object_source],
|
||||
o_id: data[:link_object_source_value],
|
||||
)
|
||||
data.delete(:link_object_source)
|
||||
end
|
||||
|
||||
if data.key?(:link_object_target)
|
||||
linkobject = link_object_get(name: data[:link_object_target])
|
||||
data[:link_object_target_id] = linkobject.id
|
||||
touch_reference_by_params(
|
||||
object: data[:link_object_target],
|
||||
o_id: data[:link_object_target_value],
|
||||
)
|
||||
data.delete(:link_object_target)
|
||||
end
|
||||
|
||||
|
@ -130,7 +138,19 @@ class Link < ApplicationModel
|
|||
link_object_target_id: data[:link_object_target_id],
|
||||
link_object_target_value: data[:link_object_target_value]
|
||||
)
|
||||
links.each(&:destroy)
|
||||
|
||||
# touch references
|
||||
links.each {|link|
|
||||
link.destroy
|
||||
touch_reference_by_params(
|
||||
object: Link::Object.lookup(id: link.link_object_source_id).name,
|
||||
o_id: link.link_object_source_value,
|
||||
)
|
||||
touch_reference_by_params(
|
||||
object: Link::Object.lookup(id: link.link_object_target_id).name,
|
||||
o_id: link.link_object_target_value,
|
||||
)
|
||||
}
|
||||
|
||||
# from the other site
|
||||
if data.key?(:link_type)
|
||||
|
@ -144,15 +164,25 @@ class Link < ApplicationModel
|
|||
link_object_source_id: data[:link_object_target_id],
|
||||
link_object_source_value: data[:link_object_target_value]
|
||||
)
|
||||
links.each(&:destroy)
|
||||
|
||||
# touch references
|
||||
links.each {|link|
|
||||
link.destroy
|
||||
touch_reference_by_params(
|
||||
object: Link::Object.lookup(id: link.link_object_source_id).name,
|
||||
o_id: link.link_object_source_value,
|
||||
)
|
||||
touch_reference_by_params(
|
||||
object: Link::Object.lookup(id: link.link_object_target_id).name,
|
||||
o_id: link.link_object_target_value,
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
def self.link_type_get(data)
|
||||
linktype = Link::Type.find_by(name: data[:name])
|
||||
if !linktype
|
||||
linktype = Link::Type.create(
|
||||
name: data[:name]
|
||||
)
|
||||
linktype = Link::Type.create(name: data[:name])
|
||||
end
|
||||
linktype
|
||||
end
|
||||
|
@ -160,9 +190,7 @@ class Link < ApplicationModel
|
|||
def self.link_object_get(data)
|
||||
linkobject = Link::Object.find_by(name: data[:name])
|
||||
if !linkobject
|
||||
linkobject = Link::Object.create(
|
||||
name: data[:name]
|
||||
)
|
||||
linkobject = Link::Object.create(name: data[:name])
|
||||
end
|
||||
linkobject
|
||||
end
|
||||
|
|
|
@ -9,6 +9,19 @@ class Tag < ApplicationModel
|
|||
@@cache_object = {}
|
||||
# rubocop:enable Style/ClassVars
|
||||
|
||||
=begin
|
||||
|
||||
add tags for certain object
|
||||
|
||||
Tag.tag_add(
|
||||
object: 'Ticket',
|
||||
o_id: ticket.id,
|
||||
item: 'some tag',
|
||||
created_by_id: current_user.id,
|
||||
)
|
||||
|
||||
=end
|
||||
|
||||
def self.tag_add(data)
|
||||
|
||||
# lookups
|
||||
|
@ -30,9 +43,25 @@ class Tag < ApplicationModel
|
|||
o_id: data[:o_id],
|
||||
created_by_id: data[:created_by_id],
|
||||
)
|
||||
|
||||
# touch reference
|
||||
touch_reference_by_params(data)
|
||||
true
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
remove tags of certain object
|
||||
|
||||
Tag.tag_add(
|
||||
object: 'Ticket',
|
||||
o_id: ticket.id,
|
||||
item: 'some tag',
|
||||
created_by_id: current_user.id,
|
||||
)
|
||||
|
||||
=end
|
||||
|
||||
def self.tag_remove(data)
|
||||
|
||||
# lookups
|
||||
|
@ -50,9 +79,29 @@ class Tag < ApplicationModel
|
|||
o_id: data[:o_id],
|
||||
)
|
||||
result.each(&:destroy)
|
||||
|
||||
# touch reference
|
||||
touch_reference_by_params(data)
|
||||
true
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
tag list for certain object
|
||||
|
||||
tags = Tag.tag_list(
|
||||
object: 'Ticket',
|
||||
o_id: ticket.id,
|
||||
item: 'some tag',
|
||||
created_by_id: current_user.id,
|
||||
)
|
||||
|
||||
returns
|
||||
|
||||
['tag 1', 'tag2', ...]
|
||||
|
||||
=end
|
||||
|
||||
def self.tag_list(data)
|
||||
tag_object_id_requested = tag_object_lookup(data[:object])
|
||||
tag_search = Tag.where(
|
||||
|
|
|
@ -11,11 +11,11 @@ get all assets / related models for this ticket
|
|||
returns
|
||||
|
||||
result = {
|
||||
:users => {
|
||||
123 => user_model_123,
|
||||
1234 => user_model_1234,
|
||||
}
|
||||
:tickets => [ ticket_model1 ]
|
||||
users: {
|
||||
123: user_model_123,
|
||||
1234: user_model_1234,
|
||||
},
|
||||
tickets: [ ticket_model1 ]
|
||||
}
|
||||
|
||||
=end
|
||||
|
|
Loading…
Reference in a new issue