Browse Source

Fixes #4229 - User-based ticket overview sorting.

Rolf Schmidt 2 years ago
parent
commit
da66d95d3b

+ 1 - 0
app/assets/javascripts/app/controllers/_application_controller/_generic_index.coffee

@@ -108,6 +108,7 @@ class App.ControllerGenericIndex extends App.Controller
         notes:           @pageData.notes
         buttons:         @pageData.buttons
         menus:           @pageData.menus
+        subHead:         @pageData.subHead
         showDescription: showDescription
       )
 

+ 79 - 0
app/assets/javascripts/app/controllers/_profile/overviews.coffee

@@ -0,0 +1,79 @@
+class Overviews extends App.ControllerSubContent
+  requiredPermission: 'user_preferences.overview_sorting'
+  header: __('Sorting')
+
+  constructor: ->
+    super
+    @fetch()
+
+  fetch: =>
+    @ajax(
+      type:  'GET'
+      url:   "#{App.Config.get('api_path')}/user_overview_sortings"
+      processData: true,
+      success: (data, status, xhr) =>
+        App.UserOverviewSortingOverview.refresh(data.overviews)
+        App.UserOverviewSorting.refresh(data.overview_sortings)
+        @render(data)
+    )
+
+  render: (data) ->
+    @index ||= new Index(
+      disableInitFetch: true
+      el: @el
+      id: @id
+      genericObject: 'UserOverviewSortingOverview'
+      defaultSortBy: 'prio'
+      pageData:
+        home: 'overviews'
+        object: __('Order')
+        objects: __(' Order')
+        navupdate: '#profile/overviews'
+        subHead: false
+        buttons: [
+          { name: __('Reset Order'), 'data-type': 'reset', class: 'btn--danger' }
+        ]
+      container: @el.closest('.content')
+      veryLarge: true
+      dndCallback: (e, item) =>
+        items = @el.find('table > tbody > tr')
+        prios = []
+        prio = 0
+        for item in items
+          prio += 1
+          id = $(item).data('id')
+          prios.push [id, prio]
+
+        @ajax(
+          id:          'user_overview_sortings_prio'
+          type:        'POST'
+          url:         "#{@apiPath}/user_overview_sortings_prio"
+          processData: true
+          data:        JSON.stringify(prios: prios)
+          success:     @fetch
+        )
+    )
+    @index.render()
+
+class Index extends App.ControllerGenericIndex
+  events:
+    'click [data-type=reset]': 'reset'
+
+  render: ->
+    objects = App[@genericObject].all()
+    @renderObjects(objects)
+
+  edit: (id, e) ->
+    return
+
+  reset: (e) =>
+    e.preventDefault()
+
+    App.UserOverviewSorting.destroyAll()
+
+    @notify
+      type: 'success'
+      msg:  __('Personal overview sortings deleted!')
+    @render()
+
+App.Config.set('Overviews', { prio: 2900, name: __('Overviews'), parent: '#profile', target: '#profile/overviews', controller: Overviews, permission: ['user_preferences.overview_sorting'] }, 'NavBarProfile')

+ 11 - 0
app/assets/javascripts/app/controllers/ticket_overview.coffee

@@ -820,6 +820,11 @@ class Navbar extends App.Controller
 
   autoFoldTabs: =>
     items = App.OverviewIndexCollection.get()
+    if App.UserOverviewSorting.count()
+      items.sort(App.UserOverviewSortingOverview.overviewSort)
+    else
+      items.sort((a, b) -> a.prio - b.prio)
+
     @html App.view("agent_ticket_view/navbar#{ if @vertical then '_vertical' }")
       items: items
       isAgent: @permissionCheck('ticket.agent')
@@ -892,6 +897,12 @@ class Navbar extends App.Controller
       else
         item.active = false
 
+    # sort by profile preferences
+    if App.UserOverviewSorting.count()
+      data.sort(App.UserOverviewSortingOverview.overviewSort)
+    else
+      data.sort((a, b) -> a.prio - b.prio)
+
     @html App.view("agent_ticket_view/navbar#{ if @vertical then '_vertical' else '' }")
       items: data
 

+ 9 - 0
app/assets/javascripts/app/models/user_overview_sorting.coffee

@@ -0,0 +1,9 @@
+class App.UserOverviewSorting extends App.Model
+  @configure 'UserOverviewSorting', 'user_id', 'overview_id', 'prio'
+  @extend Spine.Model.Ajax
+  @url: @apiPath + '/user_overview_sortings'
+  @configure_attributes = [
+    { name: 'user_id', display: __('User'), tag: 'select', multiple: false, null: false, relation: 'User', translate: true },
+    { name: 'overview_id', display: __('Overview'), tag: 'select', multiple: false, null: false, relation: 'Overview', translate: true },
+    { name: 'prio', display: __('Prio'), readonly: 1 },
+  ]

+ 22 - 0
app/assets/javascripts/app/models/user_overview_sorting_overview.coffee

@@ -0,0 +1,22 @@
+class App.UserOverviewSortingOverview extends App.Model
+  @configure 'UserOverviewSortingOverview', 'name'
+  @configure_attributes = [
+    { name: 'name', display: __('Name'), tag: 'input', type: 'text', null: false },
+  ]
+  @configure_overview = [
+    'name',
+  ]
+
+  @all: ->
+    super.sort(@overviewSort)
+
+  @overviewSort: (a, b) ->
+    aIndex = a.prio + 9999
+    bIndex = b.prio + 9999
+    for sorting, index in App.UserOverviewSorting.all()
+      if sorting.overview_id is a.id
+        aIndex = sorting.prio
+      if sorting.overview_id is b.id
+        bIndex = sorting.prio
+
+    return aIndex - bIndex

+ 1 - 1
app/assets/javascripts/app/views/generic/admin/index.jst.eco

@@ -1,6 +1,6 @@
 <div class="page-header">
   <div class="page-header-title">
-    <h1><%- @T(@head) %> <small><%- @T('Management') %></small></h1>
+    <h1><%- @T(@head) %><% if @subHead || @subHead is undefined: %> <small><%- @T(@subHead || 'Management') %></small><% end %></h1>
   </div>
   <div class="page-header-meta">
     <% if @showDescription: %>

+ 9 - 1
app/controllers/concerns/can_prioritize.rb

@@ -6,7 +6,7 @@ module CanPrioritize
   def prio
     klass.without_callback(:update, :before, :rearrangement) do
       params[:prios].each do |entry_prio|
-        entry = klass.find(entry_prio[0])
+        entry = prio_find(entry_prio) || prio_create(entry_prio)
         next if entry.prio == entry_prio[1]
 
         entry.prio = entry_prio[1]
@@ -15,4 +15,12 @@ module CanPrioritize
     end
     render json: { success: true }, status: :ok
   end
+
+  def prio_create(entry_prio)
+    klass.try(:prio_create, id: entry_prio[0], prio: entry_prio[1], current_user: current_user)
+  end
+
+  def prio_find(entry_prio)
+    klass.find_by(id: entry_prio[0])
+  end
 end

+ 1 - 0
app/controllers/ticket_overviews_controller.rb

@@ -25,6 +25,7 @@ class TicketOverviewsController < ApplicationController
       index_and_lists.each do |index|
         overview = Overview.lookup(id: index[:overview][:id])
         meta = {
+          id:    overview.id,
           name:  overview.name,
           prio:  overview.prio,
           link:  overview.link,

+ 34 - 0
app/controllers/user/overview_sortings_controller.rb

@@ -0,0 +1,34 @@
+# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
+
+class User::OverviewSortingsController < ApplicationController
+  include CanPrioritize
+
+  prepend_before_action { authentication_check && authorize! }
+
+  def index
+    render json: {
+      overviews:         Ticket::Overviews.all(current_user: current_user),
+      overview_sortings: User::OverviewSorting.where(user: current_user),
+    }
+  end
+
+  def show
+    model_show_render(User::OverviewSorting, params)
+  end
+
+  def create
+    model_create_render(User::OverviewSorting, params)
+  end
+
+  def update
+    model_update_render(User::OverviewSorting, params)
+  end
+
+  def destroy
+    model_destroy_render(User::OverviewSorting, params)
+  end
+
+  def prio_find(entry_prio)
+    klass.find_by(overview_id: entry_prio[0], user: current_user)
+  end
+end

+ 1 - 0
app/models/user.rb

@@ -40,6 +40,7 @@ class User < ApplicationModel
   has_many                :cti_caller_ids,         class_name: 'Cti::CallerId', dependent: :destroy
   has_many                :customer_tickets,       class_name: 'Ticket', foreign_key: :customer_id, dependent: :destroy, inverse_of: :customer
   has_many                :owner_tickets,          class_name: 'Ticket', foreign_key: :owner_id, inverse_of: :owner
+  has_many                :overview_sortings,      dependent: :destroy
   has_many                :created_recent_views,   class_name: 'RecentView', foreign_key: :created_by_id, dependent: :destroy, inverse_of: :created_by
   has_many                :permissions,            -> { where(roles: { active: true }, active: true) }, through: :roles
   has_many                :data_privacy_tasks,     as: :deletable

Some files were not shown because too many files changed in this diff