From a56b1d31c6fcb845cf86d5135c6d334e08f97e38 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Fri, 20 Feb 2015 14:40:51 +0100 Subject: [PATCH] Added overview navigation in ticket zoom. Added overview browser tests. --- .../app/controllers/ticket_overview.js.coffee | 24 ++++ .../app/controllers/ticket_zoom.js.coffee | 98 +++++++++++++++- .../javascripts/app/views/ticket_zoom.jst.eco | 29 +---- .../ticket_zoom/overview_navigator.jst.eco | 14 +++ app/assets/stylesheets/zammad.css.scss | 4 + .../agent_ticket_overview_level0_test.rb | 74 ++++++++++++ test/browser_test_helper.rb | 108 +++++++++++++++++- 7 files changed, 314 insertions(+), 37 deletions(-) create mode 100644 app/assets/javascripts/app/views/ticket_zoom/overview_navigator.jst.eco create mode 100644 test/browser/agent_ticket_overview_level0_test.rb diff --git a/app/assets/javascripts/app/controllers/ticket_overview.js.coffee b/app/assets/javascripts/app/controllers/ticket_overview.js.coffee index 659721058..de9f03134 100644 --- a/app/assets/javascripts/app/controllers/ticket_overview.js.coffee +++ b/app/assets/javascripts/app/controllers/ticket_overview.js.coffee @@ -69,6 +69,10 @@ class App.TicketOverview extends App.Controller release: => # no + overview: (overview_id) => + return if !@contentController + @contentController.overview(overview_id) + class Table extends App.Controller events: 'click [data-type=edit]': 'zoom' @@ -126,7 +130,17 @@ class Table extends App.Controller @render() ) + overview: (overview_id) => + return if !@cache + + # find requested overview data + for url, data of @cache + if data.overview.id is overview_id + return data + false + render: -> + console.log('RENDER', @cache, @view) return if !@cache return if !@cache[@view] @@ -204,7 +218,17 @@ class Table extends App.Controller @el.find('.table-overview').append(table) else openTicket = (id,e) => + + # open ticket via task manager to provide task with overview info ticket = App.Ticket.fullLocal(id) + App.TaskManager.execute( + key: 'Ticket-' + ticket.id + controller: 'TicketZoom' + params: + ticket_id: ticket.id + overview_id: overview.id + show: true + ) @navigate ticket.uiUrl() callbackTicketTitleAdd = (value, object, attribute, attributes, refObject) => attribute.title = object.title diff --git a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee index e58f439b0..9844ecb52 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee @@ -18,9 +18,16 @@ class App.TicketZoom extends App.Controller @navupdate '#' - @form_meta = undefined - @ticket_id = params.ticket_id - @article_id = params.article_id + @form_meta = undefined + @ticket_id = params.ticket_id + @article_id = params.article_id + + # if we are in init task startup, ognore overview_dd + if !params.init + @overview_id = params.overview_id + else + @overview_id = false + console.log('C OVERVIEW_ID', params.overview_id) @key = 'ticket::' + @ticket_id cache = App.Store.get( @key ) @@ -71,12 +78,17 @@ class App.TicketZoom extends App.Controller url: => '#ticket/zoom/' + @ticket_id - show: => + show: (params) => + return if @activeState + @activeState = true + console.log('S OVERVIEW_ID', params.overview_id) + App.OnlineNotification.seen( 'Ticket', @ticket_id ) @navupdate '#' @positionPageHeaderStart() hide: => + @activeState = false @positionPageHeaderStop() changed: => @@ -235,9 +247,16 @@ class App.TicketZoom extends App.Controller isCustomer: @isRole('Customer') ) + new OverviewNavigator( + el: @$('.overview-navigator') + ticket_id: @ticket.id + overview_id: @overview_id + ) + new TicketTitle( - ticket: @ticket - el: @el.find('.ticket-title') + ticket: @ticket + overview_id: @overview_id + el: @el.find('.ticket-title') ) new TicketMeta( @@ -782,6 +801,73 @@ class TicketTitle extends App.Controller release: => App.Ticket.unsubscribe( @subscribeId ) +class OverviewNavigator extends App.Controller + events: + 'click a': 'open' + + constructor: -> + super + + # rebuild overview navigator if overview has changed + @bind 'ticket_overview_rebuild', (data) => + execute = => + @render() + @delay(execute, 600, 'overview-navigator') + + @render() + + render: (overview) => + console.log('RENDER OverviewNavigator', @overview_id) + if !@overview_id + @html('') + return + + # get overview data + worker = App.TaskManager.worker( 'TicketOverview' ) + return if !worker + overview = worker.overview(@overview_id) + return if !overview + current_position = 0 + next = false + previous = false + for ticket_id in overview.ticket_ids + current_position += 1 + next = overview.ticket_ids[current_position] + previous = overview.ticket_ids[current_position-2] + break if ticket_id is @ticket_id + + # get next/previous ticket + if next + next = App.Ticket.find(next) + if previous + previous = App.Ticket.find(previous) + + @html App.view('ticket_zoom/overview_navigator')( + title: overview.overview.name + total_count: overview.tickets_count + current_position: current_position + next: next + previous: previous + ) + + open: (e) => + e.preventDefault() + id = $(e.target).data('id') + url = $(e.target).attr('href') + if !id + id = $(e.target).closest('a').data('id') + url = $(e.target).closest('a').attr('href') + console.log('id', id, 'url', url) + App.TaskManager.execute( + key: 'Ticket-' + id + controller: 'TicketZoom' + params: + ticket_id: id + overview_id: @overview_id + show: true + ) + @navigate url + class TicketMeta extends App.Controller constructor: -> super diff --git a/app/assets/javascripts/app/views/ticket_zoom.jst.eco b/app/assets/javascripts/app/views/ticket_zoom.jst.eco index ac6160cc8..f37bfa1a9 100644 --- a/app/assets/javascripts/app/views/ticket_zoom.jst.eco +++ b/app/assets/javascripts/app/views/ticket_zoom.jst.eco @@ -4,19 +4,7 @@
<%- @C('ticket_hook') %> <%- @ticket.number %>
-
- 1/36 -
- +
-
-
- diff --git a/app/assets/javascripts/app/views/ticket_zoom/overview_navigator.jst.eco b/app/assets/javascripts/app/views/ticket_zoom/overview_navigator.jst.eco new file mode 100644 index 000000000..684cf91f7 --- /dev/null +++ b/app/assets/javascripts/app/views/ticket_zoom/overview_navigator.jst.eco @@ -0,0 +1,14 @@ +
+ <%= @current_position %>/<%= @total_count %> +
+ \ No newline at end of file diff --git a/app/assets/stylesheets/zammad.css.scss b/app/assets/stylesheets/zammad.css.scss index a6a9464e5..6fcb98950 100644 --- a/app/assets/stylesheets/zammad.css.scss +++ b/app/assets/stylesheets/zammad.css.scss @@ -5079,6 +5079,10 @@ label + .wizard-buttonList { } +.overview-navigator { + display: inherit; +} + /* ---------------- diff --git a/test/browser/agent_ticket_overview_level0_test.rb b/test/browser/agent_ticket_overview_level0_test.rb new file mode 100644 index 000000000..e59d536bd --- /dev/null +++ b/test/browser/agent_ticket_overview_level0_test.rb @@ -0,0 +1,74 @@ +# encoding: utf-8 +require 'browser_test_helper' + +class AgentTicketOverviewLevel0Test < TestCase + def test_I + tests = [ + { + :name => 'verify overview count', + :action => [ + { + :execute => 'close_all_tasks', + }, + + # remember it ticket count in overview + { + :execute => 'overview_count_remember', + }, + + # create new open ticket + { + :execute => 'create_ticket', + :group => 'Users', + :subject => 'some subject 123äöü', + :body => 'some body 123äöü - with closed tab', + }, + + # remember ticket for later + { + :execute => 'match', + :css => '.active .page-header .ticket-number', + :value => '^(.*)$', + :no_quote => true, + :match_result => true, + }, + { + :execute => 'wait', + :value => 5, + }, + + # check new ticket count of open tickets in overview + { + :execute => 'overview_count_verify', + :data => { + '#ticket/view/all_unassigned' => 1, + }, + }, + + # close ticket + { + :execute => 'search_ticket', + :number => '###stack###', + }, + { + :execute => 'update_ticket', + :state => 'closed', + }, + { + :execute => 'wait', + :value => 5, + }, + + # verify new open tickets in overview + { + :execute => 'overview_count_verify', + :data => { + '#ticket/view/all_unassigned' => 0, + }, + }, + ], + }, + ] + browser_signle_test_with_login(tests, { :username => 'master@example.com' }) + end +end diff --git a/test/browser_test_helper.rb b/test/browser_test_helper.rb index 82522f43f..35216d0b6 100644 --- a/test/browser_test_helper.rb +++ b/test/browser_test_helper.rb @@ -336,6 +336,50 @@ class TestCase < Test::Unit::TestCase assert( true, "(#{test[:name]}) user creation failed" ) return + elsif action[:execute] == 'overview_count_remember' + instance.find_elements( { :css => '#navigation li.overviews a' } )[0].click + sleep 2 + overviews = {} + instance.find_elements( { :css => '.content.active .sidebar a[href]' } ).each {|element| + url = element.attribute('href') + url.gsub!(/(http|https):\/\/.+?\/(.+?)$/, "\\2") + overviews[url] = 0 + #puts url.inspect + #puts element.inspect + } + overviews.each {|url, value| + count = instance.find_elements( { :css => ".content.active .sidebar a[href=\"#{url}\"] .badge" } )[0].text + overviews[url] = count + } + @overview_count_remember = overviews + assert( !overviews.empty?, "(#{test[:name]}) overview_count_remember" ) + return + elsif action[:execute] == 'overview_count_verify' + instance.find_elements( { :css => '#navigation li.overviews a' } )[0].click + sleep 2 + overviews = {} + instance.find_elements( { :css => '.content.active .sidebar a[href]' } ).each {|element| + url = element.attribute('href') + url.gsub!(/(http|https):\/\/.+?\/(.+?)$/, "\\2") + overviews[url] = 0 + } + overviews.each {|url, value| + count = instance.find_elements( { :css => ".content.active .sidebar a[href=\"#{url}\"] .badge" } )[0].text + overviews[url] = count + } + #puts "ov #{overviews.inspect}" + #puts "@ov #{@overview_count_remember.inspect}" + #puts "data #{action[:data].inspect}" + action[:data].each {|url,count| + if @overview_count_remember.has_key?(url) + count_is = overviews[url].to_i + count_should = @overview_count_remember[url].to_i + count.to_i + assert_equal( count_should, count_is, "(#{test[:name]}) expected count of url #{url} is different overview_count_remember" ) + else + assert( false, "(#{test[:name]}) no url #{url} exists in overview_count_remember" ) + end + } + return elsif action[:execute] == 'create_signature' instance.find_elements( { :css => 'a[href="#manage"]' } )[0].click instance.find_elements( { :css => 'a[href="#channels/email"]' } )[0].click @@ -415,17 +459,17 @@ class TestCase < Test::Unit::TestCase elsif action[:execute] == 'verify_task_attributes' if action[:title] text = instance.find_elements( { :css => '.tasks .active' } )[0].text.strip - assert_equal( action[:title], text ) + assert_equal( action[:title], text ) end return elsif action[:execute] == 'verify_ticket_attributes' if action[:title] text = instance.find_elements( { :css => '.content.active .page-header .ticket-title-update' } )[0].text.strip - assert_equal( action[:title], text ) + assert_equal( action[:title], text ) end if action[:body] text = instance.find_elements( { :css => '.content.active [data-name="body"]' } )[0].text.strip - assert_equal( action[:body], text ) + assert_equal( action[:body], text ) end return elsif action[:execute] == 'set_ticket_attributes' @@ -463,6 +507,8 @@ class TestCase < Test::Unit::TestCase element.send_keys( action[:body] ) end return + + # create ticket elsif action[:execute] == 'create_ticket' instance.find_elements( { :css => 'a[href="#new"]' } )[0].click instance.find_elements( { :css => 'a[href="#ticket/create"]' } )[0].click @@ -525,6 +571,58 @@ class TestCase < Test::Unit::TestCase } assert( false, "(#{test[:name]}) ticket creation failed, can't get zoom url" ) return + + # udpate ticket + elsif action[:execute] == 'update_ticket' + + if action[:group] + element = instance.find_elements( { :css => '.active .sidebar select[name="group_id"]' } )[0] + dropdown = Selenium::WebDriver::Support::Select.new(element) + dropdown.select_by( :text, action[:group]) + sleep 0.2 + end + + if action[:state] + element = instance.find_elements( { :css => '.active .sidebar select[name="state_id"]' } )[0] + dropdown = Selenium::WebDriver::Support::Select.new(element) + dropdown.select_by( :text, action[:state]) + sleep 0.2 + end + + found = nil + (1..5).each {|loop| + if !found + text = instance.find_elements( { :css => '.content.active .js-reset' } )[0].text + if text =~ /(Discard your unsaved changes.|Verwerfen der)/ + assert( true, "(#{test[:name]}) discard message found" ) + found = true + end + sleep 1 + end + } + if !found + assert( false, "(#{test[:name]}) no discard message found" ) + end + + if action[:do_not_submit] + assert( true, "(#{test[:name]}) ticket updated without submit" ) + return + end + + instance.find_elements( { :css => '.content.active button.js-submit' } )[0].click + + (1..10).each {|loop| + text = instance.find_elements( { :css => '.content.active .js-reset' } )[0].text + if !text || text.empty? + assert( true, "(#{test[:name]}) ticket updated" ) + return + end + sleep 1 + } + assert( false, "(#{test[:name]}) unable to update ticket" ) + return + + # search user elsif action[:execute] == 'search_user' element = instance.find_elements( { :css => '#global-search' } )[0] element.click @@ -542,6 +640,8 @@ class TestCase < Test::Unit::TestCase end assert( true, "(#{test[:name]}) user #{action[:term]} found" ) return + + # search org elsif action[:execute] == 'search_organization' element = instance.find_elements( { :css => '#global-search' } )[0] element.click @@ -574,6 +674,8 @@ class TestCase < Test::Unit::TestCase end assert( true, "(#{test[:name]}) org #{action[:term]} found" ) return + + # search ticket elsif action[:execute] == 'search_ticket' element = instance.find_elements( { :css => '#global-search' } )[0] element.click