From 5641e0b3096f72d322d244c3f15547046c520d48 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Thu, 7 May 2015 20:27:29 +0900 Subject: [PATCH 01/19] ImapFolderAgent: Handle a mail without a body This addresses #745. --- app/models/agents/imap_folder_agent.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/models/agents/imap_folder_agent.rb b/app/models/agents/imap_folder_agent.rb index c39abbb7e4..c46f6ae374 100644 --- a/app/models/agents/imap_folder_agent.rb +++ b/app/models/agents/imap_folder_agent.rb @@ -525,17 +525,19 @@ def initialize(client, fetch_data, props = {}) def has_attachment? @has_attachment ||= - begin - data = @client.uid_fetch(@uid, 'BODYSTRUCTURE').first + if data = @client.uid_fetch(@uid, 'BODYSTRUCTURE').first struct_has_attachment?(data.attr['BODYSTRUCTURE']) + else + false end end def fetch @parsed ||= - begin - data = @client.uid_fetch(@uid, 'BODY.PEEK[]').first + if data = @client.uid_fetch(@uid, 'BODY.PEEK[]').first Mail.read_from_string(data.attr['BODY[]']) + else + Mail.read_from_string('') end end From 9640c056102aeb97f9f2c6944e3e6cd7d0554759 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Wed, 13 May 2015 16:12:45 +0900 Subject: [PATCH 02/19] Upgrade spring to 1.3.6 --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index f729954631..ed99c89a61 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -413,7 +413,7 @@ GEM slop (3.6.0) spectrum-rails (1.3.4) railties (>= 3.1) - spring (1.3.4) + spring (1.3.6) spring-commands-rspec (1.0.4) spring (>= 0.9.1) sprockets (2.12.3) From 90ff0afd1774b48d70e39fa7b55c0e12ff1dca09 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Wed, 13 May 2015 16:13:07 +0900 Subject: [PATCH 03/19] Upgrade dotenv-rails to 2.0.1 --- Gemfile | 3 +-- Gemfile.lock | 11 ++++------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index de0aab02b1..92d999feee 100644 --- a/Gemfile +++ b/Gemfile @@ -58,6 +58,7 @@ gem 'daemons', '~> 1.1.9' gem 'delayed_job', '~> 4.0.0' gem 'delayed_job_active_record', '~> 4.0.0' gem 'devise', '~> 3.4.0' +gem 'dotenv-rails', '~> 2.0.1' gem 'em-http-request', '~> 1.1.2' gem 'faraday', '~> 0.9.0' gem 'faraday_middleware' @@ -101,7 +102,6 @@ end group :development, :test do gem 'coveralls', require: false gem 'delorean' - gem 'dotenv-rails' gem 'pry' gem 'rr' gem 'rspec', '~> 3.2' @@ -116,7 +116,6 @@ group :development, :test do end group :production do - gem 'dotenv-deployment' gem 'rack' end diff --git a/Gemfile.lock b/Gemfile.lock index ed99c89a61..e4756a3ddd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -124,11 +124,9 @@ GEM docile (1.1.5) domain_name (0.5.24) unf (>= 0.0.5, < 1.0.0) - dotenv (0.11.1) - dotenv-deployment (~> 0.0.2) - dotenv-deployment (0.0.2) - dotenv-rails (0.11.1) - dotenv (= 0.11.1) + dotenv (2.0.1) + dotenv-rails (2.0.1) + dotenv (= 2.0.1) dropbox-api (0.4.2) hashie multi_json @@ -507,8 +505,7 @@ DEPENDENCIES delayed_job_active_record (~> 4.0.0) delorean devise (~> 3.4.0) - dotenv-deployment - dotenv-rails + dotenv-rails (~> 2.0.1) dropbox-api em-http-request (~> 1.1.2) faraday (~> 0.9.0) From 067dde298c8d2dde419efba58ff6c96f612bb4d9 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Wed, 13 May 2015 19:14:36 +0900 Subject: [PATCH 04/19] Improve how to list Heroku specific gems --- Gemfile | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Gemfile b/Gemfile index 92d999feee..3fcfe71fe5 100644 --- a/Gemfile +++ b/Gemfile @@ -125,15 +125,23 @@ gem 'tzinfo', '>= 1.2.0' # required by rails; 1.2.0 has support for *BSD and Sol # Windows does not have zoneinfo files, so bundle the tzinfo-data gem. gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw] -# This hack needs some explanation. When on Heroku, use the pg, unicorn, and rails12factor gems. -# When not on Heroku, we still want our Gemfile.lock to include these gems, so we scope them to -# an unsupported platform. -if ENV['ON_HEROKU'] || ENV['HEROKU_POSTGRESQL_ROSE_URL'] || ENV['HEROKU_POSTGRESQL_GOLD_URL'] || File.read(File.join(File.dirname(__FILE__), 'Procfile')) =~ /intended for Heroku/ +# Introduces a scope for Heroku specific gems. +def on_heroku + if ENV['ON_HEROKU'] || + ENV['HEROKU_POSTGRESQL_ROSE_URL'] || + ENV['HEROKU_POSTGRESQL_GOLD_URL'] || + File.read(File.join(File.dirname(__FILE__), 'Procfile')) =~ /intended for Heroku/ + yield + else + # When not on Heroku, we still want our Gemfile.lock to include + # Heroku specific gems, so we scope them to an unsupported + # platform. + platform :ruby_18, &proc + end +end + +on_heroku do gem 'pg' gem 'unicorn' gem 'rails_12factor', group: :production -else - gem 'pg', platform: :ruby_18 - gem 'unicorn', platform: :ruby_18 - gem 'rails_12factor', platform: :ruby_18 end From db33fc7eed58a00dba3f991e3b5e6ebb000abc8b Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Wed, 13 May 2015 23:58:12 +0900 Subject: [PATCH 05/19] Use nested groups --- Gemfile | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Gemfile b/Gemfile index 3fcfe71fe5..3927c913bf 100644 --- a/Gemfile +++ b/Gemfile @@ -97,22 +97,22 @@ group :development do gem 'guard' gem 'guard-livereload' gem 'guard-rspec' -end -group :development, :test do - gem 'coveralls', require: false - gem 'delorean' - gem 'pry' - gem 'rr' - gem 'rspec', '~> 3.2' - gem 'rspec-collection_matchers', '~> 1.1.0' - gem 'rspec-rails', '~> 3.1' - gem 'rspec-html-matchers', '~> 0.7' - gem 'shoulda-matchers' - gem 'spring', '~> 1.3.0' - gem 'spring-commands-rspec' - gem 'vcr' - gem 'webmock', '~> 1.17.4', require: false + group :test do + gem 'coveralls', require: false + gem 'delorean' + gem 'pry' + gem 'rr' + gem 'rspec', '~> 3.2' + gem 'rspec-collection_matchers', '~> 1.1.0' + gem 'rspec-rails', '~> 3.1' + gem 'rspec-html-matchers', '~> 0.7' + gem 'shoulda-matchers' + gem 'spring', '~> 1.3.0' + gem 'spring-commands-rspec' + gem 'vcr' + gem 'webmock', '~> 1.17.4', require: false + end end group :production do From cf5f96cb592f45c505371345ab8a1cccc7d5eba9 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Thu, 14 May 2015 02:47:33 +0900 Subject: [PATCH 06/19] Call `Dotenv.overload` after `Dotenv::Railtie.load` is called `dotenv-rails` calls `Dotenv::Railtie.load` when `Huginn::Application` is defined, so the `Dotenv.overload` call should be moved here. --- config/application.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/application.rb b/config/application.rb index f4156e403a..91e82fe8da 100644 --- a/config/application.rb +++ b/config/application.rb @@ -4,10 +4,10 @@ Bundler.require(:default, Rails.env) -Dotenv.overload File.expand_path('../../spec/env.test', __FILE__) if Rails.env.test? - module Huginn class Application < Rails::Application + Dotenv.overload File.expand_path('../../spec/env.test', __FILE__) if Rails.env.test? + # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. From 3e085512ff086afbced43f76540bc53fe0e73a56 Mon Sep 17 00:00:00 2001 From: Dominik Sander Date: Mon, 11 May 2015 21:41:03 +0200 Subject: [PATCH 07/19] Make delayed_job sleep_delay and max_run_time .env configurable --- .env.example | 8 +++++++- config/initializers/delayed_job.rb | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 3a487249be..28f6df2fb2 100644 --- a/.env.example +++ b/.env.example @@ -147,7 +147,7 @@ ENABLE_SECOND_PRECISION_SCHEDULE=false # Specify the scheduler frequency in seconds (default: 0.3). # Increasing this value will help reduce the use of system resources # at the expense of time accuracy. -#SCHEDULER_FREQUENCY=0.3 +SCHEDULER_FREQUENCY=0.3 # Use Graphviz for generating diagrams instead of using Google Chart # Tools. Specify a dot(1) command path built with SVG support @@ -159,3 +159,9 @@ TIMEZONE="Pacific Time (US & Canada)" # Number of failed jobs to keep in the database FAILED_JOBS_TO_KEEP=100 + +# Maximum runtime of background jobs in minutes +DELAYED_JOB_MAX_RUNTIME=20 + +# Amount of seconds for delayed_job to sleep before checking for new jobs +DELAYED_JOB_SLEEP_DELAY=10 \ No newline at end of file diff --git a/config/initializers/delayed_job.rb b/config/initializers/delayed_job.rb index cf2d29c1f3..5a55bdc2a8 100644 --- a/config/initializers/delayed_job.rb +++ b/config/initializers/delayed_job.rb @@ -1,9 +1,10 @@ Delayed::Worker.destroy_failed_jobs = false Delayed::Worker.max_attempts = 5 -Delayed::Worker.max_run_time = 20.minutes +Delayed::Worker.max_run_time = (ENV['DELAYED_JOB_MAX_RUNTIME'].presence || 20).to_i.minutes Delayed::Worker.read_ahead = 5 Delayed::Worker.default_priority = 10 Delayed::Worker.delay_jobs = !Rails.env.test? +Delayed::Worker.sleep_delay = (ENV['DELAYED_JOB_SLEEP_DELAY'].presence || 10).to_f # Delayed::Worker.logger = Logger.new(Rails.root.join('log', 'delayed_job.log')) # Delayed::Worker.logger.level = Logger::DEBUG From 864152b8716fa72e65ad0271862de700a99fd98c Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Thu, 14 May 2015 20:44:22 +0900 Subject: [PATCH 08/19] Fix typos in the description --- app/models/agents/imap_folder_agent.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/agents/imap_folder_agent.rb b/app/models/agents/imap_folder_agent.rb index c46f6ae374..39efa2c29d 100644 --- a/app/models/agents/imap_folder_agent.rb +++ b/app/models/agents/imap_folder_agent.rb @@ -12,7 +12,7 @@ class ImapFolderAgent < Agent The ImapFolderAgent checks an IMAP server in specified folders and creates Events based on new mails found since the last run. - In the first visit to a foler, this agent only checks for the + In the first visit to a folder, this agent only checks for the initial status and does not create events. Specify an IMAP server to connect with `host`, and set `ssl` to @@ -45,8 +45,8 @@ class ImapFolderAgent < Agent specified, will be chosen as the "body" value in a created event. - Named captues will appear in the "matches" hash in a created - event. + Named captures will appear in the "matches" hash in a + created event. - "from", "to", "cc" From 40d6192070caabb60874223150d57661747c01be Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Thu, 14 May 2015 20:46:25 +0900 Subject: [PATCH 09/19] Define DryRunnable#dry_run? A dry-runnable Agent can use this method to decide if it should avoid affecting unsandboxed resources, like calling an external API that might change any state. --- app/concerns/dry_runnable.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/concerns/dry_runnable.rb b/app/concerns/dry_runnable.rb index bbca6ef408..40fc2a5392 100644 --- a/app/concerns/dry_runnable.rb +++ b/app/concerns/dry_runnable.rb @@ -25,6 +25,10 @@ class << self ) end + def dry_run? + is_a? Sandbox + end + module Sandbox attr_accessor :results From 3ce41669b465ea1bb8c3a24570c35af51ee0c3a0 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Thu, 14 May 2015 20:47:03 +0900 Subject: [PATCH 10/19] Use keyword arguments for Net::IMAP.new --- app/models/agents/imap_folder_agent.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/agents/imap_folder_agent.rb b/app/models/agents/imap_folder_agent.rb index 39efa2c29d..ca0b2e2a7c 100644 --- a/app/models/agents/imap_folder_agent.rb +++ b/app/models/agents/imap_folder_agent.rb @@ -322,7 +322,7 @@ def each_unread_mail port = (Integer(port) if port.present?) log "Connecting to #{host}#{':%d' % port if port}#{' via SSL' if ssl}" - Client.open(host, port, ssl) { |imap| + Client.open(host, port: port, ssl: ssl) { |imap| log "Logging in as #{username}" imap.login(username, interpolated[:password]) @@ -437,8 +437,8 @@ def pluralize(count, noun) class Client < ::Net::IMAP class << self - def open(host, port, ssl) - imap = new(host, port, ssl) + def open(host, *args) + imap = new(host, *args) yield imap ensure imap.disconnect unless imap.nil? From 106058ab96a8514424b1b2c8ce655e7827adb4a6 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Thu, 14 May 2015 20:47:47 +0900 Subject: [PATCH 11/19] ImapFolderAgent: Enable dry-run --- app/models/agents/imap_folder_agent.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/agents/imap_folder_agent.rb b/app/models/agents/imap_folder_agent.rb index ca0b2e2a7c..87959634b5 100644 --- a/app/models/agents/imap_folder_agent.rb +++ b/app/models/agents/imap_folder_agent.rb @@ -6,6 +6,8 @@ module Agents class ImapFolderAgent < Agent cannot_receive_events! + can_dry_run! + default_schedule "every_30m" description <<-MD @@ -311,7 +313,7 @@ def check if boolify(interpolated['mark_as_read']) log 'Marking as read' - mail.mark_as_read + mail.mark_as_read unless dry_run? end } end From 316f0bfec6fccb986e0a20cadef8e67856eab9b3 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Thu, 14 May 2015 22:16:21 +0900 Subject: [PATCH 12/19] Make sure a dry-run does not save Agent's memory --- spec/concerns/dry_runnable_spec.rb | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/spec/concerns/dry_runnable_spec.rb b/spec/concerns/dry_runnable_spec.rb index bfba97fe61..7e38958033 100644 --- a/spec/concerns/dry_runnable_spec.rb +++ b/spec/concerns/dry_runnable_spec.rb @@ -8,10 +8,10 @@ class Agents::SandboxedAgent < Agent def check log "Logging" - create_event payload: { test: "foo" } + create_event payload: { 'test' => 'foo' } error "Recording error" - create_event payload: { test: "bar" } - self.memory = { last_status: "ok" } + create_event payload: { 'test' => 'bar' } + self.memory = { 'last_status' => 'ok' } save! end end @@ -24,18 +24,23 @@ def check } end + def counts + [users(:bob).agents.count, users(:bob).events.count, users(:bob).logs.count] + end + it "traps logging, event emission and memory updating" do results = nil expect { results = @agent.dry_run! + @agent.reload }.not_to change { - [users(:bob).agents.count, users(:bob).events.count, users(:bob).logs.count] + [@agent.memory, counts] } expect(results[:log]).to match(/\AI, .+ INFO -- : Logging\nE, .+ ERROR -- : Recording error\n/) - expect(results[:events]).to eq([{ test: 'foo' }, { test: 'bar' }]) - expect(results[:memory]).to eq({ "last_status" => "ok" }) + expect(results[:events]).to eq([{ 'test' => 'foo' }, { 'test' => 'bar' }]) + expect(results[:memory]).to eq({ 'last_status' => 'ok' }) end it "does not perform dry-run if Agent does not support dry-run" do @@ -45,8 +50,9 @@ def check expect { results = @agent.dry_run! + @agent.reload }.not_to change { - [users(:bob).agents.count, users(:bob).events.count, users(:bob).logs.count] + [@agent.memory, counts] } expect(results[:log]).to match(/\AE, .+ ERROR -- : Exception during dry-run. SandboxedAgent does not support dry-run: /) From cc4966daf4eeb05effc0c67c9d9525de0266b58b Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Thu, 14 May 2015 22:20:21 +0900 Subject: [PATCH 13/19] Make sure DryRunnable does not affect normal run, and test #dry_run? also --- spec/concerns/dry_runnable_spec.rb | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/spec/concerns/dry_runnable_spec.rb b/spec/concerns/dry_runnable_spec.rb index 7e38958033..4eaf3f89a0 100644 --- a/spec/concerns/dry_runnable_spec.rb +++ b/spec/concerns/dry_runnable_spec.rb @@ -11,7 +11,7 @@ def check create_event payload: { 'test' => 'foo' } error "Recording error" create_event payload: { 'test' => 'bar' } - self.memory = { 'last_status' => 'ok' } + self.memory = { 'last_status' => 'ok', 'dry_run' => dry_run? } save! end end @@ -28,7 +28,25 @@ def counts [users(:bob).agents.count, users(:bob).events.count, users(:bob).logs.count] end - it "traps logging, event emission and memory updating" do + it "does not affect normal run, with dry_run? returning false" do + before = counts + after = before.zip([0, 2, 2]).map { |x, d| x + d } + + expect { + @agent.check + @agent.reload + }.to change { counts }.from(before).to(after) + + expect(@agent.memory).to eq({ 'last_status' => 'ok', 'dry_run' => false }) + + payloads = @agent.events.reorder(:id).last(2).map(&:payload) + expect(payloads).to eq([{ 'test' => 'foo' }, { 'test' => 'bar' }]) + + messages = @agent.logs.reorder(:id).last(2).map(&:message) + expect(messages).to eq(['Logging', 'Recording error']) + end + + it "traps logging, event emission and memory updating, with dry_run? returning true" do results = nil expect { @@ -40,7 +58,7 @@ def counts expect(results[:log]).to match(/\AI, .+ INFO -- : Logging\nE, .+ ERROR -- : Recording error\n/) expect(results[:events]).to eq([{ 'test' => 'foo' }, { 'test' => 'bar' }]) - expect(results[:memory]).to eq({ 'last_status' => 'ok' }) + expect(results[:memory]).to eq({ 'last_status' => 'ok', 'dry_run' => true }) end it "does not perform dry-run if Agent does not support dry-run" do From 15378aa006a7c5161b39b0a3e23ce68f70e5c76f Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Tue, 19 May 2015 22:14:52 +0900 Subject: [PATCH 14/19] Add "Dry Run" to the action menu --- .../javascripts/components/utils.js.coffee | 26 +++++++++++++++++++ .../pages/agent-edit-page.js.coffee | 26 +------------------ app/controllers/agents_controller.rb | 9 ++++--- app/views/agents/_action_menu.html.erb | 6 +++++ 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/app/assets/javascripts/components/utils.js.coffee b/app/assets/javascripts/components/utils.js.coffee index cf29e5c46f..7fb2b3c258 100644 --- a/app/assets/javascripts/components/utils.js.coffee +++ b/app/assets/javascripts/components/utils.js.coffee @@ -33,3 +33,29 @@ class @Utils onHide?() body?(modal.querySelector('.modal-body')) $(modal).modal('show') + + @handleDryRunButton: (button, data = $(button.form).serialize()) -> + $(button).prop('disabled', true) + $('body').css(cursor: 'progress') + $.ajax type: 'POST', url: $(button).data('action-url'), dataType: 'json', data: data + .always => + $('body').css(cursor: 'auto') + .done (json) => + Utils.showDynamicModal """ +
Log
+

+          
Events
+

+          
Memory
+

+          """,
+          body: (body) ->
+            $(body).
+              find('.agent-dry-run-log').text(json.log).end().
+              find('.agent-dry-run-events').text(json.events).end().
+              find('.agent-dry-run-memory').text(json.memory)
+          title: 'Dry Run Results',
+          onHide: -> $(button).prop('disabled', false)
+      .fail (xhr, status, error) ->
+        alert('Error: ' + error)
+        $(button).prop('disabled', false)
diff --git a/app/assets/javascripts/pages/agent-edit-page.js.coffee b/app/assets/javascripts/pages/agent-edit-page.js.coffee
index 59f62e93ee..c9a0ef8120 100644
--- a/app/assets/javascripts/pages/agent-edit-page.js.coffee
+++ b/app/assets/javascripts/pages/agent-edit-page.js.coffee
@@ -142,31 +142,7 @@ class @AgentEditPage
 
   invokeDryRun: (e) ->
     e.preventDefault()
-    button = this
-    $(button).prop('disabled', true)
-    $('body').css(cursor: 'progress')
-    $.ajax type: 'POST', url: $(button).data('action-url'), dataType: 'json', data: $(button.form).serialize()
-      .always =>
-        $("body").css(cursor: 'auto')
-      .done (json) =>
-        Utils.showDynamicModal """
-          
Log
-

-          
Events
-

-          
Memory
-

-          """,
-          body: (body) ->
-            $(body).
-              find('.agent-dry-run-log').text(json.log).end().
-              find('.agent-dry-run-events').text(json.events).end().
-              find('.agent-dry-run-memory').text(json.memory)
-          title: 'Dry Run Results',
-          onHide: -> $(button).prop('disabled', false)
-      .fail (xhr, status, error) ->
-        alert('Error: ' + error)
-        $(button).prop('disabled', false)
+    Utils.handleDryRunButton(this)
 
 $ ->
   Utils.registerPage(AgentEditPage, forPathsMatching: /^agents/)
diff --git a/app/controllers/agents_controller.rb b/app/controllers/agents_controller.rb
index d656b371bc..d19f7cd25c 100644
--- a/app/controllers/agents_controller.rb
+++ b/app/controllers/agents_controller.rb
@@ -35,15 +35,18 @@ def run
   end
 
   def dry_run
-    attrs = params[:agent]
+    attrs = params[:agent] || {}
     if agent = current_user.agents.find_by(id: params[:id])
       # PUT /agents/:id/dry_run
-      type = agent.type
+      if attrs.present?
+        type = agent.type
+        agent = Agent.build_for_type(type, current_user, attrs)
+      end
     else
       # POST /agents/dry_run
       type = attrs.delete(:type)
+      agent = Agent.build_for_type(type, current_user, attrs)
     end
-    agent = Agent.build_for_type(type, current_user, attrs)
     agent.name ||= '(Untitled)'
 
     if agent.valid?
diff --git a/app/views/agents/_action_menu.html.erb b/app/views/agents/_action_menu.html.erb
index d251acde2e..5a8a59e8da 100644
--- a/app/views/agents/_action_menu.html.erb
+++ b/app/views/agents/_action_menu.html.erb
@@ -5,6 +5,12 @@
     
   <% end %>
 
+  <% if agent.can_dry_run? %>
+    
  • + <%= link_to icon_tag('glyphicon-refresh') + ' Dry Run', '#', 'data-action-url' => dry_run_agent_path(agent), tabindex: "-1", onclick: "Utils.handleDryRunButton(this, '_method=PUT')" %> +
  • + <% end %> +
  • <%= link_to icon_tag('glyphicon-eye-open') + ' Show'.html_safe, agent_path(agent) %>
  • From 42e53c4b1cd86065e4347c3285b3c2de309a65e1 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Wed, 20 May 2015 23:27:31 +0900 Subject: [PATCH 15/19] Remove superfluous CSS position specifiers --- app/assets/stylesheets/diagram.css.scss | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/assets/stylesheets/diagram.css.scss b/app/assets/stylesheets/diagram.css.scss index c068ca62c2..ba5acb4dfd 100644 --- a/app/assets/stylesheets/diagram.css.scss +++ b/app/assets/stylesheets/diagram.css.scss @@ -8,13 +8,9 @@ } .overlay-container { - position: absolute; - top: 0; - left: 0; z-index: auto; .overlay { - position: relative; z-index: auto; width: 100%; height: 100%; From b779471e1389203b8f0154013dd0f70799c92356 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Wed, 20 May 2015 23:57:58 +0900 Subject: [PATCH 16/19] Exclude disabled agents from Agent Diagram and add a toggle button --- app/controllers/diagrams_controller.rb | 13 ++++++++----- app/views/diagrams/show.html.erb | 7 ++++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/controllers/diagrams_controller.rb b/app/controllers/diagrams_controller.rb index 6772ea4101..b69ad775fa 100644 --- a/app/controllers/diagrams_controller.rb +++ b/app/controllers/diagrams_controller.rb @@ -1,9 +1,12 @@ class DiagramsController < ApplicationController def show - @agents = if params[:scenario_id].present? - current_user.scenarios.find(params[:scenario_id]).agents.includes(:receivers) - else - current_user.agents.includes(:receivers) - end + if params[:scenario_id].present? + @scenario = current_user.scenarios.find(params[:scenario_id]) + agents = @scenario.agents + else + agents = current_user.agents + end + agents = agents.active unless params[:include_disabled].present? + @agents = agents.includes(:receivers) end end diff --git a/app/views/diagrams/show.html.erb b/app/views/diagrams/show.html.erb index f09b0d0c1e..04c4b1aba1 100644 --- a/app/views/diagrams/show.html.erb +++ b/app/views/diagrams/show.html.erb @@ -9,7 +9,12 @@

    Agent Event Flow

    - <%= link_to icon_tag('glyphicon-chevron-left') + ' Back'.html_safe, (params[:scenario_id] ? scenario_path(params[:scenario_id]) : agents_path), class: "btn btn-default" %> + <%= link_to icon_tag('glyphicon-chevron-left') + ' Back'.html_safe, (@scenario ? scenario_path(@scenario) : agents_path), class: "btn btn-default" %> + <% if params[:include_disabled] %> + <%= link_to @scenario ? scenario_diagram_path(@scenario) : diagram_path, class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-close') %> Hide disabled Agents<% end %> + <% else %> + <%= link_to @scenario ? scenario_diagram_path(@scenario, include_disabled: true) : diagram_path(include_disabled: true), class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-open') %> Show disabled Agents<% end %> + <% end %>
    From 22eb2fa9ef8ea39ec647175b3d921a243dc61fd2 Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Thu, 21 May 2015 13:47:59 +0900 Subject: [PATCH 17/19] Show the number of disabled Agents in the toggle button --- app/controllers/diagrams_controller.rb | 1 + app/models/agent.rb | 3 ++- app/views/diagrams/show.html.erb | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/controllers/diagrams_controller.rb b/app/controllers/diagrams_controller.rb index b69ad775fa..e4400b0b77 100644 --- a/app/controllers/diagrams_controller.rb +++ b/app/controllers/diagrams_controller.rb @@ -6,6 +6,7 @@ def show else agents = current_user.agents end + @disabled_agents = agents.inactive agents = agents.active unless params[:include_disabled].present? @agents = agents.includes(:receivers) end diff --git a/app/models/agent.rb b/app/models/agent.rb index c0aa3d8ab9..2d893d2573 100644 --- a/app/models/agent.rb +++ b/app/models/agent.rb @@ -60,7 +60,8 @@ class Agent < ActiveRecord::Base has_many :scenario_memberships, :dependent => :destroy, :inverse_of => :agent has_many :scenarios, :through => :scenario_memberships, :inverse_of => :agents - scope :active, -> { where(disabled: false) } + scope :active, -> { where(disabled: false) } + scope :inactive, -> { where(disabled: true) } scope :of_type, lambda { |type| type = case type diff --git a/app/views/diagrams/show.html.erb b/app/views/diagrams/show.html.erb index 04c4b1aba1..a9ea7ae3e1 100644 --- a/app/views/diagrams/show.html.erb +++ b/app/views/diagrams/show.html.erb @@ -11,9 +11,9 @@
    <%= link_to icon_tag('glyphicon-chevron-left') + ' Back'.html_safe, (@scenario ? scenario_path(@scenario) : agents_path), class: "btn btn-default" %> <% if params[:include_disabled] %> - <%= link_to @scenario ? scenario_diagram_path(@scenario) : diagram_path, class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-close') %> Hide disabled Agents<% end %> + <%= link_to @scenario ? scenario_diagram_path(@scenario) : diagram_path, class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-close') %> Hide <%= pluralize(@disabled_agents.count, 'disabled Agent') %><% end %> <% else %> - <%= link_to @scenario ? scenario_diagram_path(@scenario, include_disabled: true) : diagram_path(include_disabled: true), class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-open') %> Show disabled Agents<% end %> + <%= link_to @scenario ? scenario_diagram_path(@scenario, include_disabled: true) : diagram_path(include_disabled: true), class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-open') %> Show <%= pluralize(@disabled_agents.count, 'disabled Agent') %><% end %> <% end %>
    From b8896f611c6f0e945af394d2c3a30dfdd1d247bf Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Thu, 21 May 2015 13:53:05 +0900 Subject: [PATCH 18/19] Omit the toggle button if there are no disabled agents --- app/views/diagrams/show.html.erb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/views/diagrams/show.html.erb b/app/views/diagrams/show.html.erb index a9ea7ae3e1..5d8fdcea33 100644 --- a/app/views/diagrams/show.html.erb +++ b/app/views/diagrams/show.html.erb @@ -10,10 +10,12 @@
    <%= link_to icon_tag('glyphicon-chevron-left') + ' Back'.html_safe, (@scenario ? scenario_path(@scenario) : agents_path), class: "btn btn-default" %> - <% if params[:include_disabled] %> - <%= link_to @scenario ? scenario_diagram_path(@scenario) : diagram_path, class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-close') %> Hide <%= pluralize(@disabled_agents.count, 'disabled Agent') %><% end %> - <% else %> - <%= link_to @scenario ? scenario_diagram_path(@scenario, include_disabled: true) : diagram_path(include_disabled: true), class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-open') %> Show <%= pluralize(@disabled_agents.count, 'disabled Agent') %><% end %> + <% if (num_disabled = @disabled_agents.count).nonzero? -%> + <% if params[:include_disabled] %> + <%= link_to @scenario ? scenario_diagram_path(@scenario) : diagram_path, class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-close') %> Hide <%= pluralize(num_disabled, 'disabled Agent') %><% end %> + <% else %> + <%= link_to @scenario ? scenario_diagram_path(@scenario, include_disabled: true) : diagram_path(include_disabled: true), class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-open') %> Show <%= pluralize(num_disabled, 'disabled Agent') %><% end %> + <% end %> <% end %>
    From b4a7dce81d38a5395f74a0fdb9bedbf83eef427f Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Thu, 21 May 2015 15:38:21 +0900 Subject: [PATCH 19/19] Show disabled agents by default --- app/controllers/diagrams_controller.rb | 2 +- app/views/diagrams/show.html.erb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/diagrams_controller.rb b/app/controllers/diagrams_controller.rb index e4400b0b77..9092e0b204 100644 --- a/app/controllers/diagrams_controller.rb +++ b/app/controllers/diagrams_controller.rb @@ -7,7 +7,7 @@ def show agents = current_user.agents end @disabled_agents = agents.inactive - agents = agents.active unless params[:include_disabled].present? + agents = agents.active if params[:exclude_disabled].present? @agents = agents.includes(:receivers) end end diff --git a/app/views/diagrams/show.html.erb b/app/views/diagrams/show.html.erb index 5d8fdcea33..f106fb7367 100644 --- a/app/views/diagrams/show.html.erb +++ b/app/views/diagrams/show.html.erb @@ -11,10 +11,10 @@
    <%= link_to icon_tag('glyphicon-chevron-left') + ' Back'.html_safe, (@scenario ? scenario_path(@scenario) : agents_path), class: "btn btn-default" %> <% if (num_disabled = @disabled_agents.count).nonzero? -%> - <% if params[:include_disabled] %> - <%= link_to @scenario ? scenario_diagram_path(@scenario) : diagram_path, class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-close') %> Hide <%= pluralize(num_disabled, 'disabled Agent') %><% end %> + <% if params[:exclude_disabled] %> + <%= link_to @scenario ? scenario_diagram_path(@scenario) : diagram_path, class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-open') %> Show <%= pluralize(num_disabled, 'disabled Agent') %><% end %> <% else %> - <%= link_to @scenario ? scenario_diagram_path(@scenario, include_disabled: true) : diagram_path(include_disabled: true), class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-open') %> Show <%= pluralize(num_disabled, 'disabled Agent') %><% end %> + <%= link_to @scenario ? scenario_diagram_path(@scenario, exclude_disabled: true) : diagram_path(exclude_disabled: true), class: 'btn btn-default' do %><%= icon_tag('glyphicon-eye-close') %> Hide <%= pluralize(num_disabled, 'disabled Agent') %><% end %> <% end %> <% end %>