Improved permanent task highlighting in nav bar.
This commit is contained in:
parent
e6540720a3
commit
81e27f8901
24 changed files with 256 additions and 174 deletions
|
@ -130,6 +130,11 @@ class App.Controller extends Spine.Controller
|
||||||
return if !$('#navigation').is(':visible')
|
return if !$('#navigation').is(':visible')
|
||||||
$('#navigation').addClass('hide')
|
$('#navigation').addClass('hide')
|
||||||
|
|
||||||
|
updateNavMenu: =>
|
||||||
|
delay = ->
|
||||||
|
App.Event.trigger('menu:render')
|
||||||
|
@delay(delay, 200)
|
||||||
|
|
||||||
scrollTo: (x = 0, y = 0, delay = 0) ->
|
scrollTo: (x = 0, y = 0, delay = 0) ->
|
||||||
a = ->
|
a = ->
|
||||||
window.scrollTo(x, y)
|
window.scrollTo(x, y)
|
||||||
|
|
|
@ -6,7 +6,7 @@ class App.ChannelChat extends App.Controller
|
||||||
'click .js-selectBrowserWidth': 'selectBrowserWidth'
|
'click .js-selectBrowserWidth': 'selectBrowserWidth'
|
||||||
'click .js-swatch': 'usePaletteColor'
|
'click .js-swatch': 'usePaletteColor'
|
||||||
'click .js-toggle-chat': 'toggleChat'
|
'click .js-toggle-chat': 'toggleChat'
|
||||||
'click .js-chatSetting': 'toggleChatSetting'
|
'change .js-chatSetting input': 'toggleChatSetting'
|
||||||
'click .js-eyedropper': 'pickColor'
|
'click .js-eyedropper': 'pickColor'
|
||||||
|
|
||||||
elements:
|
elements:
|
||||||
|
@ -307,12 +307,7 @@ class App.ChannelChat extends App.Controller
|
||||||
|
|
||||||
toggleChatSetting: =>
|
toggleChatSetting: =>
|
||||||
value = @chatSetting.prop('checked')
|
value = @chatSetting.prop('checked')
|
||||||
setting = App.Setting.findByAttribute('name', 'chat')
|
App.Setting.set('chat', value)
|
||||||
setting.state_current = { value: value }
|
|
||||||
setting.save()
|
|
||||||
@Config.set('chat', value)
|
|
||||||
delay = -> App.Event.trigger('ui:rerender')
|
|
||||||
@delay(delay, 200)
|
|
||||||
|
|
||||||
updateParams: =>
|
updateParams: =>
|
||||||
quote = (value) ->
|
quote = (value) ->
|
||||||
|
|
|
@ -3,7 +3,7 @@ class App.ChannelForm extends App.Controller
|
||||||
events:
|
events:
|
||||||
'change form.js-params': 'updateParams'
|
'change form.js-params': 'updateParams'
|
||||||
'keyup form.js-params': 'updateParams'
|
'keyup form.js-params': 'updateParams'
|
||||||
'click .js-formSetting': 'toggleFormSetting'
|
'change .js-formSetting input': 'toggleFormSetting'
|
||||||
|
|
||||||
elements:
|
elements:
|
||||||
'.js-paramsBlock': 'paramsBlock'
|
'.js-paramsBlock': 'paramsBlock'
|
||||||
|
@ -16,10 +16,11 @@ class App.ChannelForm extends App.Controller
|
||||||
|
|
||||||
render: =>
|
render: =>
|
||||||
App.Setting.unsubscribe(@subscribeId)
|
App.Setting.unsubscribe(@subscribeId)
|
||||||
setting = App.Setting.findByAttribute('name', 'form_ticket_create')
|
|
||||||
|
setting = App.Setting.get('form_ticket_create')
|
||||||
@html App.view('channel/form')(
|
@html App.view('channel/form')(
|
||||||
baseurl: window.location.origin
|
baseurl: window.location.origin
|
||||||
formSetting: setting.state_current.value
|
formSetting: setting
|
||||||
)
|
)
|
||||||
|
|
||||||
@paramsBlock.each (i, block) ->
|
@paramsBlock.each (i, block) ->
|
||||||
|
@ -49,8 +50,6 @@ class App.ChannelForm extends App.Controller
|
||||||
|
|
||||||
toggleFormSetting: =>
|
toggleFormSetting: =>
|
||||||
value = @formSetting.prop('checked')
|
value = @formSetting.prop('checked')
|
||||||
setting = App.Setting.findByAttribute('name', 'form_ticket_create')
|
App.Setting.set('form_ticket_create', value)
|
||||||
setting.state_current = { value: value }
|
|
||||||
setting.save()
|
|
||||||
|
|
||||||
App.Config.set( 'Form', { prio: 2000, name: 'Form', parent: '#channels', target: '#channels/form', controller: App.ChannelForm, role: ['Admin'] }, 'NavBarAdmin' )
|
App.Config.set( 'Form', { prio: 2000, name: 'Form', parent: '#channels', target: '#channels/form', controller: App.ChannelForm, role: ['Admin'] }, 'NavBarAdmin' )
|
||||||
|
|
|
@ -55,12 +55,7 @@ class App.ControllerIntegrationBase extends App.Controller
|
||||||
msg: App.i18n.translateContent('Update successful!')
|
msg: App.i18n.translateContent('Update successful!')
|
||||||
timeout: 2000
|
timeout: 2000
|
||||||
}
|
}
|
||||||
if @preferences
|
App.Setting.preferencesPost(@)
|
||||||
if @preferences.render
|
|
||||||
App.Event.trigger( 'ui:rerender' )
|
|
||||||
|
|
||||||
if @preferences.session_check
|
|
||||||
App.Auth.loginCheck()
|
|
||||||
|
|
||||||
fail: (settings, details) ->
|
fail: (settings, details) ->
|
||||||
App.Event.trigger 'notify', {
|
App.Event.trigger 'notify', {
|
||||||
|
@ -73,25 +68,4 @@ class App.ControllerIntegrationBase extends App.Controller
|
||||||
|
|
||||||
value =
|
value =
|
||||||
items: [params]
|
items: [params]
|
||||||
App.Setting.set(
|
App.Setting.set(@featureConfig, value)
|
||||||
@featureConfig,
|
|
||||||
value,
|
|
||||||
done: ->
|
|
||||||
App.Event.trigger 'notify', {
|
|
||||||
type: 'success'
|
|
||||||
msg: App.i18n.translateContent('Update successful!')
|
|
||||||
timeout: 2000
|
|
||||||
}
|
|
||||||
if @preferences
|
|
||||||
if @preferences.render
|
|
||||||
App.Event.trigger( 'ui:rerender' )
|
|
||||||
|
|
||||||
if @preferences.session_check
|
|
||||||
App.Auth.loginCheck()
|
|
||||||
fail: (settings, details) ->
|
|
||||||
App.Event.trigger 'notify', {
|
|
||||||
type: 'error'
|
|
||||||
msg: App.i18n.translateContent(details.error_human || details.error || 'Unable to update object!')
|
|
||||||
timeout: 2000
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
|
@ -108,13 +108,8 @@ class App.SettingsAreaItem extends App.Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
# rerender ui || get new collections and session data
|
# rerender ui || get new collections and session data
|
||||||
if @setting.preferences
|
App.Setting.preferencesPost(@setting)
|
||||||
if @setting.preferences.render
|
|
||||||
ui.render()
|
|
||||||
App.Event.trigger( 'ui:rerender' )
|
|
||||||
|
|
||||||
if @setting.preferences.session_check
|
|
||||||
App.Auth.loginCheck()
|
|
||||||
fail: (settings, details) ->
|
fail: (settings, details) ->
|
||||||
ui.formEnable(e)
|
ui.formEnable(e)
|
||||||
App.Event.trigger 'notify', {
|
App.Event.trigger 'notify', {
|
||||||
|
@ -158,10 +153,10 @@ class App.SettingsAreaLogo extends App.Controller
|
||||||
if file.size && file.size > 1024 * 1024 * maxSiteInMb
|
if file.size && file.size > 1024 * 1024 * maxSiteInMb
|
||||||
App.Event.trigger 'notify', {
|
App.Event.trigger 'notify', {
|
||||||
type: 'error'
|
type: 'error'
|
||||||
msg: App.i18n.translateContent('File too big, max. %s MB allowed.', maxSiteInMb )
|
msg: App.i18n.translateContent('File too big, max. %s MB allowed.', maxSiteInMb)
|
||||||
timeout: 2000
|
timeout: 2000
|
||||||
}
|
}
|
||||||
@logoPreview.attr( 'src', '' )
|
@logoPreview.attr('src', '')
|
||||||
return
|
return
|
||||||
|
|
||||||
reader.readAsDataURL(file)
|
reader.readAsDataURL(file)
|
||||||
|
@ -209,4 +204,4 @@ class App.SettingsAreaLogo extends App.Controller
|
||||||
)
|
)
|
||||||
|
|
||||||
# add resized image
|
# add resized image
|
||||||
App.ImageService.resizeForApp( @params.logo, @logoPreview.width(), @logoPreview.height(), store )
|
App.ImageService.resizeForApp(@params.logo, @logoPreview.width(), @logoPreview.height(), store)
|
||||||
|
|
|
@ -72,13 +72,8 @@ class App.SettingsForm extends App.Controller
|
||||||
timeout: 2000
|
timeout: 2000
|
||||||
}
|
}
|
||||||
|
|
||||||
# rerender ui || get new collections and session data
|
# rerender ui || get new collections and session data
|
||||||
if @preferences
|
App.Setting.preferencesPost(@)
|
||||||
if @preferences.render
|
|
||||||
App.Event.trigger( 'ui:rerender' )
|
|
||||||
|
|
||||||
if @preferences.session_check
|
|
||||||
App.Auth.loginCheck()
|
|
||||||
|
|
||||||
fail: (settings, details) ->
|
fail: (settings, details) ->
|
||||||
App.Event.trigger 'notify', {
|
App.Event.trigger 'notify', {
|
||||||
|
|
|
@ -86,8 +86,7 @@ class App.CustomerChat extends App.Controller
|
||||||
)
|
)
|
||||||
|
|
||||||
featureActive: =>
|
featureActive: =>
|
||||||
if @Config.get('chat')
|
return true if @Config.get('chat')
|
||||||
return true
|
|
||||||
false
|
false
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
|
@ -164,6 +163,10 @@ class App.CustomerChat extends App.Controller
|
||||||
@title 'Customer Chat', true
|
@title 'Customer Chat', true
|
||||||
@navupdate '#customer_chat'
|
@navupdate '#customer_chat'
|
||||||
|
|
||||||
|
active: (state) =>
|
||||||
|
return @shown if state is undefined
|
||||||
|
@shown = state
|
||||||
|
|
||||||
counter: =>
|
counter: =>
|
||||||
counter = 0
|
counter = 0
|
||||||
|
|
||||||
|
@ -239,11 +242,6 @@ class App.CustomerChat extends App.Controller
|
||||||
@stopPushState()
|
@stopPushState()
|
||||||
@pushState()
|
@pushState()
|
||||||
|
|
||||||
updateNavMenu: =>
|
|
||||||
delay = ->
|
|
||||||
App.Event.trigger('menu:render')
|
|
||||||
@delay(delay, 200, 'updateNavMenu')
|
|
||||||
|
|
||||||
updateMeta: =>
|
updateMeta: =>
|
||||||
if @meta.waiting_chat_count && @maxChatWindows > @windowCount()
|
if @meta.waiting_chat_count && @maxChatWindows > @windowCount()
|
||||||
@acceptChatElement.addClass('is-clickable is-blinking')
|
@acceptChatElement.addClass('is-clickable is-blinking')
|
||||||
|
|
|
@ -8,6 +8,7 @@ class App.CTI extends App.Controller
|
||||||
return if !@isRole('CTI')
|
return if !@isRole('CTI')
|
||||||
|
|
||||||
@list = []
|
@list = []
|
||||||
|
@backends = []
|
||||||
@meta =
|
@meta =
|
||||||
active: false
|
active: false
|
||||||
counter: 0
|
counter: 0
|
||||||
|
@ -18,40 +19,39 @@ class App.CTI extends App.Controller
|
||||||
|
|
||||||
@load()
|
@load()
|
||||||
|
|
||||||
App.Event.bind(
|
@bind('cti_event', (data) =>
|
||||||
|
if data.direction is 'in'
|
||||||
|
if data.state is 'newCall'
|
||||||
|
if @switch()
|
||||||
|
@notify(data)
|
||||||
|
return if @meta.state[data.id]
|
||||||
|
@meta.state[data.id] = true
|
||||||
|
@meta.counter += 1
|
||||||
|
@updateNavMenu()
|
||||||
|
if data.state is 'answer' || data.state is 'hangup'
|
||||||
|
return if !@meta.state[data.id]
|
||||||
|
delete @meta.state[data.id]
|
||||||
|
@meta.counter -= 1
|
||||||
|
@updateNavMenu()
|
||||||
'cti_event'
|
'cti_event'
|
||||||
(data) =>
|
)
|
||||||
console.log('cti_event', data)
|
@bind('cti_list_push', (data) =>
|
||||||
if data.direction is 'in'
|
if data.assets
|
||||||
if data.state is 'newCall'
|
App.Collection.loadAssets(data.assets)
|
||||||
if @switch()
|
if data.backends
|
||||||
@notify(data)
|
@backends = data.backends
|
||||||
return if @meta.state[data.id]
|
if data.list
|
||||||
@meta.state[data.id] = true
|
@list = data.list
|
||||||
@meta.counter += 1
|
@render()
|
||||||
@updateNavMenu()
|
'cti_list_push'
|
||||||
if data.state is 'answer' || data.state is 'hangup'
|
)
|
||||||
return if !@meta.state[data.id]
|
@bind('auth', (data) =>
|
||||||
delete @meta.state[data.id]
|
@meta.counter = 0
|
||||||
@meta.counter -= 1
|
)
|
||||||
@updateNavMenu()
|
|
||||||
|
|
||||||
'cti_event'
|
@bind('cti:reload', =>
|
||||||
)
|
@load()
|
||||||
App.Event.bind(
|
'cti_reload'
|
||||||
'cti_list_push'
|
|
||||||
(data) =>
|
|
||||||
if data.assets
|
|
||||||
App.Collection.loadAssets(data.assets)
|
|
||||||
if data.list
|
|
||||||
@list = data.list
|
|
||||||
@render()
|
|
||||||
'cti_list_push'
|
|
||||||
)
|
|
||||||
App.Event.bind(
|
|
||||||
'auth'
|
|
||||||
(data) =>
|
|
||||||
@meta.counter = 0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# rerender view, e. g. on langauge change
|
# rerender view, e. g. on langauge change
|
||||||
|
@ -69,6 +69,8 @@ class App.CTI extends App.Controller
|
||||||
success: (data) =>
|
success: (data) =>
|
||||||
if data.assets
|
if data.assets
|
||||||
App.Collection.loadAssets(data.assets)
|
App.Collection.loadAssets(data.assets)
|
||||||
|
if data.backends
|
||||||
|
@backends = data.backends
|
||||||
if data.list
|
if data.list
|
||||||
@list = data.list
|
@list = data.list
|
||||||
@render()
|
@render()
|
||||||
|
@ -82,16 +84,27 @@ class App.CTI extends App.Controller
|
||||||
title: title
|
title: title
|
||||||
)
|
)
|
||||||
|
|
||||||
featureActive: =>
|
featureActive: ->
|
||||||
return true
|
true
|
||||||
return true if @Config.get('sipgate_integration')
|
|
||||||
false
|
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
if !@isRole('CTI')
|
if !@isRole('CTI')
|
||||||
@renderScreenUnauthorized(objectName: 'CTI')
|
@renderScreenUnauthorized(objectName: 'CTI')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# check if min one backend is enabled
|
||||||
|
backendEnabled = false
|
||||||
|
for backend in @backends
|
||||||
|
if backend.enabled
|
||||||
|
backendEnabled = true
|
||||||
|
if !backendEnabled
|
||||||
|
@html App.view('cti/not_configured')(
|
||||||
|
backends: @backends
|
||||||
|
isAdmin: @isRole('Admin')
|
||||||
|
)
|
||||||
|
@updateNavMenu()
|
||||||
|
return
|
||||||
|
|
||||||
format = (time) ->
|
format = (time) ->
|
||||||
# Minutes and seconds
|
# Minutes and seconds
|
||||||
mins = ~~(time / 60)
|
mins = ~~(time / 60)
|
||||||
|
@ -158,6 +171,10 @@ class App.CTI extends App.Controller
|
||||||
@title 'CTI', true
|
@title 'CTI', true
|
||||||
@navupdate '#cti'
|
@navupdate '#cti'
|
||||||
|
|
||||||
|
active: (state) =>
|
||||||
|
return @shown if state is undefined
|
||||||
|
@shown = state
|
||||||
|
|
||||||
counter: =>
|
counter: =>
|
||||||
count = 0
|
count = 0
|
||||||
for item in @list
|
for item in @list
|
||||||
|
@ -182,11 +199,6 @@ class App.CTI extends App.Controller
|
||||||
processData: true
|
processData: true
|
||||||
)
|
)
|
||||||
|
|
||||||
updateNavMenu: =>
|
|
||||||
delay = ->
|
|
||||||
App.Event.trigger('menu:render')
|
|
||||||
@delay(delay, 200, 'updateNavMenu')
|
|
||||||
|
|
||||||
class CTIRouter extends App.ControllerPermanent
|
class CTIRouter extends App.ControllerPermanent
|
||||||
constructor: (params) ->
|
constructor: (params) ->
|
||||||
super
|
super
|
||||||
|
|
|
@ -59,13 +59,11 @@ class App.Dashboard extends App.Controller
|
||||||
@navigate '#clues'
|
@navigate '#clues'
|
||||||
|
|
||||||
active: (state) =>
|
active: (state) =>
|
||||||
@activeState = state
|
return @shown if state is undefined
|
||||||
|
@shown = state
|
||||||
if state
|
if state
|
||||||
@mayBeClues()
|
@mayBeClues()
|
||||||
|
|
||||||
isActive: =>
|
|
||||||
@activeState
|
|
||||||
|
|
||||||
url: ->
|
url: ->
|
||||||
'#dashboard'
|
'#dashboard'
|
||||||
|
|
||||||
|
@ -81,9 +79,6 @@ class App.Dashboard extends App.Controller
|
||||||
# highlight navbar
|
# highlight navbar
|
||||||
@navupdate '#dashboard'
|
@navupdate '#dashboard'
|
||||||
|
|
||||||
hide: ->
|
|
||||||
# no
|
|
||||||
|
|
||||||
changed: ->
|
changed: ->
|
||||||
false
|
false
|
||||||
|
|
||||||
|
@ -112,6 +107,6 @@ class DashboardRouter extends App.ControllerPermanent
|
||||||
persistent: true
|
persistent: true
|
||||||
)
|
)
|
||||||
|
|
||||||
App.Config.set( 'dashboard', DashboardRouter, 'Routes' )
|
App.Config.set('dashboard', DashboardRouter, 'Routes')
|
||||||
App.Config.set( 'Dashboard', { prio: 100, parent: '', name: 'Dashboard', target: '#dashboard', role: ['Agent'], class: 'dashboard' }, 'NavBar' )
|
App.Config.set('Dashboard', { prio: 100, parent: '', name: 'Dashboard', target: '#dashboard', key: 'Dashboard', role: ['Agent'], class: 'dashboard' }, 'NavBar')
|
||||||
App.Config.set( 'Dashboard', { controller: 'Dashboard', authentication: true }, 'permanentTask' )
|
App.Config.set('Dashboard', { controller: 'Dashboard', authentication: true }, 'permanentTask')
|
||||||
|
|
|
@ -1801,11 +1801,6 @@ class CustomerChatRef extends App.Controller
|
||||||
# write state
|
# write state
|
||||||
App.SessionStorage.set('chat_layout_ref', state)
|
App.SessionStorage.set('chat_layout_ref', state)
|
||||||
|
|
||||||
updateNavMenu: =>
|
|
||||||
delay = ->
|
|
||||||
App.Event.trigger('menu:render')
|
|
||||||
@delay(delay, 200)
|
|
||||||
|
|
||||||
testChat: (chat, count) ->
|
testChat: (chat, count) ->
|
||||||
for i in [0..count]
|
for i in [0..count]
|
||||||
text = @questions[Math.floor(Math.random() * @questions.length)].question
|
text = @questions[Math.floor(Math.random() * @questions.length)].question
|
||||||
|
|
|
@ -55,9 +55,10 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||||
@notificationWidget = undefined
|
@notificationWidget = undefined
|
||||||
|
|
||||||
renderMenu: =>
|
renderMenu: =>
|
||||||
items = @getItems( navbar: @Config.get( 'NavBar' ) )
|
items = @getItems( navbar: @Config.get('NavBar') )
|
||||||
|
|
||||||
# apply counter and switch info from persistant controllers (if exists)
|
# apply counter and switch info from persistant controllers (if exists)
|
||||||
|
activeTab = {}
|
||||||
itemsNew = []
|
itemsNew = []
|
||||||
for item in items
|
for item in items
|
||||||
shown = true
|
shown = true
|
||||||
|
@ -70,6 +71,8 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||||
item.counter = worker.counter()
|
item.counter = worker.counter()
|
||||||
if worker.switch
|
if worker.switch
|
||||||
item.switch = worker.switch()
|
item.switch = worker.switch()
|
||||||
|
if worker.active && worker.active()
|
||||||
|
activeTab[item.target] = true
|
||||||
if worker.featureActive
|
if worker.featureActive
|
||||||
if worker.featureActive()
|
if worker.featureActive()
|
||||||
shown = true
|
shown = true
|
||||||
|
@ -80,16 +83,17 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||||
items = itemsNew
|
items = itemsNew
|
||||||
|
|
||||||
# get open tabs to repopen on rerender
|
# get open tabs to repopen on rerender
|
||||||
open_tab = {}
|
openTab = {}
|
||||||
@$('.open').children('a').each( (i,d) ->
|
@$('.open').children('a').each( (i,d) ->
|
||||||
href = $(d).attr('href')
|
href = $(d).attr('href')
|
||||||
open_tab[href] = true
|
openTab[href] = true
|
||||||
)
|
)
|
||||||
|
|
||||||
# render menu
|
# render menu
|
||||||
@$('.js-menu').html App.view('navigation/menu')(
|
@$('.js-menu').html App.view('navigation/menu')(
|
||||||
items: items
|
items: items
|
||||||
open_tab: open_tab
|
openTab: openTab
|
||||||
|
activeTab: activeTab
|
||||||
)
|
)
|
||||||
|
|
||||||
# bind on switch changes and execute it on controller
|
# bind on switch changes and execute it on controller
|
||||||
|
|
|
@ -26,7 +26,6 @@ class App.OrganizationProfile extends App.Controller
|
||||||
meta.head = organization.displayName()
|
meta.head = organization.displayName()
|
||||||
meta.title = organization.displayName()
|
meta.title = organization.displayName()
|
||||||
meta.iconClass = organization.icon()
|
meta.iconClass = organization.icon()
|
||||||
|
|
||||||
meta
|
meta
|
||||||
|
|
||||||
url: =>
|
url: =>
|
||||||
|
@ -41,9 +40,6 @@ class App.OrganizationProfile extends App.Controller
|
||||||
|
|
||||||
render: (organization) =>
|
render: (organization) =>
|
||||||
|
|
||||||
# update taskbar with new meta data
|
|
||||||
App.TaskManager.touch(@task_key)
|
|
||||||
|
|
||||||
if !@doNotLog
|
if !@doNotLog
|
||||||
@doNotLog = 1
|
@doNotLog = 1
|
||||||
@recentView('Organization', @organization_id)
|
@recentView('Organization', @organization_id)
|
||||||
|
@ -55,6 +51,7 @@ class App.OrganizationProfile extends App.Controller
|
||||||
new Object(
|
new Object(
|
||||||
el: elLocal.find('.js-object-container')
|
el: elLocal.find('.js-object-container')
|
||||||
organization: organization
|
organization: organization
|
||||||
|
task_key: @task_key
|
||||||
)
|
)
|
||||||
|
|
||||||
new App.TicketStats(
|
new App.TicketStats(
|
||||||
|
@ -83,6 +80,9 @@ class Object extends App.Controller
|
||||||
|
|
||||||
render: (organization) =>
|
render: (organization) =>
|
||||||
|
|
||||||
|
# update taskbar with new meta data
|
||||||
|
App.TaskManager.touch(@task_key)
|
||||||
|
|
||||||
# get display data
|
# get display data
|
||||||
organizationData = []
|
organizationData = []
|
||||||
for attributeName, attributeConfig of App.Organization.attributesGet('view')
|
for attributeName, attributeConfig of App.Organization.attributesGet('view')
|
||||||
|
@ -117,6 +117,7 @@ class Object extends App.Controller
|
||||||
organization_id: organization.id
|
organization_id: organization.id
|
||||||
container: @el.closest('.content')
|
container: @el.closest('.content')
|
||||||
)
|
)
|
||||||
|
|
||||||
editOrganization = =>
|
editOrganization = =>
|
||||||
new App.ControllerGenericEdit(
|
new App.ControllerGenericEdit(
|
||||||
id: organization.id
|
id: organization.id
|
||||||
|
|
|
@ -29,10 +29,8 @@ class App.TicketOverview extends App.Controller
|
||||||
@delay(update, 2800, 'overview:fetch')
|
@delay(update, 2800, 'overview:fetch')
|
||||||
|
|
||||||
active: (state) =>
|
active: (state) =>
|
||||||
@activeState = state
|
return @shown if state is undefined
|
||||||
|
@shown = state
|
||||||
isActive: =>
|
|
||||||
@activeState
|
|
||||||
|
|
||||||
url: =>
|
url: =>
|
||||||
"#ticket/view/#{@view}"
|
"#ticket/view/#{@view}"
|
||||||
|
@ -399,7 +397,7 @@ class Table extends App.Controller
|
||||||
view: @view
|
view: @view
|
||||||
|
|
||||||
# start bulk action observ
|
# start bulk action observ
|
||||||
@el.append( @bulkForm.el )
|
@el.append(@bulkForm.el)
|
||||||
if @$('.table-overview').find('input[name="bulk"]:checked').length isnt 0
|
if @$('.table-overview').find('input[name="bulk"]:checked').length isnt 0
|
||||||
@bulkForm.show()
|
@bulkForm.show()
|
||||||
|
|
||||||
|
@ -431,7 +429,7 @@ class Table extends App.Controller
|
||||||
ticket_id = $(element).val()
|
ticket_id = $(element).val()
|
||||||
for ticket_id_selected in ticketIDs
|
for ticket_id_selected in ticketIDs
|
||||||
if ticket_id_selected is ticket_id
|
if ticket_id_selected is ticket_id
|
||||||
$(element).attr( 'checked', true )
|
$(element).attr('checked', true)
|
||||||
)
|
)
|
||||||
|
|
||||||
viewmode: (e) =>
|
viewmode: (e) =>
|
||||||
|
@ -591,8 +589,8 @@ class BulkForm extends App.Controller
|
||||||
params.ticket_id = ticket.id
|
params.ticket_id = ticket.id
|
||||||
params.form_id = @form_id
|
params.form_id = @form_id
|
||||||
|
|
||||||
sender = App.TicketArticleSender.findByAttribute( 'name', 'Agent' )
|
sender = App.TicketArticleSender.findByAttribute('name', 'Agent')
|
||||||
type = App.TicketArticleType.find( params['type_id'] )
|
type = App.TicketArticleType.find(params['type_id'])
|
||||||
params.sender_id = sender.id
|
params.sender_id = sender.id
|
||||||
|
|
||||||
if !params['internal']
|
if !params['internal']
|
||||||
|
@ -789,7 +787,7 @@ class TicketOverviewRouter extends App.ControllerPermanent
|
||||||
persistent: true
|
persistent: true
|
||||||
)
|
)
|
||||||
|
|
||||||
App.Config.set( 'ticket/view', TicketOverviewRouter, 'Routes' )
|
App.Config.set('ticket/view', TicketOverviewRouter, 'Routes')
|
||||||
App.Config.set( 'ticket/view/:view', TicketOverviewRouter, 'Routes' )
|
App.Config.set('ticket/view/:view', TicketOverviewRouter, 'Routes')
|
||||||
App.Config.set( 'TicketOverview', { controller: 'TicketOverview', authentication: true }, 'permanentTask' )
|
App.Config.set('TicketOverview', { controller: 'TicketOverview', authentication: true }, 'permanentTask')
|
||||||
App.Config.set( 'TicketOverview', { prio: 1000, parent: '', name: 'Overviews', target: '#ticket/view', role: ['Agent', 'Customer'], class: 'overviews' }, 'NavBar' )
|
App.Config.set('TicketOverview', { prio: 1000, parent: '', name: 'Overviews', target: '#ticket/view', key: 'TicketOverview', role: ['Agent', 'Customer'], class: 'overviews' }, 'NavBar')
|
||||||
|
|
|
@ -8,16 +8,13 @@ class App.UserProfile extends App.Controller
|
||||||
return
|
return
|
||||||
|
|
||||||
# fetch new data if needed
|
# fetch new data if needed
|
||||||
@subscribeId = App.User.full(@user_id, @render)
|
App.User.full(@user_id, @render)
|
||||||
|
|
||||||
# rerender view, e. g. on langauge change
|
# rerender view, e. g. on langauge change
|
||||||
@bind 'ui:rerender', =>
|
@bind 'ui:rerender', =>
|
||||||
return if !@authenticate(true)
|
return if !@authenticate(true)
|
||||||
@render(App.User.fullLocal(@user_id))
|
@render(App.User.fullLocal(@user_id))
|
||||||
|
|
||||||
release: =>
|
|
||||||
App.User.unsubscribe(@subscribeId)
|
|
||||||
|
|
||||||
meta: =>
|
meta: =>
|
||||||
meta =
|
meta =
|
||||||
url: @url()
|
url: @url()
|
||||||
|
@ -43,9 +40,6 @@ class App.UserProfile extends App.Controller
|
||||||
|
|
||||||
render: (user) =>
|
render: (user) =>
|
||||||
|
|
||||||
# update taskbar with new meta data
|
|
||||||
App.TaskManager.touch(@task_key)
|
|
||||||
|
|
||||||
if !@doNotLog
|
if !@doNotLog
|
||||||
@doNotLog = 1
|
@doNotLog = 1
|
||||||
@recentView('User', @user_id)
|
@recentView('User', @user_id)
|
||||||
|
@ -55,8 +49,9 @@ class App.UserProfile extends App.Controller
|
||||||
))
|
))
|
||||||
|
|
||||||
new Object(
|
new Object(
|
||||||
el: elLocal.find('.js-object-container')
|
el: elLocal.find('.js-object-container')
|
||||||
user: user
|
user: user
|
||||||
|
task_key: @task_key
|
||||||
)
|
)
|
||||||
|
|
||||||
new App.TicketStats(
|
new App.TicketStats(
|
||||||
|
@ -70,7 +65,6 @@ class App.UserProfile extends App.Controller
|
||||||
genericObject: user
|
genericObject: user
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Object extends App.Controller
|
class Object extends App.Controller
|
||||||
events:
|
events:
|
||||||
'focusout [contenteditable]': 'update'
|
'focusout [contenteditable]': 'update'
|
||||||
|
@ -86,6 +80,9 @@ class Object extends App.Controller
|
||||||
|
|
||||||
render: (user) =>
|
render: (user) =>
|
||||||
|
|
||||||
|
# update taskbar with new meta data
|
||||||
|
App.TaskManager.touch(@task_key)
|
||||||
|
|
||||||
# get display data
|
# get display data
|
||||||
userData = []
|
userData = []
|
||||||
for attributeName, attributeConfig of App.User.attributesGet('view')
|
for attributeName, attributeConfig of App.User.attributesGet('view')
|
||||||
|
|
|
@ -10,5 +10,29 @@ class App.Setting extends App.Model
|
||||||
@set: (name, value, options = {}) ->
|
@set: (name, value, options = {}) ->
|
||||||
setting = App.Setting.findByAttribute('name', name)
|
setting = App.Setting.findByAttribute('name', name)
|
||||||
setting.state_current.value = value
|
setting.state_current.value = value
|
||||||
|
if !options.done
|
||||||
|
options.done = ->
|
||||||
|
App.Setting.preferencesPost(@)
|
||||||
|
|
||||||
|
if !options.fail
|
||||||
|
options.fail = (settings, details) ->
|
||||||
|
App.Event.trigger 'notify', {
|
||||||
|
type: 'error'
|
||||||
|
msg: App.i18n.translateContent(details.error_human || details.error || 'Unable to update object!')
|
||||||
|
timeout: 2000
|
||||||
|
}
|
||||||
setting.save(options)
|
setting.save(options)
|
||||||
App.Config.set(name, value)
|
App.Config.set(name, value)
|
||||||
|
|
||||||
|
@preferencesPost: (setting) ->
|
||||||
|
return if !setting.preferences
|
||||||
|
if setting.preferences.render
|
||||||
|
App.Event.trigger('ui:rerender')
|
||||||
|
|
||||||
|
if setting.preferences.trigger
|
||||||
|
trigger = setting.preferences.trigger
|
||||||
|
delay = -> App.Event.trigger(trigger)
|
||||||
|
App.Delay.set(delay, 20)
|
||||||
|
|
||||||
|
if setting.preferences.session_check
|
||||||
|
App.Auth.loginCheck()
|
||||||
|
|
10
app/assets/javascripts/app/views/cti/not_configured.jst.eco
Normal file
10
app/assets/javascripts/app/views/cti/not_configured.jst.eco
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<div class="main flex">
|
||||||
|
<h1><%- @T('Caller log') %></h1>
|
||||||
|
<p><%- @T('Sorry, currently is no CTI backend enabled!') %></p>
|
||||||
|
<p><%- @T('We support') %>:</p>
|
||||||
|
<ul>
|
||||||
|
<% for backend in @backends: %>
|
||||||
|
<li><% if @isAdmin: %><a href="<%- backend.url %>"><% end %><%= backend.name %><% if @isAdmin: %></a><% end %>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
|
</div>
|
|
@ -1,6 +1,6 @@
|
||||||
<% for item in @items: %>
|
<% for item in @items: %>
|
||||||
<% if item.child: %>
|
<% if item.child: %>
|
||||||
<div class="dropdown<%- ' open' if @open_tab[item.target] %>">
|
<div class="dropdown<%- ' open' if @openTab[item.target] %>">
|
||||||
<a href="<%= item.target %>" class="menu-item js-<%- item.class %>MenuItem dropdown-toggle" data-toggle="dropdown">
|
<a href="<%= item.target %>" class="menu-item js-<%- item.class %>MenuItem dropdown-toggle" data-toggle="dropdown">
|
||||||
<%- @Icon(item.class, 'menu-item-icon') %>
|
<%- @Icon(item.class, 'menu-item-icon') %>
|
||||||
<span class="menu-item-name flex">
|
<span class="menu-item-name flex">
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<% else: %>
|
<% else: %>
|
||||||
<a class="menu-item js-<%- item.class %>MenuItem" href="<%= item.target %>" data-key="<%- item.key %>">
|
<a class="menu-item js-<%- item.class %>MenuItem <% if @activeTab[item.target]: %>is-active<% end %>" href="<%= item.target %>" data-key="<%- item.key %>">
|
||||||
<%- @Icon(item.class, 'menu-item-icon') %>
|
<%- @Icon(item.class, 'menu-item-icon') %>
|
||||||
<span class="menu-item-name">
|
<span class="menu-item-name">
|
||||||
<%- @T(item.name) %>
|
<%- @T(item.name) %>
|
||||||
|
|
32
app/controllers/cti_controller.rb
Normal file
32
app/controllers/cti_controller.rb
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
class CtiController < ApplicationController
|
||||||
|
before_action :authentication_check
|
||||||
|
|
||||||
|
# list current caller log
|
||||||
|
def index
|
||||||
|
return if deny_if_not_role('CTI')
|
||||||
|
|
||||||
|
backends = [
|
||||||
|
{
|
||||||
|
name: 'sipgate.io',
|
||||||
|
enabled: Setting.get('sipgate_integration'),
|
||||||
|
url: '#system/integration/sipgate',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
result = Cti::Log.log
|
||||||
|
result[:backends] = backends
|
||||||
|
render json: result
|
||||||
|
end
|
||||||
|
|
||||||
|
# set caller log to done
|
||||||
|
def done
|
||||||
|
return if deny_if_not_role('CTI')
|
||||||
|
log = Cti::Log.find(params['id'])
|
||||||
|
log.done = params['done']
|
||||||
|
log.save
|
||||||
|
render json: {}
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -4,23 +4,6 @@ require 'builder'
|
||||||
|
|
||||||
class Integration::SipgateController < ApplicationController
|
class Integration::SipgateController < ApplicationController
|
||||||
|
|
||||||
# list current caller log
|
|
||||||
def index
|
|
||||||
return if !authentication_check
|
|
||||||
return if deny_if_not_role('CTI')
|
|
||||||
render json: Cti::Log.log
|
|
||||||
end
|
|
||||||
|
|
||||||
# set caller log to done
|
|
||||||
def done
|
|
||||||
return if !authentication_check
|
|
||||||
return if deny_if_not_role('CTI')
|
|
||||||
log = Cti::Log.find(params['id'])
|
|
||||||
log.done = params['done']
|
|
||||||
log.save
|
|
||||||
render json: {}
|
|
||||||
end
|
|
||||||
|
|
||||||
# notify about inbound call / block inbound call
|
# notify about inbound call / block inbound call
|
||||||
def in
|
def in
|
||||||
http_log_config facility: 'sipgate.io'
|
http_log_config facility: 'sipgate.io'
|
||||||
|
|
51
app/models/transaction/cti_caller_id_detection.rb
Normal file
51
app/models/transaction/cti_caller_id_detection.rb
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
require 'signature_detection'
|
||||||
|
|
||||||
|
class Transaction::CtiCallerIdDetection
|
||||||
|
|
||||||
|
=begin
|
||||||
|
{
|
||||||
|
object: 'Ticket',
|
||||||
|
type: 'create',
|
||||||
|
object_id: 123,
|
||||||
|
via_web: true,
|
||||||
|
user_id: 123,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
object: 'User',
|
||||||
|
type: 'update',
|
||||||
|
object_id: 123,
|
||||||
|
via_web: true,
|
||||||
|
changes: {
|
||||||
|
'attribute1' => [before, now],
|
||||||
|
'attribute2' => [before, now],
|
||||||
|
}
|
||||||
|
user_id: 123,
|
||||||
|
},
|
||||||
|
=end
|
||||||
|
|
||||||
|
def initialize(item, params = {})
|
||||||
|
@item = item
|
||||||
|
@params = params
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform
|
||||||
|
|
||||||
|
# return if we run import mode
|
||||||
|
return if Setting.get('import_mode')
|
||||||
|
|
||||||
|
if @item[:object] == 'Ticket' && @item[:type] == 'create'
|
||||||
|
ticket = Ticket.lookup(id: @item[:object_id])
|
||||||
|
return if !ticket
|
||||||
|
Cti::CallerId.build(ticket)
|
||||||
|
end
|
||||||
|
|
||||||
|
if @item[:object] == 'User'
|
||||||
|
user = User.lookup(id: @item[:object_id])
|
||||||
|
return if !user
|
||||||
|
Cti::CallerId.build(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
6
config/routes/cti.rb
Normal file
6
config/routes/cti.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Zammad::Application.routes.draw do
|
||||||
|
|
||||||
|
match '/api/v1/cti/log', to: 'cti#index', via: :get
|
||||||
|
match '/api/v1/cti/done/:id', to: 'cti#done', via: :post
|
||||||
|
|
||||||
|
end
|
|
@ -1,7 +1,5 @@
|
||||||
Zammad::Application.routes.draw do
|
Zammad::Application.routes.draw do
|
||||||
|
|
||||||
match '/api/v1/cti/log', to: 'integration/sipgate#index', via: :get
|
|
||||||
match '/api/v1/cti/done/:id', to: 'integration/sipgate#done', via: :post
|
|
||||||
match '/api/v1/sipgate/in', to: 'integration/sipgate#in', via: :post
|
match '/api/v1/sipgate/in', to: 'integration/sipgate#in', via: :post
|
||||||
match '/api/v1/sipgate/out', to: 'integration/sipgate#out', via: :post
|
match '/api/v1/sipgate/out', to: 'integration/sipgate#out', via: :post
|
||||||
|
|
||||||
|
|
15
db/migrate/20160429000001_update_cti.rb
Normal file
15
db/migrate/20160429000001_update_cti.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
class UpdateCti < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
setting = Setting.find_by(name: 'sipgate_integration')
|
||||||
|
if setting
|
||||||
|
setting.preferences = { prio: 1, trigger: 'cti:reload' }
|
||||||
|
setting.save
|
||||||
|
end
|
||||||
|
|
||||||
|
setting = Setting.find_by(name: 'chat')
|
||||||
|
if setting
|
||||||
|
setting.preferences = { trigger: 'menu:render' }
|
||||||
|
setting.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1198,7 +1198,7 @@ Setting.create_if_not_exists(
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
preferences: { render: true },
|
preferences: { trigger: 'menu:render' },
|
||||||
state: false,
|
state: false,
|
||||||
frontend: true
|
frontend: true
|
||||||
)
|
)
|
||||||
|
@ -1851,7 +1851,7 @@ Setting.create_if_not_exists(
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
state: false,
|
state: false,
|
||||||
preferences: { prio: 1 },
|
preferences: { prio: 1, trigger: 'cti:reload' },
|
||||||
frontend: false
|
frontend: false
|
||||||
)
|
)
|
||||||
Setting.create_if_not_exists(
|
Setting.create_if_not_exists(
|
||||||
|
|
Loading…
Reference in a new issue