Fixes #257 - Define default "stay on tab" / "close tab" behavior.

This commit is contained in:
Rolf Schmidt 2021-09-09 14:35:00 +02:00 committed by Thorsten Eckel
parent b3bfe71ab8
commit 41691e9846
8 changed files with 224 additions and 5 deletions

View file

@ -978,8 +978,14 @@ class App.TicketZoom extends App.Controller
@openTicketInOverview(nextTicket) @openTicketInOverview(nextTicket)
App.Event.trigger('overview:fetch') App.Event.trigger('overview:fetch')
return return
else if taskAction is 'closeTabOnTicketClose' || taskAction is 'next_task_on_close'
if taskAction is 'closeTab' || taskAction is 'next_task' state_type_id = App.TicketState.find(ticket.state_id).state_type_id
state_type = App.TicketStateType.find(state_type_id).name
if state_type is 'closed'
App.Event.trigger('overview:fetch')
@taskCloseTicket(true)
return
else if taskAction is 'closeTab' || taskAction is 'next_task'
App.Event.trigger('overview:fetch') App.Event.trigger('overview:fetch')
@taskCloseTicket(true) @taskCloseTicket(true)
return return

View file

@ -15,7 +15,7 @@ class App.TicketZoomAttributeBar extends App.Controller
constructor: -> constructor: ->
super super
@secondaryAction = 'stayOnTab' @secondaryAction = @getAction()
@subscribeId = App.Macro.subscribe(@checkMacroChanges) @subscribeId = App.Macro.subscribe(@checkMacroChanges)
@render() @render()
@ -31,6 +31,9 @@ class App.TicketZoomAttributeBar extends App.Controller
@render() @render()
) )
getAction: ->
return App.Session.get().preferences.secondaryAction || App.Config.get('ticket_secondary_action') || 'stayOnTab'
release: => release: =>
App.Macro.unsubscribe(@subscribeId) App.Macro.unsubscribe(@subscribeId)
@ -74,6 +77,7 @@ class App.TicketZoomAttributeBar extends App.Controller
start: => start: =>
return if !@taskbarWatcher return if !@taskbarWatcher
@taskbarWatcher.start() @taskbarWatcher.start()
@setSecondaryAction(@getAction(), @el)
stop: => stop: =>
return if !@taskbarWatcher return if !@taskbarWatcher
@ -114,11 +118,25 @@ class App.TicketZoomAttributeBar extends App.Controller
chooseSecondaryAction: (e) => chooseSecondaryAction: (e) =>
type = $(e.currentTarget).find('.js-secondaryActionLabel').data('type') type = $(e.currentTarget).find('.js-secondaryActionLabel').data('type')
@setSecondaryAction(type, @el) @setSecondaryAction(type, @el)
@setUserPreferencesSecondaryAction(type)
setSecondaryAction: (type, localEl) -> setSecondaryAction: (type, localEl) ->
element = localEl.find(".js-secondaryActionLabel[data-type=#{type}]") element = localEl.find(".js-secondaryActionLabel[data-type=#{type}]")
return @setSecondaryAction('stayOnTab', localEl) if element.length == 0
text = element.text() text = element.text()
localEl.find('.js-secondaryAction .js-selectedIcon.is-selected').removeClass('is-selected') localEl.find('.js-secondaryAction .js-selectedIcon.is-selected').removeClass('is-selected')
element.closest('.js-secondaryAction').find('.js-selectedIcon').addClass('is-selected') element.closest('.js-secondaryAction').find('.js-selectedIcon').addClass('is-selected')
localEl.find('.js-secondaryActionButtonLabel').text(text) localEl.find('.js-secondaryActionButtonLabel').text(text)
localEl.find('.js-secondaryActionButtonLabel').data('type', type) localEl.find('.js-secondaryActionButtonLabel').data('type', type)
setUserPreferencesSecondaryAction: (type) ->
session = App.Session.get()
return if session.preferences.secondaryAction is type
@ajax(
id: 'setUserPreferencesSecondaryAction'
type: 'PUT'
url: "#{App.Config.get('api_path')}/users/preferences"
data: JSON.stringify(secondaryAction: type)
processData: true
)

View file

@ -7,7 +7,7 @@ class App.Macro extends App.Model
{ name: 'perform', display: 'Actions', tag: 'ticket_perform_action', null: true { name: 'perform', display: 'Actions', tag: 'ticket_perform_action', null: true
}, },
{ name: 'ux_flow_next_up', display: 'Once completed...', tag: 'select', default: 'none', options: { { name: 'ux_flow_next_up', display: 'Once completed...', tag: 'select', default: 'none', options: {
none: 'Stay on tab', next_task: 'Close tab', next_from_overview: 'Advance to next ticket from overview' none: 'Stay on tab', next_task: 'Close tab', next_task_on_close: 'Close tab on ticket close', next_from_overview: 'Advance to next ticket from overview'
} }
}, },
{ name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },

View file

@ -10,6 +10,11 @@
<span class="dropdown-selectedSpacer js-selectedIcon"> <span class="dropdown-selectedSpacer js-selectedIcon">
<%- @Icon('checkmark') %> <%- @Icon('checkmark') %>
</span> </span>
<li class="js-secondaryAction" role="menuitem">
<span class="js-secondaryActionLabel" data-type="closeTabOnTicketClose"><%- @T('Close tab on ticket close') %></span>
<span class="dropdown-selectedSpacer js-selectedIcon">
<%- @Icon('checkmark') %>
</span>
<% if @overview_id: %> <% if @overview_id: %>
<li class="js-secondaryAction" role="menuitem"> <li class="js-secondaryAction" role="menuitem">
<span class="js-secondaryActionLabel" data-type="closeNextInOverview"><%- @T('Next in overview') %></span> <span class="js-secondaryActionLabel" data-type="closeNextInOverview"><%- @T('Next in overview') %></span>

View file

@ -9,7 +9,7 @@ class Macro < ApplicationModel
store :perform store :perform
validates :name, presence: true validates :name, presence: true
validates :ux_flow_next_up, inclusion: { in: %w[none next_task next_from_overview] } validates :ux_flow_next_up, inclusion: { in: %w[none next_task next_task_on_close next_from_overview] }
has_and_belongs_to_many :groups, after_add: :cache_update, after_remove: :cache_update, class_name: 'Group' has_and_belongs_to_many :groups, after_add: :cache_update, after_remove: :cache_update, class_name: 'Group'

View file

@ -0,0 +1,37 @@
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
class Issue257TicketSecondaryAction < ActiveRecord::Migration[6.0]
def change
# return if it's a new setup
return if !Setting.exists?(name: 'system_init_done')
Setting.create_if_not_exists(
title: 'Tab behaviour after ticket action',
name: 'ticket_secondary_action',
area: 'CustomerWeb::Base',
description: 'Defines the tab behaviour after a ticket action.',
options: {
form: [
{
display: '',
null: true,
name: 'ticket_secondary_action',
tag: 'boolean',
options: {
'closeTab' => 'Close tab',
'closeTabOnTicketClose' => 'Close tab on ticket close',
'closeNextInOverview' => 'Next in overview',
'stayOnTab' => 'Stay on tab',
},
},
],
},
state: 'stayOnTab',
preferences: {
authentication: true,
permission: ['admin.channel_web'],
},
frontend: true
)
end
end

View file

@ -2363,6 +2363,35 @@ Setting.create_if_not_exists(
frontend: true frontend: true
) )
Setting.create_if_not_exists(
title: 'Tab behaviour after ticket action',
name: 'ticket_secondary_action',
area: 'CustomerWeb::Base',
description: 'Defines the tab behaviour after a ticket action.',
options: {
form: [
{
display: '',
null: true,
name: 'ticket_secondary_action',
tag: 'boolean',
options: {
'closeTab' => 'Close tab',
'closeTabOnTicketClose' => 'Close tab on ticket close',
'closeNextInOverview' => 'Next in overview',
'stayOnTab' => 'Stay on tab',
},
},
],
},
state: 'stayOnTab',
preferences: {
authentication: true,
permission: ['admin.channel_web'],
},
frontend: true
)
Setting.create_if_not_exists( Setting.create_if_not_exists(
title: 'Enable Ticket creation', title: 'Enable Ticket creation',
name: 'form_ticket_create', name: 'form_ticket_create',

View file

@ -1782,4 +1782,128 @@ RSpec.describe 'Ticket zoom', type: :system do
end end
end end
end end
describe 'Tab behaviour - Define default "stay on tab" / "close tab" behavior #257', authenticated_as: :authenticate do
def authenticate
Setting.set('ticket_secondary_action', 'closeTabOnTicketClose')
true
end
let!(:ticket) { create(:ticket, group: Group.find_by(name: 'Users')) }
before do
visit "ticket/zoom/#{ticket.id}"
end
it 'does show the default of the system' do
expect(page).to have_text('Close tab on ticket close')
end
it 'does save state for the user preferences' do
click '.js-attributeBar .dropup div'
click 'span[data-type=stayOnTab]'
refresh
expect(page).to have_text('Stay on tab')
expect(User.find_by(email: 'admin@example.com').preferences[:secondaryAction]).to eq('stayOnTab')
end
context 'Tab behaviour - Close tab on ticket close' do
it 'does not close the tab without any action' do
click '.js-submit'
expect(current_url).to include('ticket/zoom')
end
it 'does close the tab on ticket close' do
select 'closed', from: 'State'
click '.js-submit'
expect(current_url).not_to include('ticket/zoom')
end
end
context 'Tab behaviour - Stay on tab' do
def authenticate
Setting.set('ticket_secondary_action', 'stayOnTab')
true
end
it 'does not close the tab without any action' do
click '.js-submit'
expect(current_url).to include('ticket/zoom')
end
it 'does not close the tab on ticket close' do
select 'closed', from: 'State'
click '.js-submit'
expect(current_url).to include('ticket/zoom')
end
end
context 'Tab behaviour - Close tab' do
def authenticate
Setting.set('ticket_secondary_action', 'closeTab')
true
end
it 'does close the tab without any action' do
click '.js-submit'
expect(current_url).not_to include('ticket/zoom')
end
it 'does close the tab on ticket close' do
select 'closed', from: 'State'
click '.js-submit'
expect(current_url).not_to include('ticket/zoom')
end
end
context 'Tab behaviour - Next in overview' do
let(:ticket1) { create(:ticket, title: SecureRandom.uuid, group: Group.find_by(name: 'Users')) }
let(:ticket2) { create(:ticket, title: SecureRandom.uuid, group: Group.find_by(name: 'Users')) }
let(:ticket3) { create(:ticket, title: SecureRandom.uuid, group: Group.find_by(name: 'Users')) }
def authenticate
Setting.set('ticket_secondary_action', 'closeNextInOverview')
ticket1
ticket2
ticket3
true
end
before do
visit 'ticket/view/all_open'
end
it 'does change the tab without any action' do
click_on ticket1.title
expect(current_url).to include("ticket/zoom/#{ticket1.id}")
click '.js-submit'
expect(current_url).to include("ticket/zoom/#{ticket2.id}")
click '.js-submit'
expect(current_url).to include("ticket/zoom/#{ticket3.id}")
end
it 'does show default stay on tab if secondary action is not given' do
click_on ticket1.title
refresh
expect(page).to have_text('Stay on tab')
end
end
context 'On ticket switch' do
let(:ticket1) { create(:ticket, title: SecureRandom.uuid, group: Group.find_by(name: 'Users')) }
let(:ticket2) { create(:ticket, title: SecureRandom.uuid, group: Group.find_by(name: 'Users')) }
before do
visit "ticket/zoom/#{ticket1.id}"
visit "ticket/zoom/#{ticket2.id}"
end
it 'does setup the last behaviour' do
click '.js-attributeBar .dropup div'
click 'span[data-type=stayOnTab]'
visit "ticket/zoom/#{ticket1.id}"
expect(page).to have_text('Stay on tab')
end
end
end
end end