Merge branch 'interface' of github.com:martini/zammad into interface

Conflicts:
	app/assets/javascripts/app/views/navigation.jst.eco
This commit is contained in:
Felix Niklas 2014-07-12 18:47:51 +02:00
commit 08e4204b0d
13 changed files with 216 additions and 452 deletions

View file

@ -6,7 +6,6 @@ class App.DashboardTicket extends App.Controller
constructor: ->
super
@start_page = 1
@navupdate '#'
# set new key
@key = 'ticket_overview_' + @view

View file

@ -88,3 +88,5 @@ class Index extends App.ControllerContent
@el.find( '#sortable-sidebar' ).sortable( dndOptions )
App.Config.set( 'dashboard', Index, 'Routes' )
App.Config.set( 'Dashboard', { prio: 100, parent: '', name: 'Dashboard', target: '#dashboard', role: ['Agent'], class: 'dashboard' }, 'NavBar' )

View file

@ -210,6 +210,11 @@ class App.Navigation extends App.Controller
@delay( searchFunction, 220, 'search' )
)
if !@taskBar
@taskBar = true
new App.TaskbarWidget( el: @el.find('.tasks') )
getItems: (data) ->
navbar = _.values(data.navbar)

View file

@ -1,261 +0,0 @@
class App.TaskWidget extends App.Controller
constructor: ->
super
@render()
# render on generic ui call
@bind 'ui:rerender', => @render()
# render on login
@bind 'auth:login', => @render()
# reset current tasks on logout
@bind 'auth:logout', => @el.html('')
# only do take over check after spool messages are finised
App.Event.bind(
'spool:sent'
=>
@spoolSent = true
# broadcast to other browser instance
App.WebSocket.send(
action: 'broadcast'
event: 'session:takeover'
spool: true
recipient:
user_id: [ App.Session.get( 'id' ) ]
data:
taskbar_id: App.TaskManager.TaskbarId()
)
'task'
)
# session take over message
App.Event.bind(
'session:takeover'
(data) =>
# only if spool messages are already sent
return if !@spoolSent
# check if error message is already shown
if !@error
# only if new client id isnt own client id
if data.taskbar_id isnt App.TaskManager.TaskbarId()
@error = new App.SessionMessage(
title: 'Session'
message: 'Session taken over... please reload page or work with other browser window.'
keyboard: false
backdrop: true
close: true
button: 'Reload application'
forceReload: true
)
@disconnectClient()
'task'
)
render: ->
return if _.isEmpty( @Session.all() )
@html App.view('task_widget')(
taskBarActions: @_getTaskActions()
)
@el.find('.taskbar-items').html('')
new Taskbar(
el: @el.find('.taskbar-items')
)
_getTaskActions: ->
roles = App.Session.get( 'roles' )
navbar = _.values( @Config.get( 'TaskActions' ) )
level1 = []
for item in navbar
if typeof item.callback is 'function'
data = item.callback() || {}
for key, value of data
item[key] = value
if !item.parent
match = 0
if !item.role
match = 1
if !roles && item.role
match = _.include( item.role, 'Anybody' )
if roles
for role in roles
if !match
match = _.include( item.role, role.name )
if match
level1.push item
level1
class Taskbar extends App.Controller
events:
'click [data-type="close"]': 'remove'
constructor: ->
super
@render()
# on window resize
resizeTasksDelay = =>
App.Delay.set( @resizeTasks, 60, 'resizeTasks', 'task' )
$(window).off( 'resize.taskbar' ).on( 'resize.taskbar', resizeTasksDelay )
# render view
@bind 'task:render', => @render()
# reset current tasks on logout
@bind 'auth:logout', => @el.html('')
render: ->
return if _.isEmpty( @Session.all() )
tasks = App.TaskManager.all()
item_list = []
for task in tasks
# collect meta data of task for task bar item
data =
url: '#'
id: false
title: App.i18n.translateInline('Loading...')
head: App.i18n.translateInline('Loading...')
worker = App.TaskManager.worker( task.key )
if worker
meta = worker.meta()
# apply meta data of controller
if meta
for key, value of meta
data[key] = value
# collect new task bar items
item = {}
item.task = task
item.data = data
item_list.push item
# set title
if task.active
@title data.title
@html App.view('task_widget_tasks')(
item_list: item_list
)
@resizeTasks()
dndOptions =
tolerance: 'pointer'
distance: 15
opacity: 0.6
forcePlaceholderSize: true
items: '> a'
update: =>
items = @el.find('> a')
order = []
for item in items
key = $(item).data('key')
if !key
throw "No such key attributes found for task item"
order.push key
App.TaskManager.reorder( order )
@el.sortable( dndOptions )
remove: (e, key = false, force = false) =>
e.preventDefault()
if !key
key = $(e.target).parent().data('key')
if !key
throw "No such key attributes found for task item"
# check if input has changed
worker = App.TaskManager.worker( key )
if !force && worker && worker.changed
if worker.changed()
new Remove(
key: key
ui: @
)
return
# check if active task is closed
currentTask = App.TaskManager.get( key )
tasks = App.TaskManager.all()
active_is_closed = false
for task in tasks
if currentTask.active && task.key is key
active_is_closed = true
# remove task
App.TaskManager.remove( key )
@resizeTasks()
# navigate to next task if needed
tasks = App.TaskManager.all()
if active_is_closed && !_.isEmpty( tasks )
task_last = undefined
for task in tasks
task_last = task
if task_last
worker = App.TaskManager.worker( task_last.key )
if worker
@navigate worker.url()
return
if _.isEmpty( tasks )
@navigate '#'
resizeTasks: ->
width = $('#task .taskbar-items').width()# - $('#task .taskbar-new').width() - 200
task_count = App.TaskManager.all().length
task_size = ( width / task_count ) - 40
elementsOversize = 0
elementsOversizeLeftTotal = 0
$('#task .task').each(
(position, element) ->
widthTask = $(element).width()
if widthTask > task_size
elementsOversize++
else
elementsOversizeLeftTotal += task_size - widthTask
)
addOversize = elementsOversizeLeftTotal / elementsOversize
task_size += addOversize
if task_size < 40
$('#task .task').css('max-width', '40px')
else if task_size < 130
$('#task .task').css('max-width', task_size + 'px')
else
$('#task .task').css('max-width', '130px')
class Remove extends App.ControllerModal
constructor: ->
super
@render()
render: ->
@html App.view('modal')(
title: 'Confirm'
message: 'Tab has changed, you really want to close it?'
close: true
button: 'Close'
)
@modalShow(
backdrop: true,
keyboard: true,
)
submit: (e) =>
@modalHide()
@ui.remove(e, @key, true)
App.Config.set( 'task', App.TaskWidget, 'Widgets' )

View file

@ -0,0 +1,136 @@
class App.TaskbarWidget extends App.Controller
events:
'click [data-type="close"]': 'remove'
constructor: ->
super
@render()
# render on generic ui call
@bind 'ui:rerender', => @render()
# render view
@bind 'task:render', => @render()
# render on login
@bind 'auth:login', => @render()
# reset current tasks on logout
@bind 'auth:logout', => @render()
render: ->
return if _.isEmpty( @Session.all() )
tasks = App.TaskManager.all()
item_list = []
for task in tasks
# collect meta data of task for task bar item
data =
url: '#'
id: false
title: App.i18n.translateInline('Loading...')
head: App.i18n.translateInline('Loading...')
worker = App.TaskManager.worker( task.key )
if worker
meta = worker.meta()
# apply meta data of controller
if meta
for key, value of meta
data[key] = value
# collect new task bar items
item = {}
item.task = task
item.data = data
item_list.push item
# set title
if task.active
@title data.title
@html App.view('task_widget_tasks')(
item_list: item_list
)
dndOptions =
tolerance: 'pointer'
distance: 15
opacity: 0.6
forcePlaceholderSize: true
items: '> a'
update: =>
items = @el.find('> a')
order = []
for item in items
key = $(item).data('key')
if !key
throw "No such key attributes found for task item"
order.push key
App.TaskManager.reorder( order )
@el.sortable( dndOptions )
remove: (e, key = false, force = false) =>
e.preventDefault()
if !key
key = $(e.target).parent().parent().data('key')
if !key
throw "No such key attributes found for task item"
# check if input has changed
worker = App.TaskManager.worker( key )
if !force && worker && worker.changed
if worker.changed()
new Remove(
key: key
ui: @
)
return
# check if active task is closed
currentTask = App.TaskManager.get( key )
tasks = App.TaskManager.all()
active_is_closed = false
for task in tasks
if currentTask.active && task.key is key
active_is_closed = true
# remove task
App.TaskManager.remove( key )
# navigate to next task if needed
tasks = App.TaskManager.all()
if active_is_closed && !_.isEmpty( tasks )
task_last = undefined
for task in tasks
task_last = task
if task_last
worker = App.TaskManager.worker( task_last.key )
if worker
@navigate worker.url()
return
if _.isEmpty( tasks )
@navigate '#'
class Remove extends App.ControllerModal
constructor: ->
super
@render()
render: ->
@html App.view('modal')(
title: 'Confirm'
message: 'Tab has changed, you really want to close it?'
close: true
button: 'Close'
)
@modalShow(
backdrop: true,
keyboard: true,
)
submit: (e) =>
@modalHide()
@ui.remove(e, @key, true)

View file

@ -673,4 +673,4 @@ App.Config.set( 'ticket/view', Index, 'Routes' )
App.Config.set( 'ticket/view/:view', Index, 'Routes' )
#App.Config.set( 'ticket/view/:view/:position/:direction', Router, 'Routes' )
App.Config.set( 'TicketOverview', { prio: 1000, parent: '', name: 'Overviews', target: '#ticket/view', role: ['Agent', 'Customer'] }, 'NavBar' )
App.Config.set( 'TicketOverview', { prio: 1000, parent: '', name: 'Overviews', target: '#ticket/view', role: ['Agent', 'Customer'], class: 'overviews' }, 'NavBar' )

View file

@ -5,8 +5,6 @@ class App.TicketZoom extends App.Controller
# check authentication
return if !@authenticate()
@navupdate '#'
@edit_form = undefined
@ticket_id = params.ticket_id
@article_id = params.article_id
@ -41,6 +39,7 @@ class App.TicketZoom extends App.Controller
@ticket = App.Ticket.retrieve( @ticket.id )
meta.head = @ticket.title
meta.title = '#' + @ticket.number + ' - ' + @ticket.title
meta.class = "level-#{@ticket.priority_id}"
meta
url: =>

View file

@ -5,8 +5,6 @@ class App.UserZoom extends App.Controller
# check authentication
return if !@authenticate()
@navupdate '#'
start = (user) =>
@user = user
@render()
@ -17,6 +15,8 @@ class App.UserZoom extends App.Controller
meta =
url: @url()
id: @user_id
class: "level-1"
if @user
meta.head = @user.displayName()
meta.title = @user.displayName()

View file

@ -0,0 +1,54 @@
class Widget extends App.Controller
constructor: ->
super
@bind()
bind: ->
# only do take over check after spool messages are finised
App.Event.bind(
'spool:sent'
=>
@spoolSent = true
# broadcast to other browser instance
App.WebSocket.send(
action: 'broadcast'
event: 'session:takeover'
spool: true
recipient:
user_id: [ App.Session.get( 'id' ) ]
data:
taskbar_id: App.TaskManager.TaskbarId()
)
'maintenance'
)
# session take over message
App.Event.bind(
'session:takeover'
(data) =>
# only if spool messages are already sent
return if !@spoolSent
# check if error message is already shown
if !@error
# only if new client id isnt own client id
if data.taskbar_id isnt App.TaskManager.TaskbarId()
@error = new App.SessionMessage(
title: 'Session'
message: 'Session taken over... please reload page or work with other browser window.'
keyboard: false
backdrop: true
close: true
button: 'Reload application'
forceReload: true
)
@disconnectClient()
'maintenance'
)
App.Config.set( 'session_taken_over', Widget, 'Widgets' )

View file

@ -147,7 +147,7 @@ class _taskManagerSingleton extends App.Controller
# create div for permanent content
if !$("#content_permanent")[0]
$('#app section').append('<div id="content_permanent" class="content"></div>')
$('#app').append('<div id="content_permanent" class="content"></div>')
# empty static content if task is shown
if active

View file

@ -7,67 +7,9 @@
</div>
<div class="logo" title="<%- @C( 'product_name' ) %>"></div>
<ul id="global-search-result" class="custom-dropdown-menu" role="menu">
<li>
<a href="#ticket/zoom/1" class="task level-1 ticket-popover horizontal center icon-switch" data-id="1" data-original-title="" title="">
<div class="priority icon"></div>
<div class="flex contain-text">
#10001 - Welcome to Zammad! -
<time datetime="2014-07-02T19:18:54.000Z">7 d 13 h</time>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="" class="user user-popover horizontal center icon-switch" data-id="3" data-original-title="" title="">
<div class="user icon"></div>
<div class="flex contain-text">
Felix Niklas
</div>
</a>
</li>
<li>
<a href="" class="user user-popover horizontal center icon-switch" data-id="4" data-original-title="" title="">
<div class="user icon"></div>
<div class="flex contain-text">
Franz Lautner
</div>
</a>
</li>
<li>
<a href="" class="user user-popover horizontal center icon-switch" data-id="2" data-original-title="" title="">
<div class="user icon icon"></div>
<div class="flex contain-text">
Nicole Braun
</div>
</a>
</li>
</ul>
</form>
<ul class="nav navbar-nav">
<li class="dashboard active"><a href="#">Dashboard</a></li>
<% for item in @navbar_left: %>
<% if item.child: %>
<li class="dropdown <% if @open_tab[item.target] : %>open<% end %>">
@ -85,131 +27,13 @@
</ul>
</li>
<% else: %>
<li class="overviews <% if @active_tab[item.target] : %>active<% end %>"><a href="<%= item.target %>"><%- @T( item.name ) %></a></li>
<li class="<%= item.class %> <% if @active_tab[item.target] : %>active<% end %>"><a href="<%= item.target %>"><%- @T( item.name ) %></a></li>
<% end %>
<% end %>
<li class="customers"><a href="#">Customers</a></li>
<li class="customers"><a href="#to_somewhere">Customers</a></li>
</ul>
<div class="tasks flex">
<div class="task level-1 horizontal center">
<div class="priority icon"></div>
<div class="name contain-text flex">Klischee nicht sauber ausgearbeitet</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-2 horizontal center">
<div class="modified priority icon"></div>
<div class="name contain-text flex">Probleme mit Siebdruck</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-3 horizontal center">
<div class="priority icon"></div>
<div class="name contain-text flex">Programmfehler</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-2 horizontal center">
<div class="modified priority icon"></div>
<div class="name contain-text flex">Tonerstaub unter Glasplatte</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-1 horizontal center">
<div class="priority icon"></div>
<div class="name contain-text flex">Programmfehler</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-1 horizontal center">
<div class="modified priority icon"></div>
<div class="name contain-text flex">Super Service!</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-2 horizontal center">
<div class="priority icon"></div>
<div class="name contain-text flex">Probleme mit Siebdruck</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-3 horizontal center">
<div class="priority icon"></div>
<div class="name contain-text flex">Programmfehler</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-2 horizontal center">
<div class="priority icon"></div>
<div class="name contain-text flex">Tonerstaub unter Glasplatte</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-1 horizontal center">
<div class="priority icon"></div>
<div class="name contain-text flex">Programmfehler</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-1 horizontal center">
<div class="priority icon"></div>
<div class="name contain-text flex">Super Service!</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-2 horizontal center">
<div class="priority icon"></div>
<div class="name contain-text flex">Probleme mit Siebdruck</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-3 horizontal center">
<div class="priority icon"></div>
<div class="name contain-text flex">Programmfehler</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-2 horizontal center">
<div class="priority icon"></div>
<div class="name contain-text flex">Tonerstaub unter Glasplatte</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-1 horizontal center">
<div class="priority icon"></div>
<div class="name contain-text flex">Programmfehler</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
<div class="task level-1 horizontal center">
<div class="priority icon"></div>
<div class="name contain-text flex">Super Service!</div>
<div class="close-task button horizontal centered">
<div class="close icon close-task"></div>
</div>
</div>
</div>
<script>
$('.task').click(function(){ $(this).toggleClass('active') })
</script>
<!-- <div class="spinner"></div> -->
<div class="tasks flex"></div>
<% if !_.isEmpty(@user): %>
<ul class="user-menu horizontal stretch">

View file

@ -1,3 +1,9 @@
<% for item in @item_list: %>
<a href="<%- item.data.url %>" title="<%= item.data.title %>" class="btn btn-small <% if item.task.active: %>active btn-primary<% else if item.task.notify: %>active btn-warning<% else: %>btn-default<% end %>" data-key="<%- item.task.key %>"><span class="task"><%= item.data.head %></span><span data-type="close" class="glyphicon glyphicon-remove-circle" title="<%- @T('close') %>"></a>
<a href="<%- item.data.url %>" title="<%= item.data.title %>" class="task <%= item.data.class %> horizontal center <% if item.task.active: %>active<% end %>" data-key="<%- item.task.key %>">
<div class="priority icon <% if item.task.notify: %>modified<% end %>"></div>
<div class="name contain-text flex"><%= item.data.head %></div>
<div class="close-task button horizontal centered">
<div class="close-task icon" title="<%- @T('close') %>" data-type="close"></div>
</div>
</a>
<% end %>