Merge branch 'develop' of git.znuny.com:zammad/zammad into develop
This commit is contained in:
commit
72cef05b9e
9 changed files with 721 additions and 37 deletions
50
.gitignore
vendored
50
.gitignore
vendored
|
@ -4,49 +4,51 @@
|
|||
# or operating system, you probably want to add a global ignore instead:
|
||||
# git config --global core.excludesfile ~/.gitignore_global
|
||||
|
||||
# Ignore .swp files
|
||||
.*.swp
|
||||
|
||||
# Ignore bundler config
|
||||
/.bundle
|
||||
|
||||
# Ignore mac stuff
|
||||
.DS_Store
|
||||
|
||||
# Ignore Rubymine config
|
||||
/.idea
|
||||
|
||||
# Ignore .project files
|
||||
/.project
|
||||
|
||||
# Ignore .rbenv-vars
|
||||
/.rbenv-vars
|
||||
|
||||
# Ignore database config
|
||||
/config/database.yml
|
||||
|
||||
# Ignore coverage stuff
|
||||
/coverage
|
||||
|
||||
# Ignore the default SQLite database.
|
||||
/db/*.sqlite3
|
||||
|
||||
# Ignore local changes to schema.rb (e. g. through extentions)
|
||||
/db/schema.rb
|
||||
|
||||
# Ignore custom gem file
|
||||
/Gemfile.local
|
||||
|
||||
# Ignore node modules
|
||||
/node_modules
|
||||
|
||||
# Ignore all logfiles and tempfiles.
|
||||
/log
|
||||
/tmp/*
|
||||
/tmp/pids/*
|
||||
/public/assets/*.*
|
||||
/public/assets/app
|
||||
/public/assets/custom
|
||||
/tmp/*
|
||||
/tmp/pids/*
|
||||
|
||||
# except /tmp/pids/ which is needed for certain Zammad processes
|
||||
!/tmp
|
||||
!/tmp/pids
|
||||
!/tmp/pids/.keep
|
||||
|
||||
# Ignore custom gem file
|
||||
/Gemfile.local
|
||||
|
||||
# Ignore .project files
|
||||
/.project
|
||||
|
||||
# Ignore local database settings
|
||||
/config/database.yml
|
||||
|
||||
# Ignore mac stuff
|
||||
.DS_Store
|
||||
|
||||
# Ignore .swp files
|
||||
.*.swp
|
||||
|
||||
# Ignore coverage stuff
|
||||
/coverage
|
||||
|
||||
# Ignore Rubymine config
|
||||
/.idea
|
||||
node_modules
|
||||
|
|
4
Gemfile
4
Gemfile
|
@ -12,6 +12,7 @@ gem 'activerecord-session_store'
|
|||
gem 'json'
|
||||
|
||||
# Supported DBs
|
||||
gem 'activerecord-nulldb-adapter', group: :nulldb
|
||||
gem 'mysql2', group: :mysql
|
||||
gem 'pg', group: :postgres
|
||||
|
||||
|
@ -113,7 +114,8 @@ group :development, :test do
|
|||
gem 'github_changelog_generator'
|
||||
end
|
||||
|
||||
gem 'puma'
|
||||
gem 'puma', group: :puma
|
||||
gem 'unicorn', group: :unicorn
|
||||
|
||||
# load onw gem's
|
||||
local_gemfile = File.join(File.dirname(__FILE__), 'Gemfile.local')
|
||||
|
|
|
@ -30,6 +30,8 @@ GEM
|
|||
activemodel (= 4.2.7.1)
|
||||
activesupport (= 4.2.7.1)
|
||||
arel (~> 6.0)
|
||||
activerecord-nulldb-adapter (0.3.6)
|
||||
activerecord (>= 2.0.0)
|
||||
activerecord-session_store (1.0.0)
|
||||
actionpack (>= 4.0, < 5.1)
|
||||
activerecord (>= 4.0, < 5.1)
|
||||
|
@ -152,6 +154,7 @@ GEM
|
|||
inflection (1.0.0)
|
||||
json (1.8.3)
|
||||
jwt (1.5.4)
|
||||
kgio (2.11.0)
|
||||
koala (2.4.0)
|
||||
addressable
|
||||
faraday
|
||||
|
@ -271,6 +274,7 @@ GEM
|
|||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rainbow (2.1.0)
|
||||
raindrops (0.17.0)
|
||||
rake (11.2.2)
|
||||
rb-fsevent (0.9.7)
|
||||
rb-inotify (0.9.7)
|
||||
|
@ -371,6 +375,9 @@ GEM
|
|||
unf_ext
|
||||
unf_ext (0.0.7.2)
|
||||
unicode-display_width (1.1.1)
|
||||
unicorn (5.2.0)
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
websocket (1.2.3)
|
||||
writeexcel (1.0.5)
|
||||
zendesk_api (1.14.0)
|
||||
|
@ -385,6 +392,7 @@ PLATFORMS
|
|||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
activerecord-nulldb-adapter
|
||||
activerecord-session_store
|
||||
autoprefixer-rails
|
||||
biz
|
||||
|
@ -447,6 +455,7 @@ DEPENDENCIES
|
|||
therubyracer
|
||||
twitter
|
||||
uglifier
|
||||
unicorn
|
||||
writeexcel
|
||||
zendesk_api
|
||||
|
||||
|
|
|
@ -1,13 +1,372 @@
|
|||
class App.TicketOverview extends App.Controller
|
||||
className: 'overviews'
|
||||
activeFocus: 'nav'
|
||||
mouse:
|
||||
x: null
|
||||
y: null
|
||||
|
||||
elements:
|
||||
'.js-batch-overlay': 'batchOverlay'
|
||||
'.js-batch-overlay-backdrop': 'batchOverlayBackdrop'
|
||||
'.js-batch-cancel': 'batchCancel'
|
||||
'.js-batch-macro-circle': 'batchMacroCircle'
|
||||
'.js-batch-assign-circle': 'batchAssignCircle'
|
||||
'.js-batch-assign': 'batchAssign'
|
||||
'.js-batch-macro': 'batchMacro'
|
||||
|
||||
events:
|
||||
'mousedown .item': 'startDragItem'
|
||||
'mouseenter .js-batch-overlay-entry': 'highlightBatchEntry'
|
||||
'mouseleave .js-batch-overlay-entry': 'unhighlightBatchEntry'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
@render()
|
||||
|
||||
startDragItem: (event) ->
|
||||
@grabbedItem = $(event.currentTarget)
|
||||
offset = @grabbedItem.offset()
|
||||
@batchDragger = $(App.view('ticket_overview/batch_dragger')())
|
||||
@grabbedItemClone = @grabbedItem.clone()
|
||||
@grabbedItemClone.data('offset', @grabbedItem.offset())
|
||||
@grabbedItemClone.addClass('batch-dragger-item js-main-item')
|
||||
@batchDragger.append @grabbedItemClone
|
||||
|
||||
@batchDragger.data
|
||||
startX: event.pageX
|
||||
startY: event.pageY
|
||||
dx: Math.min(event.pageX - offset.left, 180)
|
||||
dy: event.pageY - offset.top
|
||||
moved: false
|
||||
|
||||
$(document).on 'mousemove.item', @dragItem
|
||||
$(document).one 'mouseup.item', @endDragItem
|
||||
# TODO: fire @cancelDrag on ESC
|
||||
|
||||
dragItem: (event) =>
|
||||
event.preventDefault()
|
||||
pos = @batchDragger.data()
|
||||
threshold = 3
|
||||
x = event.pageX - pos.dx
|
||||
y = event.pageY - pos.dy
|
||||
dir = if event.pageY > pos.startY then 1 else -1
|
||||
|
||||
if !pos.moved
|
||||
if Math.abs(event.pageX - pos.startX) > threshold or Math.abs(event.pageY - pos.startY) > threshold
|
||||
@batchDragger.data 'moved', true
|
||||
# check grabbed items batch checkbox to make sure its checked
|
||||
# (could be grabbed without checking the checkbox it)
|
||||
@grabbedItemWasntChecked = !@grabbedItem.find('[name="bulk"]').prop('checked')
|
||||
@grabbedItem.find('[name="bulk"]').prop('checked', true)
|
||||
@grabbedItemClone.find('[name="bulk"]').prop('checked', true)
|
||||
|
||||
additionalItems = @el.find('[name="bulk"]:checked').parents('.item').not(@grabbedItem)
|
||||
additionalItemsClones = additionalItems.clone()
|
||||
@draggedItems = @grabbedItemClone.add(additionalItemsClones)
|
||||
# store offsets for later use
|
||||
additionalItemsClones.each (i, item) -> $(@).data('offset', additionalItems.eq(i).offset())
|
||||
@batchDragger.prepend additionalItemsClones.addClass('batch-dragger-item').get().reverse()
|
||||
if(additionalItemsClones.length)
|
||||
@batchDragger.find('.js-batch-dragger-count').text(@draggedItems.length)
|
||||
|
||||
$('#app').append @batchDragger
|
||||
|
||||
@draggedItems.each (i, item) =>
|
||||
dx = $(item).data('offset').left - $(item).offset().left - x
|
||||
dy = $(item).data('offset').top - $(item).offset().top - y
|
||||
$.Velocity.hook item, 'translateX', "#{dx}px"
|
||||
$.Velocity.hook item, 'translateY', "#{dy}px"
|
||||
|
||||
@moveDraggedItems(-dir)
|
||||
|
||||
@mouseY = event.pageY
|
||||
@showBatchOverlay()
|
||||
else
|
||||
return
|
||||
|
||||
$.Velocity.hook @batchDragger, 'translateX', "#{x}px"
|
||||
$.Velocity.hook @batchDragger, 'translateY', "#{y}px"
|
||||
|
||||
endDragItem: (event) =>
|
||||
$(document).off 'mousemove.item'
|
||||
$(document).off 'mouseup.item'
|
||||
pos = @batchDragger.data()
|
||||
|
||||
if !@hoveredBatchEntry
|
||||
@cleanUpDrag()
|
||||
return
|
||||
|
||||
$.Velocity.hook @batchDragger, 'transformOriginX', "#{pos.dx}px"
|
||||
$.Velocity.hook @batchDragger, 'transformOriginY', "#{pos.dy}px"
|
||||
@hoveredBatchEntry.velocity
|
||||
properties:
|
||||
scale: 1.1
|
||||
options:
|
||||
duration: 200
|
||||
complete: =>
|
||||
@hoveredBatchEntry.velocity "reverse",
|
||||
duration: 200
|
||||
complete: =>
|
||||
# clean scale
|
||||
@hoveredBatchEntry.removeAttr('style')
|
||||
@cleanUpDrag(true)
|
||||
@performBatchAction @hoveredBatchEntry.attr('data-action')
|
||||
@hoveredBatchEntry = null
|
||||
@batchDragger.velocity
|
||||
properties:
|
||||
scale: 0
|
||||
options:
|
||||
duration: 200
|
||||
|
||||
cancelDrag: ->
|
||||
$(document).off 'mousemove.item'
|
||||
$(document).off 'mouseup.item'
|
||||
@cleanUpDrag()
|
||||
|
||||
cleanUpDrag: (success) ->
|
||||
@hideBatchOverlay()
|
||||
$('.batch-dragger').remove()
|
||||
|
||||
if @grabbedItemWasntChecked
|
||||
@grabbedItem.find('[name="bulk"]').prop('checked', false)
|
||||
|
||||
if success
|
||||
# uncheck all checked items
|
||||
@el.find('[name="bulk"]:checked').prop('checked', false)
|
||||
@el.find('[name="bulk_all"]').prop('checked', false)
|
||||
|
||||
moveDraggedItems: (dir) ->
|
||||
@draggedItems.velocity
|
||||
properties:
|
||||
translateX: 0
|
||||
translateY: (i) => dir * i * @batchDragger.height()/2
|
||||
options:
|
||||
easing: 'ease-in-out'
|
||||
duration: 300
|
||||
|
||||
@batchDragger.find('.js-batch-dragger-count').velocity
|
||||
properties:
|
||||
translateY: if dir < 0 then 0 else -@batchDragger.height()+8
|
||||
options:
|
||||
easing: 'ease-in-out'
|
||||
duration: 300
|
||||
|
||||
performBatchAction: (action) ->
|
||||
console.log "perform action #{action} on checked items"
|
||||
|
||||
showBatchOverlay: ->
|
||||
@batchOverlay.show()
|
||||
@batchOverlayBackdrop.velocity { opacity: [1, 0] }, { duration: 500 }
|
||||
@batchOverlayShown = true
|
||||
$(document).on 'mousemove.batchoverlay', @controlBatchOverlay
|
||||
|
||||
hideBatchOverlay: ->
|
||||
$(document).off 'mousemove.batchoverlay'
|
||||
@batchOverlayShown = false
|
||||
@batchOverlayBackdrop.velocity { opacity: [0, 1] }, { duration: 300, queue: false }
|
||||
@hideBatchCircles =>
|
||||
@batchOverlay.hide()
|
||||
|
||||
if @batchAssignShown
|
||||
@hideBatchAssign()
|
||||
|
||||
if @batchMacroShown
|
||||
@hideBatchMacro()
|
||||
|
||||
controlBatchOverlay: (event) =>
|
||||
# store to detect if the mouse is hovering a drag-action entry
|
||||
# after an animation ended -> @highlightBatchEntryAtMousePosition
|
||||
@mouse.x = event.pageX
|
||||
@mouse.y = event.pageY
|
||||
|
||||
if event.pageY <= window.innerHeight/5*2
|
||||
mouseInArea = 'top'
|
||||
else if event.pageY > window.innerHeight/5*2 && event.pageY <= window.innerHeight/5*3
|
||||
mouseInArea = 'middle'
|
||||
else
|
||||
mouseInArea = 'bottom'
|
||||
|
||||
switch mouseInArea
|
||||
when 'top'
|
||||
if !@batchMacroShown
|
||||
@hideBatchCircles()
|
||||
@showBatchMacro()
|
||||
@moveDraggedItems(1)
|
||||
|
||||
when 'middle'
|
||||
if @batchAssignShown
|
||||
@hideBatchAssign()
|
||||
|
||||
if @batchMacroShown
|
||||
@hideBatchMacro()
|
||||
|
||||
if !@batchCirclesShown
|
||||
@showBatchCircles()
|
||||
|
||||
when 'bottom'
|
||||
if !@batchAssignShown
|
||||
@hideBatchCircles()
|
||||
@showBatchAssign()
|
||||
@moveDraggedItems(-1)
|
||||
|
||||
showBatchCircles: ->
|
||||
@batchCirclesShown = true
|
||||
|
||||
@batchMacroCircle.velocity
|
||||
properties:
|
||||
translateY: [0, '-150%']
|
||||
opacity: [1, 0]
|
||||
options:
|
||||
easing: [1,-.55,.2,1.37]
|
||||
duration: 500
|
||||
visibility: 'visible'
|
||||
delay: 200
|
||||
|
||||
@batchAssignCircle.velocity
|
||||
properties:
|
||||
translateY: [0, '150%']
|
||||
opacity: [1, 0]
|
||||
options:
|
||||
easing: [1,-.55,.2,1.37]
|
||||
duration: 500
|
||||
visibility: 'visible'
|
||||
delay: 200
|
||||
|
||||
hideBatchCircles: (callback) ->
|
||||
@batchMacroCircle.velocity
|
||||
properties:
|
||||
translateY: ['-150%', 0]
|
||||
opacity: [0, 1]
|
||||
options:
|
||||
duration: 300
|
||||
visibility: 'hidden'
|
||||
queue: false
|
||||
|
||||
@batchAssignCircle.velocity
|
||||
properties:
|
||||
translateY: ['150%', 0]
|
||||
opacity: [0, 1]
|
||||
options:
|
||||
duration: 300
|
||||
complete: callback
|
||||
visibility: 'hidden'
|
||||
queue: false
|
||||
|
||||
@batchCirclesShown = false
|
||||
|
||||
showBatchAssign: ->
|
||||
return if !@batchOverlayShown # user might have dropped the item already
|
||||
@batchAssignShown = true
|
||||
|
||||
@batchAssign.velocity
|
||||
properties:
|
||||
translateY: [0, '100%']
|
||||
opacity: [1, 0]
|
||||
options:
|
||||
easing: [1,-.55,.2,1.37]
|
||||
duration: 500
|
||||
visibility: 'visible'
|
||||
complete: @highlightBatchEntryAtMousePosition
|
||||
delay: if @batchCirclesShown then 0 else 200
|
||||
|
||||
@batchCancel.css
|
||||
top: 0
|
||||
bottom: 'auto'
|
||||
|
||||
@batchCancel.velocity
|
||||
properties:
|
||||
translateY: [0, '100%']
|
||||
opacity: [1, 0]
|
||||
options:
|
||||
easing: [1,-.55,.2,1.37]
|
||||
duration: 500
|
||||
visibility: 'visible'
|
||||
delay: if @batchCirclesShown then 0 else 200
|
||||
|
||||
hideBatchAssign: ->
|
||||
@batchAssign.velocity
|
||||
properties:
|
||||
translateY: ['100%', 0]
|
||||
opacity: [0, 1]
|
||||
options:
|
||||
duration: 300
|
||||
visibility: 'hidden'
|
||||
queue: false
|
||||
|
||||
@batchCancel.velocity
|
||||
properties:
|
||||
translateY: ['100%', 0]
|
||||
opacity: [0, 1]
|
||||
options:
|
||||
duration: 300
|
||||
visibility: 'hidden'
|
||||
queue: false
|
||||
|
||||
@batchAssignShown = false
|
||||
|
||||
showBatchMacro: ->
|
||||
return if !@batchOverlayShown # user might have dropped the item already
|
||||
@batchMacroShown = true
|
||||
|
||||
@batchMacro.velocity
|
||||
properties:
|
||||
translateY: [0, '-100%']
|
||||
opacity: [1, 0]
|
||||
options:
|
||||
easing: [1,-.55,.2,1.37]
|
||||
duration: 500
|
||||
visibility: 'visible'
|
||||
complete: @highlightBatchEntryAtMousePosition
|
||||
delay: if @batchCirclesShown then 0 else 200
|
||||
|
||||
@batchCancel.css
|
||||
top: 'auto'
|
||||
bottom: 0
|
||||
@batchCancel.velocity
|
||||
properties:
|
||||
translateY: [0, '-100%']
|
||||
opacity: [1, 0]
|
||||
options:
|
||||
easing: [1,-.55,.2,1.37]
|
||||
duration: 500
|
||||
visibility: 'visible'
|
||||
delay: if @batchCirclesShown then 0 else 200
|
||||
|
||||
hideBatchMacro: ->
|
||||
@batchMacro.velocity
|
||||
properties:
|
||||
translateY: ['-100%', 0]
|
||||
opacity: [0, 1]
|
||||
options:
|
||||
duration: 300
|
||||
visibility: 'hidden'
|
||||
queue: false
|
||||
|
||||
@batchCancel.velocity
|
||||
properties:
|
||||
translateY: ['-100%', 0]
|
||||
opacity: [0, 1]
|
||||
options:
|
||||
duration: 300
|
||||
visibility: 'hidden'
|
||||
queue: false
|
||||
|
||||
@batchMacroShown = false
|
||||
|
||||
highlightBatchEntryAtMousePosition: =>
|
||||
entryAtPoint = $(document.elementFromPoint(@mouse.x, @mouse.y)).closest('.js-batch-overlay-entry')
|
||||
if(entryAtPoint.length)
|
||||
@hoveredBatchEntry = entryAtPoint.addClass('is-hovered')
|
||||
|
||||
highlightBatchEntry: (event) ->
|
||||
@hoveredBatchEntry = $(event.currentTarget).addClass('is-hovered')
|
||||
|
||||
unhighlightBatchEntry: (event) ->
|
||||
@hoveredBatchEntry = null
|
||||
$(event.currentTarget).removeClass('is-hovered')
|
||||
|
||||
render: ->
|
||||
elLocal = $(App.view('ticket_overview')())
|
||||
elLocal = $(App.view('ticket_overview/index')())
|
||||
|
||||
@navBarControllerVertical = new Navbar
|
||||
el: elLocal.find('.overview-header')
|
||||
|
@ -397,10 +756,10 @@ class Table extends App.Controller
|
|||
)
|
||||
table = $(table)
|
||||
table.delegate('[name="bulk_all"]', 'click', (e) ->
|
||||
if $(e.target).attr('checked')
|
||||
$(e.target).closest('table').find('[name="bulk"]').attr('checked', true)
|
||||
if $(e.currentTarget).prop('checked')
|
||||
$(e.currentTarget).closest('table').find('[name="bulk"]').prop('checked', true)
|
||||
else
|
||||
$(e.target).closest('table').find('[name="bulk"]').attr('checked', false)
|
||||
$(e.currentTarget).closest('table').find('[name="bulk"]').prop('checked', false)
|
||||
)
|
||||
@$('.table-overview').append(table)
|
||||
else
|
||||
|
@ -440,6 +799,25 @@ class Table extends App.Controller
|
|||
@bulkForm.hide()
|
||||
else
|
||||
@bulkForm.show()
|
||||
|
||||
if @lastChecked && e.shiftKey
|
||||
# check items in a row
|
||||
currentItem = $(e.currentTarget).parents('.item')
|
||||
lastCheckedItem = @lastChecked.parents('.item')
|
||||
items = currentItem.parent().children()
|
||||
|
||||
if currentItem.index() > lastCheckedItem.index()
|
||||
# current item is below last checked item
|
||||
startId = lastCheckedItem.index()
|
||||
endId = currentItem.index()
|
||||
else
|
||||
# current item is above last checked item
|
||||
startId = currentItem.index()
|
||||
endId = lastCheckedItem.index()
|
||||
|
||||
items.slice(startId+1, endId).find('[name="bulk"]').prop('checked', (-> !@checked))
|
||||
|
||||
@lastChecked = $(e.currentTarget)
|
||||
callbackIconHeader = (headers) ->
|
||||
attribute =
|
||||
name: 'icon'
|
||||
|
@ -523,8 +901,8 @@ class Table extends App.Controller
|
|||
|
||||
# deselect bulk_all if one item is uncheck observ
|
||||
@$('.table-overview').delegate('[name="bulk"]', 'click', (e) ->
|
||||
if !$(e.target).attr('checked')
|
||||
$(e.target).parents().find('[name="bulk_all"]').attr('checked', false)
|
||||
if !$(e.target).prop('checked')
|
||||
$(e.target).parents().find('[name="bulk_all"]').prop('checked', false)
|
||||
)
|
||||
|
||||
getSelected: ->
|
||||
|
@ -540,7 +918,7 @@ class Table extends App.Controller
|
|||
ticketId = $(element).val()
|
||||
for ticketIdSelected in ticketIDs
|
||||
if ticketIdSelected is ticketId
|
||||
$(element).attr('checked', true)
|
||||
$(element).prop('checked', true)
|
||||
)
|
||||
|
||||
viewmode: (e) =>
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
<div class="sidebar"></div>
|
||||
<div class="main flex">
|
||||
<div class="overview-header"></div>
|
||||
<div class="overview-table"></div>
|
||||
</div>
|
|
@ -0,0 +1,3 @@
|
|||
<div class="batch-dragger zIndex-10">
|
||||
<div class="batch-dragger-counter js-batch-dragger-count"></div>
|
||||
</div>
|
|
@ -0,0 +1,50 @@
|
|||
<div class="sidebar"></div>
|
||||
<div class="main flex">
|
||||
<div class="overview-header"></div>
|
||||
<div class="overview-table"></div>
|
||||
</div>
|
||||
<div class="batch-overlay js-batch-overlay">
|
||||
<div class="batch-overlay-backdrop js-batch-overlay-backdrop"></div>
|
||||
<div class="batch-overlay-cancel js-batch-cancel">
|
||||
<%- @T('drag here to cancel') %>
|
||||
</div>
|
||||
<div class="batch-overlay-circle batch-overlay-circle--top js-batch-macro-circle">
|
||||
<div class="batch-overlay-circle-label"><%- @T('run macro') %></div>
|
||||
<%- @Icon('arrow-up') %>
|
||||
</div>
|
||||
<div class="batch-overlay-circle batch-overlay-circle--bottom js-batch-assign-circle">
|
||||
<%- @Icon('arrow-down') %>
|
||||
<div class="batch-overlay-circle-label"><%- @T('assign tickets') %></div>
|
||||
</div>
|
||||
<div class="batch-overlay-assign batch-overlay-box js-batch-assign">
|
||||
<div class="batch-overlay-assign-entry js-batch-overlay-entry" data-action="assign">
|
||||
<span class="avatar size-80 avatar--unique" style="background-position: -100px -150px;">HH</span>
|
||||
<div class="batch-overlay-assign-entry-name">Hans Huber</div>
|
||||
</div>
|
||||
<div class="batch-overlay-assign-entry js-batch-overlay-entry" data-action="assign">
|
||||
<span class="avatar avatar--organization size-80 avatar--unique" style="background-position: -200px -60px;">
|
||||
<%- @Icon('organization') %>
|
||||
</span>
|
||||
<div class="batch-overlay-assign-entry-name">Zammad</div>
|
||||
<div class="batch-overlay-assign-entry-detail">3 Personen</div>
|
||||
</div>
|
||||
<div class="batch-overlay-assign-entry js-batch-overlay-entry" data-action="assign">
|
||||
<span class="avatar size-80 avatar--unique" style="background-position: -30px -10px;">FD</span>
|
||||
<div class="batch-overlay-assign-entry-name">Felicity Dickens</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="batch-overlay-macro batch-overlay-box js-batch-macro">
|
||||
<div class="batch-overlay-macro-entry js-batch-overlay-entry" data-action="macro">
|
||||
<div class="batch-overlay-macro-entry-name">Close</div>
|
||||
</div>
|
||||
<div class="batch-overlay-macro-entry js-batch-overlay-entry" data-action="macro">
|
||||
<div class="batch-overlay-macro-entry-name">Close & Tag as Spam</div>
|
||||
</div>
|
||||
<div class="batch-overlay-macro-entry js-batch-overlay-entry" data-action="macro">
|
||||
<div class="batch-overlay-macro-entry-name">Close & Reply we're on Holidays</div>
|
||||
</div>
|
||||
<div class="batch-overlay-macro-entry js-batch-overlay-entry" data-action="macro">
|
||||
<div class="batch-overlay-macro-entry-name">Escalate to 2nd level</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -3580,6 +3580,23 @@ footer {
|
|||
}
|
||||
}
|
||||
|
||||
&--organization {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.icon-organization {
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
&.size-80 {
|
||||
.icon-organization {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon-logo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -8321,6 +8338,207 @@ output {
|
|||
margin: 20px 0 32px;
|
||||
}
|
||||
|
||||
.batch-overlay {
|
||||
@extend .fit;
|
||||
z-index: 1;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
letter-spacing: 0.07em;
|
||||
font-size: 0.95em;
|
||||
line-height: 1.3;
|
||||
display: none;
|
||||
will-change: display;
|
||||
cursor: grabbing;
|
||||
overflow: hidden;
|
||||
|
||||
&-backdrop {
|
||||
@extend .fit;
|
||||
background: hsla(231,20%,8%,.8);
|
||||
opacity: 0;
|
||||
will-change: opacity;
|
||||
}
|
||||
|
||||
&-circle {
|
||||
margin: 35px auto;
|
||||
background: hsl(207,7%,29%);
|
||||
border-radius: 100%;
|
||||
border: 4px solid white;
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
padding: 20px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
will-change: transform, opacity;
|
||||
visibility: hidden;
|
||||
|
||||
&--top {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
&--bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
fill: currentColor;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&-label {
|
||||
width: 50%;
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-cancel {
|
||||
background: hsla(0,0%,100%,.21);
|
||||
background-clip: padding-box;
|
||||
border: 2px dashed hsla(0,0%,100%,.3);
|
||||
border-radius: 8px;
|
||||
padding: 28px;
|
||||
margin: 50px 200px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
visibility: hidden;
|
||||
will-change: opacity;
|
||||
}
|
||||
|
||||
&-box {
|
||||
background: hsl(232,9%,17%);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
padding: 37px 25px;
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
will-change: opacity, transition;
|
||||
}
|
||||
|
||||
&-assign {
|
||||
padding-bottom: 87px; // 37px + 50px
|
||||
bottom: -50px; // extra space for bounce animation
|
||||
|
||||
&-entry {
|
||||
padding: 13px;
|
||||
|
||||
&.is-hovered {
|
||||
.avatar {
|
||||
border-color: $highlight-color;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border: 4px solid hsl(231,5%,30%);
|
||||
margin-bottom: 10px;
|
||||
box-sizing: content-box;
|
||||
transition: transform 120ms;
|
||||
}
|
||||
|
||||
&-detail {
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-macro {
|
||||
padding-top: 87px; // 37px + 50px
|
||||
top: -50px; // extra space for bounce animation
|
||||
|
||||
&-entry {
|
||||
margin: 13px;
|
||||
border: 4px solid hsl(231,5%,30%);
|
||||
background: hsl(233,9%,24%);
|
||||
border-radius: 100%;
|
||||
height: 120px;
|
||||
width: 120px;
|
||||
padding: 13px 13px 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.9em;
|
||||
|
||||
&.is-hovered {
|
||||
border-color: $highlight-color;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.batch-dragger {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
pointer-events: none;
|
||||
width: 250px;
|
||||
height: 40px;
|
||||
will-change: transform;
|
||||
|
||||
&-item {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: hsl(200,100%,91%);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 11px 0 9px 11px;
|
||||
box-shadow: 0 0 10px hsla(0,0%,0%,.28);
|
||||
will-change: transform;
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
td {
|
||||
display: block;
|
||||
padding: 0 12px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:nth-child(3) {
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
&:nth-child(n+4) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-counter {
|
||||
position: absolute;
|
||||
right: -8px;
|
||||
bottom: -8px;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 99px;
|
||||
z-index: 1;
|
||||
color: white;
|
||||
background: $highlight-color;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 0 10px hsla(0,0%,0%,.28);
|
||||
will-change: transform;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
----------------
|
||||
|
|
27
config/unicorn.rb
Normal file
27
config/unicorn.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
worker_processes 4
|
||||
timeout 30
|
||||
stderr_path 'log/unicorn_error.log'
|
||||
stdout_path 'log/unicorn_access.log'
|
||||
pid 'tmp/pids/unicorn.pid'
|
||||
|
||||
before_fork do |server, _worker|
|
||||
##
|
||||
# When sent a USR2, Unicorn will suffix its pidfile with .oldbin and
|
||||
# immediately start loading up a new version of itself (loaded with a new
|
||||
# version of our app). When this new Unicorn is completely loaded
|
||||
# it will begin spawning workers. The first worker spawned will check to
|
||||
# see if an .oldbin pidfile exists. If so, this means we've just booted up
|
||||
# a new Unicorn and need to tell the old one that it can now die. To do so
|
||||
# we send it a QUIT.
|
||||
#
|
||||
# Using this method we get 0 downtime deploys.
|
||||
|
||||
old_pid = 'tmp/pids/unicorn.pid.oldbin'
|
||||
if File.exist?(old_pid) && server.pid != old_pid
|
||||
begin
|
||||
Process.kill('QUIT', File.read(old_pid).to_i)
|
||||
rescue Errno::ENOENT, Errno::ESRCH
|
||||
logger.info 'Unicorn master already killed. Someone else did our job for us.'
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue