From 4d8270b84f62e7107e214ce879a3d3049757a023 Mon Sep 17 00:00:00 2001 From: Johannes Nickel Date: Wed, 29 May 2013 17:11:11 +0200 Subject: [PATCH 01/17] first stage --- app/controllers/taskbar_controller.rb | 56 +++++++++++++++++++ app/models/taskbar.rb | 11 ++++ config/routes/taskbar.rb | 10 ++++ .../20130529124443_task_manager_states.rb | 17 ++++++ 4 files changed, 94 insertions(+) create mode 100644 app/controllers/taskbar_controller.rb create mode 100644 app/models/taskbar.rb create mode 100644 config/routes/taskbar.rb create mode 100644 db/migrate/20130529124443_task_manager_states.rb diff --git a/app/controllers/taskbar_controller.rb b/app/controllers/taskbar_controller.rb new file mode 100644 index 000000000..7f77c9030 --- /dev/null +++ b/app/controllers/taskbar_controller.rb @@ -0,0 +1,56 @@ +class TaskbarController < ApplicationController + before_filter :authentication_check + + def index + + current_user_tasks = Taskbar.where(:user_id=>current_user.id) + model_index_render_result(current_user_tasks) + + end + + def show + taskbar = Taskbar.find(params[:id]) + + if taskbar.user_id != current_user.id + render :json => { :error => 'Not allowed to show this task.' }, :status => :unprocessable_entity + return + end + + model_show_render_item(taskbar) + end + + def create + + params[:user_id] = current_user.id + model_create_render(taskbar,params) + + end + + def update + params[:user_id] = current_user.id + taskbar = Taskbar.find(params[:id]) + + if taskbar.user_id != current_user.id + render :json => { :error => 'Not allowed to update this task.' }, :status => :unprocessable_entity + return + end + + model_update_render_item(taskbar, params) + + end + + def destroy + + params[:user_id] = current_user.id + taskbar = Taskbar.find(params[:id]) + + if taskbar.user_id != current_user.id + render :json => { :error => 'Not allowed to delete this task.' }, :status => :unprocessable_entity + return + end + + model_destory_render_item(taskbar) + taskbar.destroy + + end +end diff --git a/app/models/taskbar.rb b/app/models/taskbar.rb new file mode 100644 index 000000000..e0c4226c6 --- /dev/null +++ b/app/models/taskbar.rb @@ -0,0 +1,11 @@ +class Taskbar < ApplicationModel + +store :state, :params +before_create :update_time +before_update :update_time + +private + def update_last_contact + self.last_contact = Time.now + end +end \ No newline at end of file diff --git a/config/routes/taskbar.rb b/config/routes/taskbar.rb new file mode 100644 index 000000000..c965055ec --- /dev/null +++ b/config/routes/taskbar.rb @@ -0,0 +1,10 @@ +module ExtraRoutes + def add(map) + map.match '/api/taskbar', :to => 'taskbar#index', :via => :get + map.match '/api/taskbar/:id', :to => 'taskbar#show', :via => :get + map.match '/api/taskbar', :to => 'taskbar#create', :via => :post + map.match '/api/taskbar/:id', :to => 'taskbar#update', :via => :put + map.match '/api/taskbar/:id', :to => 'taskbar#destroy', :via => :delete + end + module_function :add +end diff --git a/db/migrate/20130529124443_task_manager_states.rb b/db/migrate/20130529124443_task_manager_states.rb new file mode 100644 index 000000000..994bfe34c --- /dev/null +++ b/db/migrate/20130529124443_task_manager_states.rb @@ -0,0 +1,17 @@ +class TaskManagerStates < ActiveRecord::Migration + def up + create_table :taskbars do |t| + t.column :user_id, :integer, :null => false + t.column :last_contact, :datetime, :null => false + t.column :client_id, :string, :null => false + t.column :state, :string, :limit => 8000,:null => true + t.column :params, :string, :limit => 2000,:null => true + t.timestamps + end + + end + + def down + drop_table :taskbars + end +end From a8849b9183efe09fd5569e10441c7de350fe023f Mon Sep 17 00:00:00 2001 From: Johannes Nickel Date: Thu, 30 May 2013 10:24:09 +0200 Subject: [PATCH 02/17] fixed small typos --- app/controllers/taskbar_controller.rb | 2 +- app/models/taskbar.rb | 7 ++++--- ...43_task_manager_states.rb => 20130529124443_taskbar.rb} | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) rename db/migrate/{20130529124443_task_manager_states.rb => 20130529124443_taskbar.rb} (89%) diff --git a/app/controllers/taskbar_controller.rb b/app/controllers/taskbar_controller.rb index 7f77c9030..b71796547 100644 --- a/app/controllers/taskbar_controller.rb +++ b/app/controllers/taskbar_controller.rb @@ -22,7 +22,7 @@ class TaskbarController < ApplicationController def create params[:user_id] = current_user.id - model_create_render(taskbar,params) + model_create_render(Taskbar,params) end diff --git a/app/models/taskbar.rb b/app/models/taskbar.rb index e0c4226c6..9fca405a1 100644 --- a/app/models/taskbar.rb +++ b/app/models/taskbar.rb @@ -1,8 +1,9 @@ class Taskbar < ApplicationModel -store :state, :params -before_create :update_time -before_update :update_time +store :state +store :params +before_create :update_last_contact +before_update :update_last_contact private def update_last_contact diff --git a/db/migrate/20130529124443_task_manager_states.rb b/db/migrate/20130529124443_taskbar.rb similarity index 89% rename from db/migrate/20130529124443_task_manager_states.rb rename to db/migrate/20130529124443_taskbar.rb index 994bfe34c..5d897780d 100644 --- a/db/migrate/20130529124443_task_manager_states.rb +++ b/db/migrate/20130529124443_taskbar.rb @@ -1,4 +1,4 @@ -class TaskManagerStates < ActiveRecord::Migration +class Taskbar < ActiveRecord::Migration def up create_table :taskbars do |t| t.column :user_id, :integer, :null => false From 745dbf40a1e7a1ddc947c4fa595c357854369d30 Mon Sep 17 00:00:00 2001 From: Johannes Nickel Date: Fri, 31 May 2013 17:16:33 +0200 Subject: [PATCH 03/17] updated taskbar controller --- app/controllers/taskbar_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/taskbar_controller.rb b/app/controllers/taskbar_controller.rb index b71796547..daf255395 100644 --- a/app/controllers/taskbar_controller.rb +++ b/app/controllers/taskbar_controller.rb @@ -35,7 +35,7 @@ class TaskbarController < ApplicationController return end - model_update_render_item(taskbar, params) + model_update_render_item(taskbar) end @@ -49,7 +49,7 @@ class TaskbarController < ApplicationController return end - model_destory_render_item(taskbar) + model_destory_render_item() taskbar.destroy end From a0ab8b30c35c3ece0eb90dfdf20ef7265b59ee2e Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 29 May 2013 17:07:27 +0200 Subject: [PATCH 04/17] Fixed controller name. --- config/routes/text_module.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config/routes/text_module.rb b/config/routes/text_module.rb index e6548fdfc..542ff1875 100644 --- a/config/routes/text_module.rb +++ b/config/routes/text_module.rb @@ -2,11 +2,11 @@ module ExtraRoutes def add(map) # roles - map.match '/api/text_modules', :to => 'text_modules#index', :via => :get - map.match '/api/text_modules/:id', :to => 'text_modules#show', :via => :get - map.match '/api/text_modules', :to => 'text_modules#create', :via => :post - map.match '/api/text_modules/:id', :to => 'text_modules#update', :via => :put - map.match '/api/text_modules/:id', :to => 'templates#destroy', :via => :delete + map.match '/api/text_modules', :to => 'text_modules#index', :via => :get + map.match '/api/text_modules/:id', :to => 'text_modules#show', :via => :get + map.match '/api/text_modules', :to => 'text_modules#create', :via => :post + map.match '/api/text_modules/:id', :to => 'text_modules#update', :via => :put + map.match '/api/text_modules/:id', :to => 'text_modules#destroy', :via => :delete end module_function :add From dfec4e5bd565353aa1ad1cbd42187aa4a8c559c1 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 29 May 2013 17:07:45 +0200 Subject: [PATCH 05/17] Prepared fror rails 4. --- config/routes/ticket.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/routes/ticket.rb b/config/routes/ticket.rb index bbea66ddf..50b4a72fe 100644 --- a/config/routes/ticket.rb +++ b/config/routes/ticket.rb @@ -12,7 +12,7 @@ module ExtraRoutes map.match '/api/ticket_history/:id', :to => 'tickets#ticket_history', :via => :get map.match '/api/ticket_customer', :to => 'tickets#ticket_customer', :via => :get map.match '/api/ticket_merge_list/:ticket_id', :to => 'tickets#ticket_merge_list', :via => :get - map.match '/api/ticket_merge/:slave_ticket_id/:master_ticket_number', :to => 'tickets#ticket_merge' + map.match '/api/ticket_merge/:slave_ticket_id/:master_ticket_number', :to => 'tickets#ticket_merge', :via => :get # ticket overviews map.match '/api/ticket_overviews', :to => 'ticket_overviews#show', :via => :get @@ -34,10 +34,10 @@ module ExtraRoutes map.match '/api/ticket_articles/:id', :to => 'ticket_articles#show', :via => :get map.match '/api/ticket_articles', :to => 'ticket_articles#create', :via => :post map.match '/api/ticket_articles/:id', :to => 'ticket_articles#update', :via => :put - map.match '/api/ticket_attachment/:ticket_id/:article_id/:id', :to => 'ticket_articles#attachment' - map.match '/api/ticket_attachment_new', :to => 'ticket_articles#attachment_new' + map.match '/api/ticket_attachment/:ticket_id/:article_id/:id', :to => 'ticket_articles#attachment', :via => :get + map.match '/api/ticket_attachment_new', :to => 'ticket_articles#attachment_new', :via => :post map.match '/api/ticket_article_plain/:id', :to => 'ticket_articles#article_plain', :via => :get end module_function :add -end \ No newline at end of file +end From 18defadb71b99d7057829eb69f0c077a34084ca4 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 29 May 2013 17:09:08 +0200 Subject: [PATCH 06/17] Prepared for rails 4. --- db/migrate/20120101000020_create_network.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/db/migrate/20120101000020_create_network.rb b/db/migrate/20120101000020_create_network.rb index cc7130721..d963d1661 100644 --- a/db/migrate/20120101000020_create_network.rb +++ b/db/migrate/20120101000020_create_network.rb @@ -19,7 +19,7 @@ class CreateNetwork < ActiveRecord::Migration t.timestamps end add_index :network_category_types, [:name], :unique => true - + create_table :network_privacies do |t| t.column :name, :string, :limit => 100, :null => false t.column :key, :string, :limit => 250, :null => false @@ -51,7 +51,7 @@ class CreateNetwork < ActiveRecord::Migration create_table :network_items do |t| t.references :network_category, :null => false t.column :title, :string, :limit => 200, :null => false - t.column :body, :string, :limit => 25000, :null => false + t.column :body, :string, :limit => 20000, :null => false t.column :updated_by_id, :integer, :null => false t.column :created_by_id, :integer, :null => false t.timestamps @@ -60,13 +60,13 @@ class CreateNetwork < ActiveRecord::Migration create_table :network_item_comments do |t| t.references :network_item, :null => false - t.column :body, :string, :limit => 25000, :null => false + t.column :body, :string, :limit => 20000, :null => false t.column :updated_by_id, :integer, :null => false t.column :created_by_id, :integer, :null => false t.timestamps end add_index :network_item_comments, [:network_item_id] - + create_table :network_item_plus do |t| t.references :network_item, :null => false t.column :updated_by_id, :integer, :null => false @@ -90,7 +90,7 @@ class CreateNetwork < ActiveRecord::Migration t.timestamps end add_index :network_item_subscriptions, [:network_item_id, :created_by_id], :unique => true, :name => 'index_network_item_subscriptions_on_item_id_and_created_by_id' - + end def down From c58485281f80b86c18ef2dbf29588b678fccffa0 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 29 May 2013 17:11:34 +0200 Subject: [PATCH 07/17] Prepard for rails 4. --- config/routes/tag.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/routes/tag.rb b/config/routes/tag.rb index e6a615ace..dc40d1727 100644 --- a/config/routes/tag.rb +++ b/config/routes/tag.rb @@ -2,10 +2,10 @@ module ExtraRoutes def add(map) # links - map.match '/api/tags', :to => 'tags#list' - map.match '/api/tags/add', :to => 'tags#add' - map.match '/api/tags/remove', :to => 'tags#remove' + map.match '/api/tags', :to => 'tags#list', :via => :get + map.match '/api/tags/add', :to => 'tags#add', :via => :get + map.match '/api/tags/remove', :to => 'tags#remove', :via => :get end module_function :add -end \ No newline at end of file +end From b41907fafeab445506425d93d450e3fe45443cd3 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 29 May 2013 17:12:03 +0200 Subject: [PATCH 08/17] Prepared for rails 4. --- config/routes/link.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/routes/link.rb b/config/routes/link.rb index 89b7faeb0..086f413c6 100644 --- a/config/routes/link.rb +++ b/config/routes/link.rb @@ -2,10 +2,10 @@ module ExtraRoutes def add(map) # links - map.match '/api/links', :to => 'links#index' - map.match '/api/links/add', :to => 'links#add' - map.match '/api/links/remove', :to => 'links#remove' + map.match '/api/links', :to => 'links#index', :via => :get + map.match '/api/links/add', :to => 'links#add', :via => :get + map.match '/api/links/remove', :to => 'links#remove', :via => :get end module_function :add -end \ No newline at end of file +end From fc679889a0839db698a47943d5ca829350f1d665 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 29 May 2013 18:03:59 +0200 Subject: [PATCH 09/17] Prepared for rails 4. --- config/routes.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index b4e6d3154..c22f52dc3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,12 +1,12 @@ Zammad::Application.routes.draw do # app init - match '/init', :to => 'init#index' - match '/app', :to => 'init#index' + match '/init', :to => 'init#index', :via => :get + match '/app', :to => 'init#index', :via => :get # You can have the root of your site routed with "root" # just remember to delete public/index.html. - root :to => 'init#index' + root :to => 'init#index', :via => :get # load routes from external files dir = File.expand_path('../', __FILE__) From 239a945ebcb39b75bb81990cc8a7ee47e888a873 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 29 May 2013 18:05:50 +0200 Subject: [PATCH 10/17] Removed not needed gems. --- Gemfile | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Gemfile b/Gemfile index 04c907f93..291107dca 100644 --- a/Gemfile +++ b/Gemfile @@ -24,11 +24,6 @@ group :assets do gem 'uglifier', '>= 1.2.3' end -gem 'jquery-rails' - -# Optional support for eco templates -gem 'eco' - gem 'omniauth' gem 'omniauth-twitter' gem 'omniauth-facebook' From b3517969862b03a0ac47aca756ef0b5251a93657 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 29 May 2013 18:09:02 +0200 Subject: [PATCH 11/17] Raise exception if save or update failed. --- app/controllers/application_controller.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 791616002..b4d5fe246 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -213,9 +213,11 @@ class ApplicationController < ActionController::Base generic_object = object.new( object.param_cleanup(params) ) # save object - generic_object.save + generic_object.save! + model_create_render_item(generic_object) rescue Exception => e + puts e.message.inspect logger.error e.message render :json => { :error => e.message }, :status => :unprocessable_entity end @@ -231,7 +233,7 @@ class ApplicationController < ActionController::Base generic_object = object.find( params[:id] ) # save object - generic_object.update_attributes( object.param_cleanup(params) ) + generic_object.update_attributes!( object.param_cleanup(params) ) model_update_render_item(generic_object) rescue Exception => e logger.error e.message From c8e0d631ca0bab9777e2e54c9eaf4f3bfabbcc33 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Thu, 30 May 2013 00:25:04 +0200 Subject: [PATCH 12/17] Added init version of auto save. --- .../controllers/agent_ticket_create.js.coffee | 19 +++++- .../controllers/agent_ticket_zoom.js.coffee | 53 +++++++++++------ .../app/controllers/task_widget.js.coffee | 2 - .../app/lib/app_post/task_manager.js.coffee | 58 +++++++++++++++++-- 4 files changed, 106 insertions(+), 26 deletions(-) diff --git a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee index 092f38a09..8a5b5e1e9 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee @@ -49,6 +49,9 @@ class App.TicketCreate extends App.Controller @log 'AgentTicketPhone', 'error', defaults @render(defaults) + # start auto save + @autosave() + meta: => text = App.i18n.translateInline( @article_attributes['title'] ) subject = @el.find('[name=subject]').val() @@ -66,7 +69,7 @@ class App.TicketCreate extends App.Controller activate: => @navupdate '#' @title @article_attributes['title'] - + changed: => formCurrent = @formParam( @el.find('.ticket-create') ) diff = difference( @formDefault, formCurrent ) @@ -76,6 +79,18 @@ class App.TicketCreate extends App.Controller release: => # @clearInterval( @key, 'ticket_zoom' ) @el.remove() + @clearInterval( @id, @auto_save_key ) + + autosave: => + @auto_save_key = 'create' + @type + @id + update = => + data = @formParam( @el.find('.ticket-create') ) + diff = difference( @autosaveLast, data ) + if !@autosaveLast || ( diff && !_.isEmpty( diff ) ) + @autosaveLast = data + console.log('form hash changed', diff, data) + App.TaskManager.update( @task_key, { 'state': data }) + @interval( update, 10000, @id, @auto_save_key ) # get data / in case also ticket data for split fetch: (params) -> @@ -135,7 +150,7 @@ class App.TicketCreate extends App.Controller render: (template = {}) -> # set defaults - defaults = template['options'] || {} + defaults = template['options'] || @form_state || {} if !( 'ticket_state_id' of defaults ) defaults['ticket_state_id'] = App.Collection.findByAttribute( 'TicketState', 'name', 'open' ).id if !( 'ticket_priority_id' of defaults ) diff --git a/app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee index 93399684e..aedaae759 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee @@ -34,6 +34,9 @@ class App.TicketZoom extends App.Controller @fetch( @ticket_id, false) @interval( update, 30000, @key, 'ticket_zoom' ) + # start auto save + @autosave() + meta: => return if !@ticket meta = @@ -62,6 +65,17 @@ class App.TicketZoom extends App.Controller @clearInterval( @key, 'ticket_zoom' ) @el.remove() + autosave: => + @auto_save_key = 'zoom' + @id + update = => + data = @formParam( @el.find('.ticket-update') ) + diff = difference( @autosaveLast, data ) + if !@autosaveLast || ( diff && !_.isEmpty( diff ) ) + @autosaveLast = data + console.log('form hash changed', diff, data) + App.TaskManager.update( @task_key, { 'state': data }) + @interval( update, 10000, @id, @auto_save_key ) + fetch: (ticket_id, force) -> return if !@Session.all() @@ -141,34 +155,36 @@ class App.TicketZoom extends App.Controller for article in @articles new Article( article: article ) + defaults = @form_state || {} + @configure_attributes_ticket = [ - { name: 'ticket_state_id', display: 'State', tag: 'select', multiple: false, null: true, relation: 'TicketState', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' }, - { name: 'ticket_priority_id', display: 'Priority', tag: 'select', multiple: false, null: true, relation: 'TicketPriority', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' }, - { name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: true, relation: 'Group', filter: @edit_form, class: 'span2', item_class: 'pull-left' }, - { name: 'owner_id', display: 'Owner', tag: 'select', multiple: false, null: true, relation: 'User', filter: @edit_form, nulloption: true, class: 'span2', item_class: 'pull-left' }, + { name: 'ticket_state_id', display: 'State', tag: 'select', multiple: false, null: true, relation: 'TicketState', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left', default: defaults['ticket_state_id'] }, + { name: 'ticket_priority_id', display: 'Priority', tag: 'select', multiple: false, null: true, relation: 'TicketPriority', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left', default: defaults['ticket_priority_id'] }, + { name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: true, relation: 'Group', filter: @edit_form, class: 'span2', item_class: 'pull-left', default: defaults['group_id'] }, + { name: 'owner_id', display: 'Owner', tag: 'select', multiple: false, null: true, relation: 'User', filter: @edit_form, nulloption: true, class: 'span2', item_class: 'pull-left', default: defaults['owner_id'] }, ] if @isRole('Customer') @configure_attributes_ticket = [ - { name: 'ticket_state_id', display: 'State', tag: 'select', multiple: false, null: true, relation: 'TicketState', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' }, - { name: 'ticket_priority_id', display: 'Priority', tag: 'select', multiple: false, null: true, relation: 'TicketPriority', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left' }, + { name: 'ticket_state_id', display: 'State', tag: 'select', multiple: false, null: true, relation: 'TicketState', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left', default: defaults['ticket_state_id'] }, + { name: 'ticket_priority_id', display: 'Priority', tag: 'select', multiple: false, null: true, relation: 'TicketPriority', filter: @edit_form, translate: true, class: 'span2', item_class: 'pull-left', default: defaults['ticket_priority_id'] }, ] @configure_attributes_article = [ - { name: 'ticket_article_type_id', display: 'Type', tag: 'select', multiple: false, null: true, relation: 'TicketArticleType', filter: @edit_form, default: '9', translate: true, class: 'medium', item_class: '' }, - { name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, - { name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, - { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, - { name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, - { name: 'body', display: 'Text', tag: 'textarea', rows: 6, limit: 100, null: true, class: 'span7', item_class: '', upload: true }, - { name: 'internal', display: 'Visability', tag: 'select', default: false, null: true, options: { true: 'internal', false: 'public' }, class: 'medium', item_class: '' }, + { name: 'ticket_article_type_id', display: 'Type', tag: 'select', multiple: false, null: true, relation: 'TicketArticleType', filter: @edit_form, default: '9', translate: true, class: 'medium', item_class: '', default: defaults['ticket_article_type_id'] }, + { name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide', default: defaults['to'] }, + { name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide', default: defaults['cc'] }, + { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide', default: defaults['subject'] }, + { name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide', default: defaults['in_reply_to'] }, + { name: 'body', display: 'Text', tag: 'textarea', rows: 6, limit: 100, null: true, class: 'span7', item_class: '', upload: true, default: defaults['body'] }, + { name: 'internal', display: 'Visability', tag: 'select', default: false, null: true, options: { true: 'internal', false: 'public' }, class: 'medium', item_class: '', default: defaults['internal'] }, ] if @isRole('Customer') @configure_attributes_article = [ - { name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, - { name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, - { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, - { name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide' }, - { name: 'body', display: 'Text', tag: 'textarea', rows: 6, limit: 100, null: true, class: 'span7', item_class: '', upload: true }, + { name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide', default: defaults['to'] }, + { name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide', default: defaults['cc'] }, + { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide', default: defaults['subject'] }, + { name: 'in_reply_to', display: 'In Reply to', tag: 'input', type: 'text', limit: 100, null: true, class: 'span7', item_class: 'hide', default: defaults['in_reply_to'] }, + { name: 'body', display: 'Text', tag: 'textarea', rows: 6, limit: 100, null: true, class: 'span7', item_class: '', upload: true, default: defaults['body'] }, ] @html App.view('agent_ticket_zoom')( @@ -623,6 +639,7 @@ class TicketZoomRouter extends App.ControllerPermanent constructor: (params) -> super @log 'zoom router', params + # cleanup params clean_params = ticket_id: params.ticket_id diff --git a/app/assets/javascripts/app/controllers/task_widget.js.coffee b/app/assets/javascripts/app/controllers/task_widget.js.coffee index de52791b8..3e345d870 100644 --- a/app/assets/javascripts/app/controllers/task_widget.js.coffee +++ b/app/assets/javascripts/app/controllers/task_widget.js.coffee @@ -15,8 +15,6 @@ class App.TaskWidget extends App.Controller App.TaskManager.reset() @el.html('') - App.TaskManager.syncInitial() - sync = => App.TaskManager.sync() @delay( sync, 3000, 'task-widget' ) diff --git a/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee b/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee index 892170bf2..d43aca9c8 100644 --- a/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee +++ b/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee @@ -9,16 +9,21 @@ class App.TaskManager _instance ?= new _Singleton _instance.all() - @add: ( type, type_id, callback, params, to_not_show ) -> + @add: ( type, type_id, callback, params, to_not_show, state ) -> if _instance == undefined _instance ?= new _Singleton - _instance.add( type, type_id, callback, params, to_not_show ) + _instance.add( type, type_id, callback, params, to_not_show, state ) @get: ( key ) -> if _instance == undefined _instance ?= new _Singleton _instance.get( key ) + @update: ( key, params ) -> + if _instance == undefined + _instance ?= new _Singleton + _instance.update( key, params ) + @remove: ( key ) -> if _instance == undefined _instance ?= new _Singleton @@ -39,6 +44,11 @@ class App.TaskManager _instance ?= new _Singleton _instance.syncTasksInitial() + @syncSave: -> + if _instance == undefined + _instance ?= new _Singleton + _instance.syncSave() + @sync: -> if _instance == undefined _instance ?= new _Singleton @@ -50,11 +60,12 @@ class _Singleton extends App.Controller constructor: -> @tasks = {} @task_count = 0 + @syncTasksInitial() all: -> @tasks - add: ( type, type_id, callback, params, to_not_show = false ) -> + add: ( type, type_id, callback, params, to_not_show = false, state ) -> for key, task of @tasks if task.type is type && task.type_id is type_id return key if to_not_show @@ -99,6 +110,13 @@ class _Singleton extends App.Controller params_app = _.clone(params) params_app['el'] = $('#content_permanent_' + @task_count ) params_app['task_key'] = @task_count + + # check if we have old state there + if !state + oldTask = @get_by_type( type, type_id ) + if oldTask + state = oldTask.state + params_app['form_state'] = state if to_not_show params_app['doNotLog'] = 1 a = new App[callback]( params_app ) @@ -128,6 +146,12 @@ class _Singleton extends App.Controller get: ( key ) => return @tasks[key] + update: ( key, params ) => + return false if !@tasks[key] + for item, value of params + @tasks[key][item] = value + @syncSave() + remove: ( key, to_not_show = false ) => if @tasks[key] @tasks[key].worker.release() @@ -143,6 +167,11 @@ class _Singleton extends App.Controller @tasks = {} App.Event.trigger 'ui:rerender' + get_by_type: (type, type_id) => + store = @syncLoad() || [] + for item in store + return item if item.type is type && item.type_id is type_id + syncAdd: (task) => store = @syncLoad() || [] for item in store @@ -163,6 +192,27 @@ class _Singleton extends App.Controller storeNew.push item App.Store.write( 'tasks', storeNew ) + syncSave: => + store = @syncLoad() || [] + storeNew = [] + for item in store + for key, task of @tasks + if task.type is item.type && task.type_id is item.type_id + console.log('MATCH', item) + if @tasks[key]['state'] + item['state'] = @tasks[key]['state'] + storeNew.push item +# if @tasks[key] +# @tasks[key].worker.release() +# +# storeNew.push item +# item = +# type: task.type +# type_id: task.type_id +# params: task.params +# callback: task.callback + App.Store.write( 'tasks', storeNew ) + syncLoad: => App.Store.get( 'tasks' ) @@ -176,7 +226,7 @@ class _Singleton extends App.Controller @delay( => task = store.shift() - @add(task.type, task.type_id, task.callback, task.params, true) + @add(task.type, task.type_id, task.callback, task.params, true, task.state) task_count * 500 ) From 5bc2de1597707d68f5e39b3386fb469b47b4c7b7 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Fri, 31 May 2013 01:33:20 +0200 Subject: [PATCH 13/17] Added eco gem. --- Gemfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Gemfile b/Gemfile index 291107dca..fc071a547 100644 --- a/Gemfile +++ b/Gemfile @@ -7,6 +7,8 @@ gem 'rails', '3.2.13' #gem 'rails-observers' #gem 'activerecord-session_store' +gem 'eco' + # Bundle edge Rails instead: #gem 'rails', :git => 'git://github.com/rails/rails.git' From 60ed0a21c9a63b5c815f256a85020ad643d13f35 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Fri, 31 May 2013 13:29:48 +0200 Subject: [PATCH 14/17] Rewritten taskbar manager. --- .../controllers/agent_ticket_create.js.coffee | 4 +- .../controllers/agent_ticket_merge.js.coffee | 2 +- .../controllers/agent_ticket_zoom.js.coffee | 9 +- .../app/controllers/task_widget.js.coffee | 49 +-- .../app/lib/app_post/task_manager.js.coffee | 300 ++++++++---------- .../javascripts/app/views/task_widget.jst.eco | 4 +- app/assets/javascripts/application.js | 1 + 7 files changed, 173 insertions(+), 196 deletions(-) diff --git a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee index 8a5b5e1e9..fe91d8159 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee @@ -89,7 +89,7 @@ class App.TicketCreate extends App.Controller if !@autosaveLast || ( diff && !_.isEmpty( diff ) ) @autosaveLast = data console.log('form hash changed', diff, data) - App.TaskManager.update( @task_key, { 'state': data }) + App.TaskManager.update( 'TicketCreateScreen', @type + '-' + @id, { 'state': data }) @interval( update, 10000, @id, @auto_save_key ) # get data / in case also ticket data for split @@ -302,7 +302,7 @@ class App.TicketCreate extends App.Controller # create new create screen # ui.render() - App.TaskManager.remove( ui.task_key ) + App.TaskManager.remove( 'TicketCreateScreen', ui.type + '-' + ui.id ) # scroll to top ui.scrollTo() diff --git a/app/assets/javascripts/app/controllers/agent_ticket_merge.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_merge.js.coffee index 42c09b701..b2255d688 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_merge.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_merge.js.coffee @@ -133,7 +133,7 @@ class App.TicketMerge extends App.ControllerModal msg: App.i18n.translateContent( 'Ticket %s merged!', data.slave_ticket['number'] ), timeout: 4000, - App.TaskManager.remove( @task_key ) + App.TaskManager.remove( 'Ticket', data.slave_ticket['id'] ) else diff --git a/app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee index aedaae759..1ad04e10c 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee @@ -11,7 +11,7 @@ class App.TicketZoom extends App.Controller constructor: (params) -> super - @log 'zoom', params +# console.log 'zoom', params # check authentication return if !@authenticate() @@ -31,7 +31,7 @@ class App.TicketZoom extends App.Controller if cache @load(cache) update = => - @fetch( @ticket_id, false) + @fetch( @ticket_id, false ) @interval( update, 30000, @key, 'ticket_zoom' ) # start auto save @@ -73,7 +73,7 @@ class App.TicketZoom extends App.Controller if !@autosaveLast || ( diff && !_.isEmpty( diff ) ) @autosaveLast = data console.log('form hash changed', diff, data) - App.TaskManager.update( @task_key, { 'state': data }) + App.TaskManager.update( 'Ticket', @ticket_id, { 'state': data }) @interval( update, 10000, @id, @auto_save_key ) fetch: (ticket_id, force) -> @@ -93,7 +93,7 @@ class App.TicketZoom extends App.Controller return if _.isEqual( @dataLastCall.ticket, data.ticket) diff = difference( @dataLastCall.ticket, data.ticket ) console.log('diff', diff) - App.TaskManager.notify(@task_key) + App.TaskManager.notify( 'Ticket', @ticket_id ) if $('[name="body"]').val() App.Event.trigger 'notify', { type: 'success' @@ -293,7 +293,6 @@ class App.TicketZoom extends App.Controller internal = true if article.internal == true internal = false - article.updateAttributes( internal: internal ) diff --git a/app/assets/javascripts/app/controllers/task_widget.js.coffee b/app/assets/javascripts/app/controllers/task_widget.js.coffee index 3e345d870..6b235579f 100644 --- a/app/assets/javascripts/app/controllers/task_widget.js.coffee +++ b/app/assets/javascripts/app/controllers/task_widget.js.coffee @@ -10,37 +10,31 @@ class App.TaskWidget extends App.Controller App.Event.bind 'ui:rerender', (data) => @render() - # rebuild chat widget + # rebuild taskbar widget App.Event.bind 'auth', (user) => App.TaskManager.reset() @el.html('') - sync = => - App.TaskManager.sync() - @delay( sync, 3000, 'task-widget' ) - - @delay( sync, 5000, 'task-widget' ) - render: -> return if _.isEmpty( @Session.all() ) tasks = App.TaskManager.all() item_list = [] - for key, task of tasks + for task in tasks data = url: '#' id: false title: App.i18n.translateInline('Loading...') head: App.i18n.translateInline('Loading...') - if task.worker - meta = task.worker.meta() + worker = App.TaskManager.worker( task.type, task.type_id ) + if worker + meta = worker.meta() if meta data = meta data.title = App.i18n.escape( data.title ) data.head = App.i18n.escape( data.head ) item = {} - item.key = key item.task = task item.data = data item_list.push item @@ -52,34 +46,41 @@ class App.TaskWidget extends App.Controller remove: (e) => e.preventDefault() - key = $(e.target).parent().data('id') + type_id = $(e.target).parent().data('type-id') + type = $(e.target).parent().data('type') + if !type_id && !type + throw "No such type and type-id attributes found for task item" # check if input has changed - task = App.TaskManager.get( key ) - if task.worker && task.worker.changed - if task.worker.changed() + worker = App.TaskManager.worker( type, type_id ) + if worker && worker.changed + if worker.changed() return if !window.confirm( App.i18n.translateInline('Tab has changed, you really want to close it?') ) # check if active task is closed - task_last = undefined - tasks_all = App.TaskManager.all() + currentTask = App.TaskManager.get( type, type_id ) + tasks = App.TaskManager.all() active_is_closed = false - for task_key, task of tasks_all - if task.active && task_key.toString() is key.toString() + for task in tasks + if currentTask.active && task.type is type && task.type_id.toString() is type_id.toString() active_is_closed = true # remove task - App.TaskManager.remove( key ) + App.TaskManager.remove( type, type_id ) @render() # navigate to next task if needed - if active_is_closed && !_.isEmpty( tasks_all ) - for key, task of tasks_all + tasks = App.TaskManager.all() + if active_is_closed && !_.isEmpty( tasks ) + task_last = undefined + for task in tasks task_last = task if task_last - @navigate task_last.worker.url() + worker = App.TaskManager.worker( task_last.type, task_last.type_id ) + if worker + @navigate worker.url() return - if _.isEmpty( tasks_all ) + if _.isEmpty( tasks ) @navigate '#' _getTaskActions: -> diff --git a/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee b/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee index d43aca9c8..3b21e534b 100644 --- a/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee +++ b/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee @@ -14,240 +14,216 @@ class App.TaskManager _instance ?= new _Singleton _instance.add( type, type_id, callback, params, to_not_show, state ) - @get: ( key ) -> + @get: ( type, type_id ) -> if _instance == undefined _instance ?= new _Singleton - _instance.get( key ) + _instance.get( type, type_id ) - @update: ( key, params ) -> + @update: ( type, type_id, params ) -> if _instance == undefined _instance ?= new _Singleton - _instance.update( key, params ) + _instance.update( type, type_id, params ) - @remove: ( key ) -> + @remove: ( type, type_id ) -> if _instance == undefined _instance ?= new _Singleton - _instance.remove( key ) + _instance.remove( type, type_id ) - @notify: ( key ) -> + @notify: ( type, type_id ) -> if _instance == undefined _instance ?= new _Singleton - _instance.notify( key ) + _instance.notify( type, type_id ) @reset: -> if _instance == undefined _instance ?= new _Singleton _instance.reset() - @syncInitial: -> + @worker: ( type, type_id ) -> if _instance == undefined _instance ?= new _Singleton - _instance.syncTasksInitial() + _instance.worker( type, type_id ) - @syncSave: -> + @workerAll: -> if _instance == undefined _instance ?= new _Singleton - _instance.syncSave() - - @sync: -> - if _instance == undefined - _instance ?= new _Singleton - _instance.syncTasks() + _instance.workerAll() class _Singleton extends App.Controller @include App.Log constructor: -> - @tasks = {} - @task_count = 0 - @syncTasksInitial() - + @workers = {} + @workersStarted = {} + @activeTask = undefined + @tasksInitial() + all: -> - @tasks + App.Taskbar.all() + + worker: ( type, type_id ) -> + key = @keyGenerate(type, type_id) + return @workers[ key ] if @workers[ key ] + return + + workerAll: -> + @workers add: ( type, type_id, callback, params, to_not_show = false, state ) -> - for key, task of @tasks - if task.type is type && task.type_id is type_id - return key if to_not_show - $('#content').empty() - $('.content_permanent').hide() - $('.content_permanent').removeClass('active') - $('#content_permanent_' + key ).show() - $('#content_permanent_' + key ).addClass('active') - @tasks[key].worker.activate() - @tasks[key].notify = false - for task_key, task of @tasks - if task_key isnt key - task.active = false - else - task.active = true - App.Event.trigger 'ui:rerender' - App.Event.trigger 'ui:rerender:content' - return key - - @task_count++ - if !to_not_show - for task_key, task of @tasks - task.active = false active = true if to_not_show active = false + + # create new task if not exists + task = @get( type, type_id ) +# console.log('add', type, type_id, callback, params, to_not_show, state, task) + if !task + task = new App.Taskbar + task.load( + type: type + type_id: type_id + params: params + callback: callback + notify: false + active: active + ) + task.save() + + tasks = @all() + + # empty static content if task is shown + key = @keyGenerate(type, type_id) if active + @activeTask = key $('#content').empty() - $('#content_permanent').append('
') - - if active + # hide all tasks $('.content_permanent').hide() $('.content_permanent').removeClass('active') - $('#content_permanent_' + @task_count ).show() - $('#content_permanent_' + @task_count ).addClass('active') + + # create div for task if not exists + if !$("#content_permanent_#{key}")[0] + $('#content_permanent').append('
') + + # set task to shown and active + if @activeTask is key + $('#content_permanent_' + key ).show() + $('#content_permanent_' + key ).addClass('active') else - $('#content_permanent_' + @task_count ).removeClass('active') - $('#content_permanent_' + @task_count ).hide() + $('#content_permanent_' + key ).hide() + $('#content_permanent_' + key ).removeClass('active') + + # set all tasks to active false, only new/selected one to active + if active + for task in tasks + task_key = @keyGenerate(task.type, task.type_id) + if task_key isnt key + task.active = false + else + task.active = true + task.save() + else + for task in tasks + task_key = @keyGenerate(task.type, task.type_id) + if @activeTask isnt task_key + if task.active + task.active = false + task.save() + + # start worker for task if not exists + @startController(type, type_id, callback, params, state, key, to_not_show) + + App.Event.trigger 'ui:rerender' + App.Event.trigger 'ui:rerender:content' + return key + + startController: (type, type_id, callback, params, state, key, to_not_show) => + +# console.log('controller started...', callback, type, type_id, params, state) + + # activate controller + worker = @worker( type, type_id ) + if worker && worker.activate + worker.activate() + + # return if controller is alreary started + return if @workersStarted[key] + @workersStarted[key] = true # create new controller instanz params_app = _.clone(params) - params_app['el'] = $('#content_permanent_' + @task_count ) - params_app['task_key'] = @task_count + params_app['el'] = $('#content_permanent_' + key ) + params_app['task_key'] = key # check if we have old state there if !state - oldTask = @get_by_type( type, type_id ) + oldTask = @get( type, type_id ) if oldTask state = oldTask.state params_app['form_state'] = state + if to_not_show params_app['doNotLog'] = 1 a = new App[callback]( params_app ) - - # remember new controller / prepare for task storage - task = - type: type - type_id: type_id - params: params - callback: callback - worker: a - active: active - @tasks[@task_count] = task + @workers[ key ] = a # activate controller if !to_not_show a.activate() - App.Event.trigger 'ui:rerender' + return a - # add new controller to task storage - if !to_not_show - @syncAdd(task) + get: ( type, type_id ) => + tasks = App.Taskbar.all() + for task in tasks + return task if task.type is type && task.type_id.toString() is type_id.toString() + return +# throw "No such task with '#{type}' and '#{type_id}'" - @task_count - - get: ( key ) => - return @tasks[key] - - update: ( key, params ) => - return false if !@tasks[key] + update: ( type, type_id, params ) => + task = @get( type, type_id ) + if !task + throw "No such task with '#{type}' and '#{type_id}' to update" for item, value of params - @tasks[key][item] = value - @syncSave() + task.updateAttribute(item, value) +# task.save() - remove: ( key, to_not_show = false ) => - if @tasks[key] - @tasks[key].worker.release() - if !to_not_show - @syncRemove( @tasks[key] ) - delete @tasks[key] + remove: ( type, type_id, to_not_show = false ) => + task = @get( type, type_id ) + if !task + throw "No such task with '#{type}' and '#{type_id}' to remove" + + worker = @worker( type, type_id ) + if worker && worker.release + worker.release() + @workersStarted[ @keyGenerate(type, type_id) ] = false + task.destroy() App.Event.trigger 'ui:rerender' - notify: ( key ) => - @tasks[key].notify = true + notify: ( type, type_id ) => + task = @get( type, type_id ) + if !task + throw "No such task with '#{type}' and '#{type_id}' to notify" + task.notify = true reset: => - @tasks = {} + App.Taskbar.deleteAll() App.Event.trigger 'ui:rerender' - get_by_type: (type, type_id) => - store = @syncLoad() || [] - for item in store - return item if item.type is type && item.type_id is type_id - - syncAdd: (task) => - store = @syncLoad() || [] - for item in store - return if item.type is task.type && item.type_id is task.type_id - item = - type: task.type - type_id: task.type_id - params: task.params - callback: task.callback - store.push item - App.Store.write( 'tasks', store ) - - syncRemove: (task) => - store = @syncLoad() || [] - storeNew = [] - for item in store - if item.type isnt task.type || item.type_id isnt task.type_id - storeNew.push item - App.Store.write( 'tasks', storeNew ) - - syncSave: => - store = @syncLoad() || [] - storeNew = [] - for item in store - for key, task of @tasks - if task.type is item.type && task.type_id is item.type_id - console.log('MATCH', item) - if @tasks[key]['state'] - item['state'] = @tasks[key]['state'] - storeNew.push item -# if @tasks[key] -# @tasks[key].worker.release() -# -# storeNew.push item -# item = -# type: task.type -# type_id: task.type_id -# params: task.params -# callback: task.callback - App.Store.write( 'tasks', storeNew ) - - syncLoad: => - App.Store.get( 'tasks' ) - - syncTasksInitial: => + tasksInitial: => # reopen tasks - store = _.clone(@syncLoad()) - return if !store + App.Taskbar.fetch() + tasks = @all() + return if !tasks task_count = 0 - for task in store + for task in tasks task_count += 1 @delay( => - task = store.shift() + task = tasks.shift() @add(task.type, task.type_id, task.callback, task.params, true, task.state) task_count * 500 ) - syncTasks: => - store = @syncLoad() || [] - - # open tasks - for item in store - existsLocal = false - for task_key, task of @tasks - if item.type is task.type && item.type_id is task.type_id - # also open here - existsLocal = true - if !existsLocal - @add(item.type, item.type_id, item.callback, item.params, true) - - # close tasks - for task_key, task of @tasks - onlyLocal = true - for item in store - if item.type is task.type && item.type_id is task.type_id - onlyLocal = false - if onlyLocal - @remove( task_key, true ) + keyGenerate: ( type, type_id )-> + "#{type}_#{type_id}" diff --git a/app/assets/javascripts/app/views/task_widget.jst.eco b/app/assets/javascripts/app/views/task_widget.jst.eco index d01b2af76..fb1cedc9b 100644 --- a/app/assets/javascripts/app/views/task_widget.jst.eco +++ b/app/assets/javascripts/app/views/task_widget.jst.eco @@ -1,6 +1,6 @@ -
+
<% for item in @item_list: %> - <%- item.data.head %> + <%- item.data.head %> <% end %> <% if !_.isEmpty( @taskBarActions ): %>
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 96e379f6c..c48fe7f4f 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -12,6 +12,7 @@ //not_used= require_tree ./app/lib/spine //= require ./app/lib/spine/spine.js //= require ./app/lib/spine/ajax.js +//= require ./app/lib/spine/local.js //= require ./app/lib/spine/route.js //= require ./app/lib/flot/jquery.flot.js From 6d3bc3d227103c5815dc2635a437feea1455ac46 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Fri, 31 May 2013 13:34:11 +0200 Subject: [PATCH 15/17] Improved tests. --- test/browser/agent_ticket_actions_simple_test.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/browser/agent_ticket_actions_simple_test.rb b/test/browser/agent_ticket_actions_simple_test.rb index af069c12d..5ce519851 100644 --- a/test/browser/agent_ticket_actions_simple_test.rb +++ b/test/browser/agent_ticket_actions_simple_test.rb @@ -99,6 +99,11 @@ class AgentTicketActionSimpleTest < TestCase }, # update ticket + { + :execute => 'select', + :css => 'select[name="ticket_article_type_id"]', + :value => 'note', + }, { :execute => 'check', :css => 'textarea[name="body"]', @@ -216,6 +221,11 @@ class AgentTicketActionSimpleTest < TestCase }, # update ticket + { + :execute => 'select', + :css => 'select[name="ticket_article_type_id"]', + :value => 'note', + }, { :execute => 'check', :css => '.content_permanent.active textarea[name="body"]', From 19079731cb3239240b6c4a705f80b1732cc927b5 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Sat, 1 Jun 2013 01:09:09 +0200 Subject: [PATCH 16/17] Rewrite of taskbar manager. --- .../controllers/agent_ticket_create.js.coffee | 17 +-- .../controllers/agent_ticket_merge.js.coffee | 4 +- .../controllers/agent_ticket_zoom.js.coffee | 28 ++--- .../app/controllers/task_widget.js.coffee | 22 ++-- .../app/lib/app_post/task_manager.js.coffee | 112 +++++++++--------- .../javascripts/app/models/taskbar.js.coffee | 7 +- .../javascripts/app/views/task_widget.jst.eco | 4 +- app/controllers/sessions/collection_base.rb | 2 +- app/controllers/taskbar_controller.rb | 50 ++++---- db/migrate/20130529124443_taskbar.rb | 9 +- 10 files changed, 126 insertions(+), 129 deletions(-) diff --git a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee index fe91d8159..84d3ff611 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee @@ -50,7 +50,10 @@ class App.TicketCreate extends App.Controller @render(defaults) # start auto save - @autosave() + @delay( + => @autosave(), + 5000 + ) meta: => text = App.i18n.translateInline( @article_attributes['title'] ) @@ -68,7 +71,7 @@ class App.TicketCreate extends App.Controller activate: => @navupdate '#' - @title @article_attributes['title'] + @title @meta().title changed: => formCurrent = @formParam( @el.find('.ticket-create') ) @@ -89,7 +92,7 @@ class App.TicketCreate extends App.Controller if !@autosaveLast || ( diff && !_.isEmpty( diff ) ) @autosaveLast = data console.log('form hash changed', diff, data) - App.TaskManager.update( 'TicketCreateScreen', @type + '-' + @id, { 'state': data }) + App.TaskManager.update( @task_key, { 'state': data }) @interval( update, 10000, @id, @auto_save_key ) # get data / in case also ticket data for split @@ -164,7 +167,7 @@ class App.TicketCreate extends App.Controller # defaults['customer_id'] = '2' # defaults['customer_id_autocompletion'] = '12312313' - # generate form + # generate form configure_attributes = [ { name: 'customer_id', display: 'Customer', tag: 'autocompletion', type: 'text', limit: 200, null: false, relation: 'User', class: 'span7', autocapitalize: false, help: 'Select the customer of the Ticket or create one.', link: '»', callback: @localUserInfo }, { name: 'group_id', display: 'Group', tag: 'select', multiple: false, null: false, filter: @edit_form, nulloption: true, relation: 'Group', default: defaults['group_id'], class: 'span7', }, @@ -296,13 +299,13 @@ class App.TicketCreate extends App.Controller # notify UI ui.notify type: 'success', - msg: App.i18n.translateContent( 'Ticket %s created!', @number ), + msg: App.i18n.translateInline( 'Ticket %s created!', @number ), link: "#ticket/zoom/#{@id}" timeout: 12000, # create new create screen # ui.render() - App.TaskManager.remove( 'TicketCreateScreen', ui.type + '-' + ui.id ) + App.TaskManager.remove( ui.task_key ) # scroll to top ui.scrollTo() @@ -394,7 +397,7 @@ class TicketCreateRouter extends App.ControllerPermanent type: params.type id: params.id - App.TaskManager.add( 'TicketCreateScreen', params['type'] + '-' + params['id'], 'TicketCreate', clean_params ) + App.TaskManager.add( 'TicketCreateScreen-' + params['type'] + '-' + params['id'], 'TicketCreate', clean_params ) # split ticket App.Config.set( 'ticket_create/:ticket_id/:article_id', TicketCreateRouter, 'Routes' ) diff --git a/app/assets/javascripts/app/controllers/agent_ticket_merge.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_merge.js.coffee index b2255d688..04504f1fc 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_merge.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_merge.js.coffee @@ -133,7 +133,7 @@ class App.TicketMerge extends App.ControllerModal msg: App.i18n.translateContent( 'Ticket %s merged!', data.slave_ticket['number'] ), timeout: 4000, - App.TaskManager.remove( 'Ticket', data.slave_ticket['id'] ) + App.TaskManager.remove( 'Ticket-' + data.slave_ticket['id'] ) else @@ -144,4 +144,4 @@ class App.TicketMerge extends App.ControllerModal timeout: 6000, # error: => ) - + diff --git a/app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee index 1ad04e10c..4820db2bc 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee @@ -34,14 +34,11 @@ class App.TicketZoom extends App.Controller @fetch( @ticket_id, false ) @interval( update, 30000, @key, 'ticket_zoom' ) - # start auto save - @autosave() - meta: => return if !@ticket meta = url: @url() - head: @ticket.title + head: @ticket.title + ' ' + @ticket.title title: @ticket.number + ' ' + @ticket.title id: @ticket.id @@ -51,9 +48,9 @@ class App.TicketZoom extends App.Controller activate: => @navupdate '#' if @ticket - @title 'Ticket Zoom ' + @ticket.number -# else -# @title 'Loading...' + @title App.i18n.translateInline('Ticket Zoom') + ' ' + @ticket.number + ' ' + @ticket.title + else + @title App.i18n.translateInline('Loading...') changed: => formCurrent = @formParam( @el.find('.ticket-update') ) @@ -73,7 +70,7 @@ class App.TicketZoom extends App.Controller if !@autosaveLast || ( diff && !_.isEmpty( diff ) ) @autosaveLast = data console.log('form hash changed', diff, data) - App.TaskManager.update( 'Ticket', @ticket_id, { 'state': data }) + App.TaskManager.update( @task_key, { 'state': data }) @interval( update, 10000, @id, @auto_save_key ) fetch: (ticket_id, force) -> @@ -82,7 +79,7 @@ class App.TicketZoom extends App.Controller # get data App.Com.ajax( - id: 'ticket_zoom_' + ticket_id + id: 'ticket_zoom_' + ticket_id type: 'GET' url: 'api/ticket_full/' + ticket_id + '?do_not_log=' + @doNotLog data: @@ -93,11 +90,11 @@ class App.TicketZoom extends App.Controller return if _.isEqual( @dataLastCall.ticket, data.ticket) diff = difference( @dataLastCall.ticket, data.ticket ) console.log('diff', diff) - App.TaskManager.notify( 'Ticket', @ticket_id ) + App.TaskManager.notify( @task_key ) if $('[name="body"]').val() App.Event.trigger 'notify', { type: 'success' - msg: App.i18n.translateContent('Ticket has changed!') + msg: App.i18n.translateInline('Ticket has changed!') timeout: 30000 } return @@ -106,6 +103,9 @@ class App.TicketZoom extends App.Controller @load(data) App.Store.write( @key, data ) + # start auto save + @autosave() + error: (xhr, status, error) => # do not close window if request is abort or network error exists @@ -392,7 +392,7 @@ class App.TicketZoom extends App.Controller if selectedText body = @el.find('[name="body"]').val() || '' selectedText = selectedText.replace /^(.*)$/mg, (match) => - '> ' + match + '> ' + match body = selectedText + "\n" + body @el.find('[name="body"]').val(body) @@ -645,8 +645,8 @@ class TicketZoomRouter extends App.ControllerPermanent article_id: params.article_id nav: params.nav - App.TaskManager.add( 'Ticket', @ticket_id, 'TicketZoom', clean_params ) + App.TaskManager.add( 'Ticket-' + @ticket_id, 'TicketZoom', clean_params ) App.Config.set( 'ticket/zoom/:ticket_id', TicketZoomRouter, 'Routes' ) App.Config.set( 'ticket/zoom/:ticket_id/nav/:nav', TicketZoomRouter, 'Routes' ) -App.Config.set( 'ticket/zoom/:ticket_id/:article_id', TicketZoomRouter, 'Routes' ) \ No newline at end of file +App.Config.set( 'ticket/zoom/:ticket_id/:article_id', TicketZoomRouter, 'Routes' ) diff --git a/app/assets/javascripts/app/controllers/task_widget.js.coffee b/app/assets/javascripts/app/controllers/task_widget.js.coffee index 6b235579f..73ef89084 100644 --- a/app/assets/javascripts/app/controllers/task_widget.js.coffee +++ b/app/assets/javascripts/app/controllers/task_widget.js.coffee @@ -27,7 +27,7 @@ class App.TaskWidget extends App.Controller id: false title: App.i18n.translateInline('Loading...') head: App.i18n.translateInline('Loading...') - worker = App.TaskManager.worker( task.type, task.type_id ) + worker = App.TaskManager.worker( task.key ) if worker meta = worker.meta() if meta @@ -46,27 +46,26 @@ class App.TaskWidget extends App.Controller remove: (e) => e.preventDefault() - type_id = $(e.target).parent().data('type-id') - type = $(e.target).parent().data('type') - if !type_id && !type - throw "No such type and type-id attributes found for task item" + key = $(e.target).parent().data('key') + if !key + throw "No such key attributes found for task item" # check if input has changed - worker = App.TaskManager.worker( type, type_id ) + worker = App.TaskManager.worker( key ) if worker && worker.changed if worker.changed() return if !window.confirm( App.i18n.translateInline('Tab has changed, you really want to close it?') ) # check if active task is closed - currentTask = App.TaskManager.get( type, type_id ) + currentTask = App.TaskManager.get( key ) tasks = App.TaskManager.all() active_is_closed = false for task in tasks - if currentTask.active && task.type is type && task.type_id.toString() is type_id.toString() + if currentTask.active && task.key is key active_is_closed = true # remove task - App.TaskManager.remove( type, type_id ) + App.TaskManager.remove( key ) @render() # navigate to next task if needed @@ -76,11 +75,11 @@ class App.TaskWidget extends App.Controller for task in tasks task_last = task if task_last - worker = App.TaskManager.worker( task_last.type, task_last.type_id ) + worker = App.TaskManager.worker( task_last.key ) if worker @navigate worker.url() return - if _.isEmpty( tasks ) + if _.isEmpty( tasks ) @navigate '#' _getTaskActions: -> @@ -108,5 +107,4 @@ class App.TaskWidget extends App.Controller level1.push item level1 - App.Config.set( 'task', App.TaskWidget, 'Widgets' ) diff --git a/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee b/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee index 3b21e534b..f6d445404 100644 --- a/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee +++ b/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee @@ -9,40 +9,40 @@ class App.TaskManager _instance ?= new _Singleton _instance.all() - @add: ( type, type_id, callback, params, to_not_show, state ) -> + @add: ( key, callback, params, to_not_show, state ) -> if _instance == undefined _instance ?= new _Singleton - _instance.add( type, type_id, callback, params, to_not_show, state ) + _instance.add( key, callback, params, to_not_show, state ) - @get: ( type, type_id ) -> + @get: ( key ) -> if _instance == undefined _instance ?= new _Singleton - _instance.get( type, type_id ) + _instance.get( key ) - @update: ( type, type_id, params ) -> + @update: ( key, params ) -> if _instance == undefined _instance ?= new _Singleton - _instance.update( type, type_id, params ) + _instance.update( key, params ) - @remove: ( type, type_id ) -> + @remove: ( key ) -> if _instance == undefined _instance ?= new _Singleton - _instance.remove( type, type_id ) + _instance.remove( key ) - @notify: ( type, type_id ) -> + @notify: ( key ) -> if _instance == undefined _instance ?= new _Singleton - _instance.notify( type, type_id ) + _instance.notify( key ) @reset: -> if _instance == undefined _instance ?= new _Singleton _instance.reset() - @worker: ( type, type_id ) -> + @worker: ( key ) -> if _instance == undefined _instance ?= new _Singleton - _instance.worker( type, type_id ) + _instance.worker( key ) @workerAll: -> if _instance == undefined @@ -57,42 +57,40 @@ class _Singleton extends App.Controller @workersStarted = {} @activeTask = undefined @tasksInitial() - + all: -> App.Taskbar.all() - worker: ( type, type_id ) -> - key = @keyGenerate(type, type_id) + worker: ( key ) -> return @workers[ key ] if @workers[ key ] return workerAll: -> @workers - add: ( type, type_id, callback, params, to_not_show = false, state ) -> + add: ( key, callback, params, to_not_show = false, state ) -> active = true if to_not_show active = false # create new task if not exists - task = @get( type, type_id ) -# console.log('add', type, type_id, callback, params, to_not_show, state, task) + task = @get( key ) +# console.log('add', key, callback, params, to_not_show, state, task) if !task task = new App.Taskbar task.load( - type: type - type_id: type_id + key: key params: params callback: callback + client_id: 123 notify: false active: active ) task.save() - + tasks = @all() # empty static content if task is shown - key = @keyGenerate(type, type_id) if active @activeTask = key $('#content').empty() @@ -116,37 +114,41 @@ class _Singleton extends App.Controller # set all tasks to active false, only new/selected one to active if active for task in tasks - task_key = @keyGenerate(task.type, task.type_id) - if task_key isnt key - task.active = false - else - task.active = true - task.save() - else - for task in tasks - task_key = @keyGenerate(task.type, task.type_id) - if @activeTask isnt task_key + if task.key isnt key if task.active task.active = false + console.log(111, 'save') + task.save() + else + if !task.active + console.log(222, 'save') + task.active = true + task.save() + else + for task in tasks + if @activeTask isnt task.key + if task.active + task.active = false + console.log(333, 'save') task.save() # start worker for task if not exists - @startController(type, type_id, callback, params, state, key, to_not_show) + @startController(key, callback, params, state, to_not_show) App.Event.trigger 'ui:rerender' App.Event.trigger 'ui:rerender:content' return key - startController: (type, type_id, callback, params, state, key, to_not_show) => + startController: (key, callback, params, state, to_not_show) => -# console.log('controller started...', callback, type, type_id, params, state) +# console.log('controller started...', callback, key, params, state) # activate controller - worker = @worker( type, type_id ) + worker = @worker( key ) if worker && worker.activate worker.activate() - # return if controller is alreary started + # return if controller is alreary started return if @workersStarted[key] @workersStarted[key] = true @@ -157,7 +159,7 @@ class _Singleton extends App.Controller # check if we have old state there if !state - oldTask = @get( type, type_id ) + oldTask = @get( key ) if oldTask state = oldTask.state params_app['form_state'] = state @@ -173,37 +175,37 @@ class _Singleton extends App.Controller return a - get: ( type, type_id ) => + get: ( key ) => tasks = App.Taskbar.all() for task in tasks - return task if task.type is type && task.type_id.toString() is type_id.toString() + return task if task.key is key return -# throw "No such task with '#{type}' and '#{type_id}'" +# throw "No such task with '#{key}'" - update: ( type, type_id, params ) => - task = @get( type, type_id ) + update: ( key, params ) => + task = @get( key ) if !task - throw "No such task with '#{type}' and '#{type_id}' to update" + throw "No such task with '#{key}' to update" for item, value of params task.updateAttribute(item, value) # task.save() - remove: ( type, type_id, to_not_show = false ) => - task = @get( type, type_id ) + remove: ( key, to_not_show = false ) => + task = @get( key ) if !task - throw "No such task with '#{type}' and '#{type_id}' to remove" + throw "No such task with '#{key}' to remove" - worker = @worker( type, type_id ) + worker = @worker( key ) if worker && worker.release worker.release() - @workersStarted[ @keyGenerate(type, type_id) ] = false + @workersStarted[ key ] = false task.destroy() App.Event.trigger 'ui:rerender' - notify: ( type, type_id ) => - task = @get( type, type_id ) + notify: ( key ) => + task = @get( key ) if !task - throw "No such task with '#{type}' and '#{type_id}' to notify" + throw "No such task with '#{key}' to notify" task.notify = true reset: => @@ -212,7 +214,7 @@ class _Singleton extends App.Controller tasksInitial: => # reopen tasks - App.Taskbar.fetch() +# App.Taskbar.fetch() tasks = @all() return if !tasks task_count = 0 @@ -221,9 +223,7 @@ class _Singleton extends App.Controller @delay( => task = tasks.shift() - @add(task.type, task.type_id, task.callback, task.params, true, task.state) + @add(task.key, task.callback, task.params, true, task.state) task_count * 500 ) - keyGenerate: ( type, type_id )-> - "#{type}_#{type_id}" diff --git a/app/assets/javascripts/app/models/taskbar.js.coffee b/app/assets/javascripts/app/models/taskbar.js.coffee index 506d2e0f7..137a0429c 100644 --- a/app/assets/javascripts/app/models/taskbar.js.coffee +++ b/app/assets/javascripts/app/models/taskbar.js.coffee @@ -1,4 +1,5 @@ class App.Taskbar extends App.Model - @configure 'Taskbar', 'type', 'type_id', 'callback', 'state', 'params', 'notify', 'active' - @extend Spine.Model.Local -# @url: 'api/taskbar' + @configure 'Taskbar', 'key', 'client_id', 'callback', 'state', 'params', 'notify', 'active' +# @extend Spine.Model.Local + @extend Spine.Model.Ajax + @url: 'api/taskbar' diff --git a/app/assets/javascripts/app/views/task_widget.jst.eco b/app/assets/javascripts/app/views/task_widget.jst.eco index fb1cedc9b..109aa8a2e 100644 --- a/app/assets/javascripts/app/views/task_widget.jst.eco +++ b/app/assets/javascripts/app/views/task_widget.jst.eco @@ -1,6 +1,6 @@ -
+
<% for item in @item_list: %> - <%- item.data.head %> + <%- item.data.head %> <% end %> <% if !_.isEmpty( @taskBarActions ): %>
diff --git a/app/controllers/sessions/collection_base.rb b/app/controllers/sessions/collection_base.rb index 3827228d5..235833414 100644 --- a/app/controllers/sessions/collection_base.rb +++ b/app/controllers/sessions/collection_base.rb @@ -2,7 +2,7 @@ module ExtraCollection def session( collections, user ) # all base stuff - collections['Taskbar'] = Taskbar.all + collections['Taskbar'] = Taskbar.where( :user_id => user.id ) collections['Role'] = Role.all collections['Group'] = Group.all diff --git a/app/controllers/taskbar_controller.rb b/app/controllers/taskbar_controller.rb index daf255395..f16b1c1ed 100644 --- a/app/controllers/taskbar_controller.rb +++ b/app/controllers/taskbar_controller.rb @@ -2,55 +2,47 @@ class TaskbarController < ApplicationController before_filter :authentication_check def index - - current_user_tasks = Taskbar.where(:user_id=>current_user.id) + + current_user_tasks = Taskbar.where( :user_id => current_user.id ) model_index_render_result(current_user_tasks) - + end def show - taskbar = Taskbar.find(params[:id]) + taskbar = Taskbar.find( params[:id] ) + return if !access(taskbar) - if taskbar.user_id != current_user.id - render :json => { :error => 'Not allowed to show this task.' }, :status => :unprocessable_entity - return - end - model_show_render_item(taskbar) end def create - params[:user_id] = current_user.id model_create_render(Taskbar,params) - end def update + taskbar = Taskbar.find( params[:id] ) + return if !access(taskbar) + params[:user_id] = current_user.id - taskbar = Taskbar.find(params[:id]) - - if taskbar.user_id != current_user.id - render :json => { :error => 'Not allowed to update this task.' }, :status => :unprocessable_entity - return - end - + taskbar.update_attributes!( Taskbar.param_cleanup(params) ) model_update_render_item(taskbar) - end def destroy - - params[:user_id] = current_user.id - taskbar = Taskbar.find(params[:id]) + taskbar = Taskbar.find( params[:id] ) + return if !access(taskbar) - if taskbar.user_id != current_user.id - render :json => { :error => 'Not allowed to delete this task.' }, :status => :unprocessable_entity - return - end - - model_destory_render_item() taskbar.destroy - + model_destory_render_item() end + + private + def access(taskbar) + if taskbar.user_id != current_user.id + render :json => { :error => 'Not allowed to access this task.' }, :status => :unprocessable_entity + return false + end + return true + end end diff --git a/db/migrate/20130529124443_taskbar.rb b/db/migrate/20130529124443_taskbar.rb index 5d897780d..1e6ba3325 100644 --- a/db/migrate/20130529124443_taskbar.rb +++ b/db/migrate/20130529124443_taskbar.rb @@ -4,11 +4,14 @@ class Taskbar < ActiveRecord::Migration t.column :user_id, :integer, :null => false t.column :last_contact, :datetime, :null => false t.column :client_id, :string, :null => false - t.column :state, :string, :limit => 8000,:null => true - t.column :params, :string, :limit => 2000,:null => true + t.column :key, :string, :limit => 100, :null => false + t.column :callback, :string, :limit => 100, :null => false + t.column :state, :string, :limit => 8000, :null => true + t.column :params, :string, :limit => 2000, :null => true + t.column :notify, :boolean, :null => false, :default => false + t.column :active, :boolean, :null => false, :default => false t.timestamps end - end def down From 886a249aee3e6887b8a994f553357a04fc1cae7b Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Sat, 1 Jun 2013 01:10:40 +0200 Subject: [PATCH 17/17] Improved code layout. --- app/models/taskbar.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/app/models/taskbar.rb b/app/models/taskbar.rb index 9fca405a1..48a41813e 100644 --- a/app/models/taskbar.rb +++ b/app/models/taskbar.rb @@ -1,12 +1,11 @@ class Taskbar < ApplicationModel + store :state + store :params + before_create :update_last_contact + before_update :update_last_contact -store :state -store :params -before_create :update_last_contact -before_update :update_last_contact - -private + private def update_last_contact self.last_contact = Time.now end -end \ No newline at end of file +end