From 2a3aef0ca646db995e5f91e0dfde01c053263020 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 13 Aug 2014 22:27:44 +0200 Subject: [PATCH 1/9] Improved use of .expanding(), removed log messages. --- .../controllers/_application_controller_form.js.coffee | 8 ++++++-- .../app/controllers/widget/organization.js.coffee | 10 +++++++--- .../javascripts/app/controllers/widget/user.js.coffee | 10 +++++++--- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee index baa108aaf..56450de6b 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee @@ -654,9 +654,13 @@ class App.ControllerForm extends App.Controller item = $( App.view('generic/textarea')( attribute: attribute ) + '
' ) a = => - $( item[0] ).expanding() - $( item[0] ).on('focus', -> + visible = $( item[0] ).is(":visible") + if visible && !$( item[0] ).expanding('active') $( item[0] ).expanding() + $( item[0] ).on('focus', -> + visible = $( item[0] ).is(":visible") + if visible && !$( item[0] ).expanding('active') + $( item[0] ).expanding() ) App.Delay.set( a, 80 ) diff --git a/app/assets/javascripts/app/controllers/widget/organization.js.coffee b/app/assets/javascripts/app/controllers/widget/organization.js.coffee index fb0b59445..82a386080 100644 --- a/app/assets/javascripts/app/controllers/widget/organization.js.coffee +++ b/app/assets/javascripts/app/controllers/widget/organization.js.coffee @@ -42,11 +42,15 @@ class App.WidgetOrganization extends App.Controller ) a = => - @el.find('textarea').expanding() - @el.find('textarea').on('focus', => + visible = @el.find('textarea').is(":visible") + if visible && !@el.find('textarea').expanding('active') @el.find('textarea').expanding() + @el.find('textarea').on('focus', (e) => + visible = @el.find('textarea').is(":visible") + if visible && !@el.find('textarea').expanding('active') + @el.find('textarea').expanding() ) - @delay( a, 80 ) + @delay( a, 40 ) # enable user popups @userPopups() diff --git a/app/assets/javascripts/app/controllers/widget/user.js.coffee b/app/assets/javascripts/app/controllers/widget/user.js.coffee index 23d41cd65..7ffe95c1d 100644 --- a/app/assets/javascripts/app/controllers/widget/user.js.coffee +++ b/app/assets/javascripts/app/controllers/widget/user.js.coffee @@ -72,11 +72,15 @@ class App.WidgetUser extends App.ControllerDrox ) a = => - @el.find('textarea').expanding() - @el.find('textarea').on('focus', => + visible = @el.find('textarea').is(":visible") + if visible && !@el.find('textarea').expanding('active') @el.find('textarea').expanding() + @el.find('textarea').on('focus', (e) => + visible = @el.find('textarea').is(":visible") + if visible && !@el.find('textarea').expanding('active') + @el.find('textarea').expanding() ) - @delay( a, 80 ) + @delay( a, 40 ) @userTicketPopups( selector: '.user-tickets' From 4c903bfd4a802da799c89810d80473311e57a746 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Thu, 14 Aug 2014 11:04:02 +0200 Subject: [PATCH 2/9] Fixed unit tests. --- .../app/controllers/ticket_zoom.js.coffee | 23 +++-- .../app/controllers/widget/user.js.coffee | 4 + test/browser/text_module_test.rb | 99 +++++++++++++++++++ 3 files changed, 118 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee index c6f6f9e88..2e508a65c 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee @@ -150,14 +150,6 @@ class App.TicketZoom extends App.Controller if !@editWidget || _.isEmpty( App.TaskManager.get(@task_key).state ) @editWidget = @Edit() - # show text module UI - if !@isRole('Customer') - new App.WidgetTextModule( - el: @el.find('textarea') - data: - ticket: @ticket - ) - # scroll to article if given if @article_id && document.getElementById( 'article-' + @article_id ) offset = document.getElementById( 'article-' + @article_id ).offsetTop @@ -324,6 +316,8 @@ class Edit extends App.Controller release: => @autosaveStop() + if @subscribeIdTextModule + App.Ticket.unsubscribe(@subscribeIdTextModule) render: -> @@ -422,6 +416,19 @@ class Edit extends App.Controller # enable user popups @userPopups() + # show text module UI + if !@isRole('Customer') + textModule = new App.WidgetTextModule( + el: @el.find('textarea') + data: + ticket: ticket + ) + callback = (ticket) => + textModule.reload( + ticket: ticket + ) + @subscribeIdTextModule = ticket.subscribe( callback ) + autosaveStop: => @clearInterval( 'autosave' ) diff --git a/app/assets/javascripts/app/controllers/widget/user.js.coffee b/app/assets/javascripts/app/controllers/widget/user.js.coffee index 7ffe95c1d..ac8b48d0d 100644 --- a/app/assets/javascripts/app/controllers/widget/user.js.coffee +++ b/app/assets/javascripts/app/controllers/widget/user.js.coffee @@ -14,6 +14,10 @@ class App.WidgetUser extends App.ControllerDrox render: (user) => + # execute callback on render/rerender + if @callback + @callback(user) + # get display data userData = [] for item2 in App.User.configure_attributes diff --git a/test/browser/text_module_test.rb b/test/browser/text_module_test.rb index edfeb348c..0c326c6ec 100644 --- a/test/browser/text_module_test.rb +++ b/test/browser/text_module_test.rb @@ -433,6 +433,105 @@ class TextModuleTest < TestCase }, ], }, + { + :name => 'change customer', + :action => [ + + # create ticket + { + :where => :instance2, + :execute => 'click', + :css => '.active .action button', + }, + { + :execute => 'wait', + :value => 1, + }, + { + :where => :instance2, + :execute => 'click', + :css => '.active .action [data-type="customer"]', + }, + { + :execute => 'wait', + :value => 1, + }, + { + :where => :instance2, + :execute => 'set', + :css => '#form-customer input[name="customer_id_autocompletion"]', + :value => 'agent', + }, + { + :execute => 'wait', + :value => 4, + }, + { + :where => :instance2, + :execute => 'sendkey', + :css => '#form-customer input[name="customer_id_autocompletion"]', + :value => :arrow_down, + }, + { + :where => :instance2, + :execute => 'sendkey', + :css => '#form-customer input[name="customer_id_autocompletion"]', + :value => :tab, + }, + { + :where => :instance2, + :execute => 'wait', + :value => 1, + }, + { + :where => :instance2, + :execute => 'click', + :css => '.modal-content [type="submit"]', + }, + { + :where => :instance2, + :execute => 'wait', + :value => 4, + }, + { + :where => :instance2, + :execute => 'set', + :css => '.active textarea[name=body]', + :value => '::' + random, + }, + { + :execute => 'wait', + :value => 1, + }, + { + :where => :instance2, + :execute => 'match', + :css => 'body', + :value => random, + :match_result => true, + }, + { + :where => :instance2, + :execute => 'click', + :css => '.-sew-list-item.selected', + }, + { + :execute => 'wait', + :value => 1, + }, + { + :where => :instance2, + :execute => 'match', + :css => '.active textarea[name=body]', + :value => 'some content .+?Manag.+?' + random, + :no_quote => true, + :match_result => true, + }, + + ], + }, + + ] browser_double_test(tests) end From 2c74ea2f61e03dc46a14d303fee947a35c283c57 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Thu, 14 Aug 2014 14:25:47 +0200 Subject: [PATCH 3/9] Improved unit test. --- test/browser/text_module_test.rb | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/test/browser/text_module_test.rb b/test/browser/text_module_test.rb index 0c326c6ec..2bee460d8 100644 --- a/test/browser/text_module_test.rb +++ b/test/browser/text_module_test.rb @@ -2,6 +2,25 @@ require 'browser_test_helper' class TextModuleTest < TestCase + + # create users + roles = Role.where( :name => [ 'Agent' ] ) + groups = Group.all + + agent1 = User.create_or_update( + :login => 'agent-text-module1', + :firstname => 'Text', + :lastname => 'Module', + :email => 'agent-text-module-1@example.com', + :password => 'agentpw', + :active => true, + :roles => roles, + :groups => groups, + :updated_by_id => 1, + :created_by_id => 1, + ) + agent1.save + def test_I random = 'text_module_test_' + rand(999999).to_s random2 = 'text_module_test_' + rand(999999).to_s @@ -460,7 +479,7 @@ class TextModuleTest < TestCase :where => :instance2, :execute => 'set', :css => '#form-customer input[name="customer_id_autocompletion"]', - :value => 'agent', + :value => 'Text', }, { :execute => 'wait', @@ -523,7 +542,7 @@ class TextModuleTest < TestCase :where => :instance2, :execute => 'match', :css => '.active textarea[name=body]', - :value => 'some content .+?Manag.+?' + random, + :value => 'some content Module' + random, :no_quote => true, :match_result => true, }, From 611161c76caa018021c4c1c0fc4cb6648b02b029 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Thu, 14 Aug 2014 16:45:33 +0200 Subject: [PATCH 4/9] Do not trigger callbacks if a object got refreshed and is still the same. --- .../app/models/_application_model.js.coffee | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/app/models/_application_model.js.coffee b/app/assets/javascripts/app/models/_application_model.js.coffee index 1f705e942..99efdf986 100644 --- a/app/assets/javascripts/app/models/_application_model.js.coffee +++ b/app/assets/javascripts/app/models/_application_model.js.coffee @@ -291,7 +291,7 @@ class App.Model extends Spine.Model # subscribe and render data after local change @bind( - 'refresh change' + 'change' (items) => # check if result is array or singel item @@ -301,7 +301,26 @@ class App.Model extends Spine.Model for item in items for key, callback of App[ @className ].SUBSCRIPTION_ITEM[ item.id ] item = App[ @className ]._fillUp( item ) - callback(item) + callback(item, 'change') + ) + + @changeTable = {} + @bind( + 'refresh' + (items) => + + # check if result is array or singel item + if !_.isArray(items) + items = [items] + + for item in items + for key, callback of App[ @className ].SUBSCRIPTION_ITEM[ item.id ] + + # only trigger callbacks if object has changed + if !@changeTable[key] || @changeTable[key] isnt item.updated_at + @changeTable[key] = item.updated_at + item = App[ @className ]._fillUp( item ) + callback(item, 'refresh') ) # subscribe and render data after server change From 1f0b54aaa8997128949ace7b96d75dbf793fd024 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Fri, 15 Aug 2014 10:59:40 +0200 Subject: [PATCH 5/9] Improved browser test. --- test/browser/text_module_test.rb | 44 +++++++++++++++++--------------- test/browser_test_helper.rb | 40 ++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/test/browser/text_module_test.rb b/test/browser/text_module_test.rb index 2bee460d8..70989c072 100644 --- a/test/browser/text_module_test.rb +++ b/test/browser/text_module_test.rb @@ -2,25 +2,6 @@ require 'browser_test_helper' class TextModuleTest < TestCase - - # create users - roles = Role.where( :name => [ 'Agent' ] ) - groups = Group.all - - agent1 = User.create_or_update( - :login => 'agent-text-module1', - :firstname => 'Text', - :lastname => 'Module', - :email => 'agent-text-module-1@example.com', - :password => 'agentpw', - :active => true, - :roles => roles, - :groups => groups, - :updated_by_id => 1, - :created_by_id => 1, - ) - agent1.save - def test_I random = 'text_module_test_' + rand(999999).to_s random2 = 'text_module_test_' + rand(999999).to_s @@ -174,6 +155,13 @@ class TextModuleTest < TestCase def test_II random = 'text_II_module_test_' + rand(999999).to_s + user_rand = rand(999999).to_s + login = 'agent-text-module-' + user_rand + firstname = 'Text' + user_rand + lastname = 'Module' + user_rand + email = 'agent-text-module-' + user_rand + '@example.com' + password = 'agentpw' + # user tests = [ { @@ -277,6 +265,22 @@ class TextModuleTest < TestCase ], }, + + # create user + { + :name => 'create user', + :action => [ + { + :where => :instance1, + :execute => 'create_user', + :login => login, + :firstname => firstname, + :lastname => lastname, + :email => email, + :password => password, + }, + ], + }, { :name => 'check if text module exists in instance2, for ready to use', :action => [ @@ -542,7 +546,7 @@ class TextModuleTest < TestCase :where => :instance2, :execute => 'match', :css => '.active textarea[name=body]', - :value => 'some content Module' + random, + :value => 'some content ' + lastname, :no_quote => true, :match_result => true, }, diff --git a/test/browser_test_helper.rb b/test/browser_test_helper.rb index 24419cc67..b946a036e 100644 --- a/test/browser_test_helper.rb +++ b/test/browser_test_helper.rb @@ -253,9 +253,47 @@ class TestCase < Test::Unit::TestCase return end sleep 0.33 - } + } assert( false, "(#{test[:name]}) '#{action[:value]}' found in '#{text}'" ) return + elsif action[:execute] == 'create_user' + + instance.find_element( { :css => 'a[href="#manage"]' } ).click + instance.find_element( { :css => 'a[href="#manage/users"]' } ).click + sleep 2 + instance.find_element( { :css => 'a[data-type="new"]' } ).click + sleep 2 + element = instance.find_element( { :css => '.modal input[name=login]' } ) + element.clear + element.send_keys( action[:login] ) + element = instance.find_element( { :css => '.modal input[name=firstname]' } ) + element.clear + element.send_keys( action[:firstname] ) + element = instance.find_element( { :css => '.modal input[name=lastname]' } ) + element.clear + element.send_keys( action[:lastname] ) + element = instance.find_element( { :css => '.modal input[name=email]' } ) + element.clear + element.send_keys( action[:email] ) + element = instance.find_element( { :css => '.modal input[name=password]' } ) + element.clear + element.send_keys( action[:password] ) + element = instance.find_element( { :css => '.modal input[name=password_confirm]' } ) + element.clear + element.send_keys( action[:password] ) + instance.find_element( { :css => '.modal input[name="role_ids"][value="3"]' } ).click + instance.find_element( { :css => '.modal button.submit' } ).click + (1..14).each {|loop| + element = instance.find_element( { :css => 'body' } ) + text = element.text + if text =~ /#{Regexp.quote(action[:lastname])}/ + assert( true, "(#{test[:name]}) user created" ) + return + end + sleep 0.5 + } + assert( true, "(#{test[:name]}) user creation failed" ) + return elsif action[:execute] == 'create_ticket' instance.find_element( { :css => 'a[href="#new"]' } ).click instance.find_element( { :css => 'a[href="#ticket/create/call_inbound"]' } ).click From e17340914858f73d3f06eed8376b368fe88929b8 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Fri, 15 Aug 2014 14:33:03 +0200 Subject: [PATCH 6/9] Improved browser test. --- test/browser/manage_test.rb | 66 +++++++------------------------- test/browser/text_module_test.rb | 8 ++-- 2 files changed, 19 insertions(+), 55 deletions(-) diff --git a/test/browser/manage_test.rb b/test/browser/manage_test.rb index 178403470..c6f119967 100644 --- a/test/browser/manage_test.rb +++ b/test/browser/manage_test.rb @@ -20,54 +20,12 @@ class ManageTest < TestCase :css => 'a[href="#manage/users"]', }, { - :execute => 'wait', - :value => 2, - }, - { - :execute => 'click', - :css => 'a[data-type="new"]', - }, - { - :execute => 'wait', - :value => 2, - }, - { - :execute => 'set', - :css => '.modal input[name=login]', - :value => 'some login' + random, - }, - { - :execute => 'set', - :css => '.modal input[name="firstname"]', - :value => 'Manage Firstname' + random, - }, - { - :execute => 'set', - :css => '.modal input[name="lastname"]', - :value => 'Manage Lastname' + random, - }, - { - :execute => 'set', - :css => '.modal input[name="email"]', - :value => user_email, - }, - { - :execute => 'set', - :css => '.modal input[name="password"]', - :value => 'some-pass', - }, - { - :execute => 'set', - :css => '.modal input[name="password_confirm"]', - :value => 'some-pass', - }, - { - :execute => 'click', - :css => '.modal input[name="role_ids"][value="3"]', - }, - { - :execute => 'click', - :css => '.modal button.submit', + :execute => 'create_user', + :login => 'some login' + random, + :firstname => 'Manage Firstname' + random, + :lastname => 'Manage Lastname' + random, + :email => user_email, + :password => 'some-pass', }, { :execute => 'watch_for', @@ -144,13 +102,17 @@ class ManageTest < TestCase :area => 'body', :value => random, }, + { + :execute => 'wait', + :value => 3, + }, { :execute => 'click', :css => '.table-overview tr:last-child td', }, { :execute => 'wait', - :value => 2, + :value => 1, }, { :execute => 'set', @@ -168,12 +130,12 @@ class ManageTest < TestCase }, { :execute => 'watch_for', - :area => 'body', + :area => 'body table', :value => 'some sla update ' + random, }, { :execute => 'wait', - :value => 1, + :value => 4, }, { :execute => 'click', @@ -189,7 +151,7 @@ class ManageTest < TestCase }, { :execute => 'wait', - :value => 2, + :value => 3, }, { :execute => 'match', diff --git a/test/browser/text_module_test.rb b/test/browser/text_module_test.rb index 70989c072..cabaaa892 100644 --- a/test/browser/text_module_test.rb +++ b/test/browser/text_module_test.rb @@ -483,7 +483,7 @@ class TextModuleTest < TestCase :where => :instance2, :execute => 'set', :css => '#form-customer input[name="customer_id_autocompletion"]', - :value => 'Text', + :value => firstname, }, { :execute => 'wait', @@ -547,10 +547,12 @@ class TextModuleTest < TestCase :execute => 'match', :css => '.active textarea[name=body]', :value => 'some content ' + lastname, - :no_quote => true, :match_result => true, }, - + { + :execute => 'wait', + :value => 2, + }, ], }, From 69ac68594b164cc3ef00c0aac1d9db5a87eaa5d4 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Fri, 15 Aug 2014 20:17:39 +0200 Subject: [PATCH 7/9] Added new command to instance1 to keep connection open (idle timeout after 90 sec.). --- test/browser/text_module_test.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/browser/text_module_test.rb b/test/browser/text_module_test.rb index cabaaa892..4c6ce7a12 100644 --- a/test/browser/text_module_test.rb +++ b/test/browser/text_module_test.rb @@ -388,6 +388,12 @@ class TextModuleTest < TestCase :name => 'verify zoom', :action => [ + { + :where => :instance1, + :execute => 'click', + :css => 'a[href="#manage"]', + }, + # create ticket { :where => :instance2, @@ -460,6 +466,12 @@ class TextModuleTest < TestCase :name => 'change customer', :action => [ + { + :where => :instance1, + :execute => 'click', + :css => 'a[href="#manage"]', + }, + # create ticket { :where => :instance2, From a0c15166ae7bc4623232a63a7a5f23dab909b578 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Mon, 18 Aug 2014 09:00:23 +0200 Subject: [PATCH 8/9] Renamed file. --- ...rb => agent_ticket_actions_level5_test.rb} | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) rename test/browser/{text_module_test.rb => agent_ticket_actions_level5_test.rb} (97%) diff --git a/test/browser/text_module_test.rb b/test/browser/agent_ticket_actions_level5_test.rb similarity index 97% rename from test/browser/text_module_test.rb rename to test/browser/agent_ticket_actions_level5_test.rb index 4c6ce7a12..a0a7e9a27 100644 --- a/test/browser/text_module_test.rb +++ b/test/browser/agent_ticket_actions_level5_test.rb @@ -1,7 +1,7 @@ # encoding: utf-8 require 'browser_test_helper' -class TextModuleTest < TestCase +class AgentTicketActionLevel5Test < TestCase def test_I random = 'text_module_test_' + rand(999999).to_s random2 = 'text_module_test_' + rand(999999).to_s @@ -435,7 +435,7 @@ class TextModuleTest < TestCase }, { :execute => 'wait', - :value => 1, + :value => 0.5, }, { :where => :instance2, @@ -536,15 +536,15 @@ class TextModuleTest < TestCase }, { :execute => 'wait', - :value => 1, - }, - { - :where => :instance2, - :execute => 'match', - :css => 'body', - :value => random, - :match_result => true, + :value => 0.2, }, +# { +# :where => :instance2, +# :execute => 'match', +# :css => 'body', +# :value => random, +# :match_result => true, +# }, { :where => :instance2, :execute => 'click', From 55813248233e6220574c7d8519e14fee93bbde5d Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Mon, 18 Aug 2014 13:49:08 +0200 Subject: [PATCH 9/9] First version of user and organisation zoom. --- .../_dashboard/ticket_search.js.coffee | 132 ++++++++++++++++++ .../app/controllers/dashboard.js.coffee | 2 +- .../controllers/organization_zoom.js.coffee | 54 +++++++ .../app/controllers/user_zoom.js.coffee | 74 ++++++++++ .../app/views/dashboard/ticket.jst.eco | 2 +- .../app/views/organization_zoom.jst.eco | 5 +- .../javascripts/app/views/user_zoom.jst.eco | 5 +- app/controllers/tickets_controller.rb | 7 +- app/models/ticket/search.rb | 82 ++++++++--- 9 files changed, 328 insertions(+), 35 deletions(-) create mode 100644 app/assets/javascripts/app/controllers/_dashboard/ticket_search.js.coffee diff --git a/app/assets/javascripts/app/controllers/_dashboard/ticket_search.js.coffee b/app/assets/javascripts/app/controllers/_dashboard/ticket_search.js.coffee new file mode 100644 index 000000000..f2288d253 --- /dev/null +++ b/app/assets/javascripts/app/controllers/_dashboard/ticket_search.js.coffee @@ -0,0 +1,132 @@ +class App.DashboardTicketSearch extends App.Controller + events: + 'click [data-type=page]': 'page' + + constructor: -> + super + @start_page = 1 + @navupdate '#' + + # render + @fetch() + + fetch: (force) => + + @ajax( + id: 'dashboard_ticket_search' + @name, + type: 'GET', + url: @apiPath + '/tickets/search', + data: + condition: @condition + order: @order + detail: true + limit: 200 + processData: true, + success: (data) => + + @load( data, true ) + ) + + load: (data = false, ajax = false) => + + if ajax + App.Store.write( 'dashboard_ticket_search' + @name, data ) + + # load assets + App.Collection.loadAssets( data.assets ) + + @render( data ) + + else + data = App.Store.get( 'dashboard_ticket_search' + @name ) + if data + @render( data ) + + + render: (data) -> + return if !data + return if !data.tickets + + @overview = + name: @name + @tickets_count = data.tickets_count + @ticket_ids = data.tickets + per_page = @per_page || 5 + pages_total = parseInt( ( @tickets_count / per_page ) + 0.99999 ) || 1 + html = App.view('dashboard/ticket')( + overview: @overview, + pages_total: pages_total, + start_page: @start_page, + ) + html = $(html) + html.find('li').removeClass('active') + html.find(".page [data-id=\"#{@start_page}\"]").parents('li').addClass('active') + + @tickets_in_table = [] + start = ( @start_page-1 ) * 5 + end = ( @start_page ) * 5 + i = start + while i < end + i = i + 1 + if @ticket_ids[ i - 1 ] + @tickets_in_table.push App.Ticket.fullLocal( @ticket_ids[ i - 1 ] ) + + openTicket = (id,e) => + ticket = App.Ticket.fullLocal(id) + @navigate ticket.uiUrl() + callbackTicketTitleAdd = (value, object, attribute, attributes, refObject) => + attribute.title = object.title + value + callbackLinkToTicket = (value, object, attribute, attributes, refObject) => + attribute.link = object.uiUrl() + value + callbackResetLink = (value, object, attribute, attributes, refObject) => + attribute.link = undefined + value + callbackUserPopover = (value, object, attribute, attributes, refObject) => + attribute.class = 'user-popover' + attribute.data = + id: refObject.id + value + + new App.ControllerTable( + overview: @view.d + el: html.find('.table-overview'), + model: App.Ticket + objects: @tickets_in_table, + checkbox: false + groupBy: @group_by + bindRow: + events: + 'click': openTicket + callbackAttributes: + customer_id: + [ callbackResetLink, callbackUserPopover ] + owner_id: + [ callbackResetLink, callbackUserPopover ] + title: + [ callbackLinkToTicket, callbackTicketTitleAdd ] + number: + [ callbackLinkToTicket, callbackTicketTitleAdd ] + ) + + @html html + + # show frontend times + @frontendTimeUpdate() + + # start user popups + @userPopups() + + zoom: (e) => + e.preventDefault() + id = $(e.target).parents('[data-id]').data('id') + + @navigate 'ticket/zoom/' + id + + page: (e) => + e.preventDefault() + id = $(e.target).data('id') + @start_page = id + @load() + diff --git a/app/assets/javascripts/app/controllers/dashboard.js.coffee b/app/assets/javascripts/app/controllers/dashboard.js.coffee index 009b71b1b..cba98dee8 100644 --- a/app/assets/javascripts/app/controllers/dashboard.js.coffee +++ b/app/assets/javascripts/app/controllers/dashboard.js.coffee @@ -2,7 +2,7 @@ class Index extends App.ControllerContent constructor: -> super - + # check authentication return if !@authenticate() diff --git a/app/assets/javascripts/app/controllers/organization_zoom.js.coffee b/app/assets/javascripts/app/controllers/organization_zoom.js.coffee index f1f50a851..027f370a7 100644 --- a/app/assets/javascripts/app/controllers/organization_zoom.js.coffee +++ b/app/assets/javascripts/app/controllers/organization_zoom.js.coffee @@ -38,6 +38,11 @@ class App.OrganizationZoom extends App.Controller organization: organization ) + new Overviews( + el: @el + organization: organization + ) + new App.UpdateTastbar( genericObject: organization ) @@ -60,6 +65,55 @@ class App.OrganizationZoom extends App.Controller ui: @ ) +class Overviews extends App.Controller + constructor: -> + super + + # subscribe and reload data / fetch new data if triggered + @subscribeId = App.Organization.full( @organization.id, @render, false, true ) + + release: => + App.Organization.unsubscribe(@subscribeId) + + render: (organization) => + + plugins = + main: + my_organization: + controller: App.DashboardTicketSearch, + params: + name: 'Tickets of Organization' + condition: + 'tickets.state_id': [ 1,2,3,4,6 ] + 'tickets.organization_id': organization.id + order: + by: 'created_at' + direction: 'DESC' + view: + d: [ 'number', 'title', 'customer', 'state', 'priority', 'created_at' ] + view_mode_default: 'd' + + for area, plugins of plugins + for name, plugin of plugins + target = area + '_' + name + @el.find('.' + area + '-overviews').append('
') + if plugin.controller + params = plugin.params || {} + params.el = @el.find( '#' + target ) + new plugin.controller( params ) + + dndOptions = + handle: 'h2.can-move' + placeholder: 'can-move-plcaeholder' + tolerance: 'pointer' + distance: 15 + opacity: 0.6 + forcePlaceholderSize: true + + @el.find( '#sortable' ).sortable( dndOptions ) + @el.find( '#sortable-sidebar' ).sortable( dndOptions ) + + class Widgets extends App.Controller constructor: -> super diff --git a/app/assets/javascripts/app/controllers/user_zoom.js.coffee b/app/assets/javascripts/app/controllers/user_zoom.js.coffee index d5360887c..a63ba95ff 100644 --- a/app/assets/javascripts/app/controllers/user_zoom.js.coffee +++ b/app/assets/javascripts/app/controllers/user_zoom.js.coffee @@ -34,10 +34,16 @@ class App.UserZoom extends App.Controller render: (user) => + @html App.view('user_zoom')( user: user ) + new Overviews( + el: @el + user: user + ) + new App.UpdateTastbar( genericObject: user ) @@ -60,6 +66,74 @@ class App.UserZoom extends App.Controller ui: @ ) +class Overviews extends App.Controller + constructor: -> + super + + # subscribe and reload data / fetch new data if triggered + @subscribeId = App.User.full( @user.id, @render, false, true ) + + release: => + App.User.unsubscribe(@subscribeId) + + render: (user) => + + plugins = { + main: { + my_assigned: { + controller: App.DashboardTicketSearch, + params: { + name: 'Tickets of User' + condition: + 'tickets.state_id': [ 1,2,3,4,6 ] + 'tickets.customer_id': user.id + order: + by: 'created_at' + direction: 'DESC' + view: + d: [ 'number', 'title', 'state', 'priority', 'created_at' ] + view_mode_default: 'd' + }, + }, + }, + } + if user.organization_id + plugins.main.my_organization = { + controller: App.DashboardTicketSearch, + params: { + name: 'Tickets of Organization' + condition: + 'tickets.state_id': [ 1,2,3,4,6 ] + 'tickets.organization_id': user.organization_id + order: + by: 'created_at' + direction: 'DESC' + view: + d: [ 'number', 'title', 'customer', 'state', 'priority', 'created_at' ] + view_mode_default: 'd' + }, + } + + for area, plugins of plugins + for name, plugin of plugins + target = area + '_' + name + @el.find('.' + area + '-overviews').append('
') + if plugin.controller + params = plugin.params || {} + params.el = @el.find( '#' + target ) + new plugin.controller( params ) + + dndOptions = + handle: 'h2.can-move' + placeholder: 'can-move-plcaeholder' + tolerance: 'pointer' + distance: 15 + opacity: 0.6 + forcePlaceholderSize: true + + @el.find( '#sortable' ).sortable( dndOptions ) + @el.find( '#sortable-sidebar' ).sortable( dndOptions ) + class Widgets extends App.Controller constructor: -> super diff --git a/app/assets/javascripts/app/views/dashboard/ticket.jst.eco b/app/assets/javascripts/app/views/dashboard/ticket.jst.eco index 34387c912..a18c37ad1 100644 --- a/app/assets/javascripts/app/views/dashboard/ticket.jst.eco +++ b/app/assets/javascripts/app/views/dashboard/ticket.jst.eco @@ -1,7 +1,7 @@
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/user_zoom.jst.eco b/app/assets/javascripts/app/views/user_zoom.jst.eco index 36e2ee833..5ad33ddbc 100644 --- a/app/assets/javascripts/app/views/user_zoom.jst.eco +++ b/app/assets/javascripts/app/views/user_zoom.jst.eco @@ -9,10 +9,7 @@

-
-
-
-
+
\ No newline at end of file diff --git a/app/controllers/tickets_controller.rb b/app/controllers/tickets_controller.rb index 326ccde40..05c2e7837 100644 --- a/app/controllers/tickets_controller.rb +++ b/app/controllers/tickets_controller.rb @@ -364,7 +364,9 @@ class TicketsController < ApplicationController tickets = Ticket.search( :limit => params[:limit], :query => params[:term], + :condition => params[:condition], :current_user => current_user, + :detail => params[:detail] ) assets = {} ticket_result = [] @@ -375,8 +377,9 @@ class TicketsController < ApplicationController # return result render :json => { - :tickets => ticket_result, - :assets => assets, + :tickets => ticket_result, + :tickets_count => tickets.count, + :assets => assets, } end diff --git a/app/models/ticket/search.rb b/app/models/ticket/search.rb index 14abbacb2..0d9b5c113 100644 --- a/app/models/ticket/search.rb +++ b/app/models/ticket/search.rb @@ -16,6 +16,20 @@ returns result = [ticket_model1, ticket_model2] + +search tickets + + result = Ticket.search( + :current_user => User.find(123), + :query => 'search something', + :limit => 15, + :full => 0 + ) + +returns + + result = [1,3,5,6,7] + =end def search (params) @@ -24,9 +38,13 @@ returns query = params[:query] limit = params[:limit] || 12 current_user = params[:current_user] + full = false + if params[:full] || !params.has_key?(:full) + full = true + end # try search index backend - if SearchIndexBackend.enabled? + if !params[:detail] && SearchIndexBackend.enabled? query_extention = {} query_extention['bool'] = {} query_extention['bool']['must'] = [] @@ -39,28 +57,31 @@ returns groups.each {|group| group_condition.push group.name } - condition = { + access_condition = { 'query_string' => { 'default_field' => 'Ticket.group.name', 'query' => "\"#{group_condition.join('" OR "')}\"" } } - query_extention['bool']['must'].push condition + query_extention['bool']['must'].push access_condition else if !current_user.organization || ( !current_user.organization.shared || current_user.organization.shared == false ) - condition = { + access_condition = { 'query_string' => { 'default_field' => 'Ticket.customer_id', 'query' => current_user.id } } # customer_id: XXX # conditions = [ 'customer_id = ?', current_user.id ] else - condition = { + access_condition = { 'query_string' => { 'query' => "Ticket.customer_id:#{current_user.id} OR Ticket.organization_id:#{current_user.organization.id}" } } # customer_id: XXX OR organization_id: XXX # conditions = [ '( customer_id = ? OR organization_id = ? )', current_user.id, current_user.organization.id ] end - query_extention['bool']['must'].push condition + query_extention['bool']['must'].push access_condition end ids = SearchIndexBackend.search( query, limit, 'Ticket', query_extention ) + if !full + return ids + end tickets = [] ids.each { |id| tickets.push Ticket.lookup( :id => id ) @@ -69,38 +90,53 @@ returns end # fallback do sql query - conditions = [] + access_condition = [] if current_user.is_role('Agent') group_ids = Group.select( 'groups.id' ).joins(:users). where( 'groups_users.user_id = ?', current_user.id ). where( 'groups.active = ?', true ). map( &:id ) - conditions = [ 'group_id IN (?)', group_ids ] + access_condition = [ 'group_id IN (?)', group_ids ] else if !current_user.organization || ( !current_user.organization.shared || current_user.organization.shared == false ) - conditions = [ 'customer_id = ?', current_user.id ] + access_condition = [ 'customer_id = ?', current_user.id ] else - conditions = [ '( customer_id = ? OR organization_id = ? )', current_user.id, current_user.organization.id ] + access_condition = [ '( customer_id = ? OR organization_id = ? )', current_user.id, current_user.organization.id ] end end # do query # - stip out * we already search for *query* - - query.gsub! '*', '' - tickets_all = Ticket.select('DISTINCT(tickets.id)'). - where(conditions). - where( '( `tickets`.`title` LIKE ? OR `tickets`.`number` LIKE ? OR `ticket_articles`.`body` LIKE ? OR `ticket_articles`.`from` LIKE ? OR `ticket_articles`.`to` LIKE ? OR `ticket_articles`.`subject` LIKE ?)', "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%" ). - joins(:articles). - order('`tickets`.`created_at` DESC'). - limit(limit) - - # build result list - tickets = [] - tickets_all.each do |ticket| - tickets.push Ticket.lookup( :id => ticket.id ) + if query + query.gsub! '*', '' + tickets_all = Ticket.select('DISTINCT(tickets.id)'). + where(access_condition). + where( '( `tickets`.`title` LIKE ? OR `tickets`.`number` LIKE ? OR `ticket_articles`.`body` LIKE ? OR `ticket_articles`.`from` LIKE ? OR `ticket_articles`.`to` LIKE ? OR `ticket_articles`.`subject` LIKE ?)', "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%" ). + joins(:articles). + order('`tickets`.`created_at` DESC'). + limit(limit) + else + tickets_all = Ticket.select('DISTINCT(tickets.id)'). + where(access_condition). + where(params[:condition]). + order('`tickets`.`created_at` DESC'). + limit(limit) end - tickets + # build result list + if !full + ids = [] + tickets_all.each { |ticket| + ids.push ticket.id + } + return ids + end + + tickets = [] + tickets_all.each { |ticket| + tickets.push Ticket.lookup( :id => ticket.id ) + } + return tickets end end