mirror of
https://github.com/Fishwaldo/huginn.git
synced 2025-03-15 19:31:26 +00:00
Show recently received events in dry run modal
This commit is contained in:
parent
9202c84406
commit
d573b98a68
10 changed files with 255 additions and 169 deletions
|
@ -43,90 +43,65 @@ class @Utils
|
|||
|
||||
if with_event_mode is 'no'
|
||||
return @invokeDryRun(url, data, cleanup)
|
||||
$.ajax url,
|
||||
method: 'GET',
|
||||
data:
|
||||
with_event_mode: with_event_mode
|
||||
source_ids: $.map($(".link-region select option:selected"), (el) -> $(el).val() )
|
||||
success: (modal_data) =>
|
||||
Utils.showDynamicModal modal_data,
|
||||
body: (body) =>
|
||||
form = $(body).find('.dry-run-form')
|
||||
payload_editor = form.find('.payload-editor')
|
||||
|
||||
Utils.showDynamicModal """
|
||||
<h5>Event to send#{if with_event_mode is 'maybe' then ' (Optional)' else ''}</h5>
|
||||
<form class="dry-run-form" method="post">
|
||||
<div class="form-group">
|
||||
<textarea rows="10" name="event" class="payload-editor" data-height="200">
|
||||
{}
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input value="Dry Run" class="btn btn-primary" type="submit" />
|
||||
</div>
|
||||
</form>
|
||||
""",
|
||||
body: (body) =>
|
||||
form = $(body).find('.dry-run-form')
|
||||
payload_editor = form.find('.payload-editor')
|
||||
if previous = $(button).data('payload')
|
||||
payload_editor.text(previous)
|
||||
window.setupJsonEditor(payload_editor)
|
||||
form.submit (e) =>
|
||||
e.preventDefault()
|
||||
json = $(e.target).find('.payload-editor').val()
|
||||
json = '{}' if json == ''
|
||||
try
|
||||
payload = JSON.parse(json)
|
||||
throw true unless payload.constructor is Object
|
||||
if Object.keys(payload).length == 0
|
||||
json = ''
|
||||
else
|
||||
json = JSON.stringify(payload)
|
||||
catch
|
||||
alert 'Invalid JSON object.'
|
||||
return
|
||||
if json == ''
|
||||
if with_event_mode is 'yes'
|
||||
alert 'Event is required for this agent to run.'
|
||||
return
|
||||
dry_run_data = data
|
||||
$(button).data('payload', null)
|
||||
else
|
||||
dry_run_data = "event=#{encodeURIComponent(json)}&#{data}"
|
||||
$(button).data('payload', json)
|
||||
$(body).closest('[role=dialog]').on 'hidden.bs.modal', =>
|
||||
@invokeDryRun(url, dry_run_data, cleanup)
|
||||
.modal('hide')
|
||||
$(body).closest('[role=dialog]').on 'shown.bs.modal', ->
|
||||
$(this).find('.btn-primary').focus()
|
||||
title: 'Dry Run'
|
||||
onHide: cleanup
|
||||
if previous = $(button).data('payload')
|
||||
payload_editor.text(previous)
|
||||
|
||||
editor = window.setupJsonEditor(payload_editor)[0]
|
||||
|
||||
$(body).find('.dry-run-event-sample').click (e) =>
|
||||
e.preventDefault()
|
||||
editor.json = $(e.currentTarget).data('payload')
|
||||
editor.rebuild()
|
||||
|
||||
form.submit (e) =>
|
||||
e.preventDefault()
|
||||
json = $(e.target).find('.payload-editor').val()
|
||||
json = '{}' if json == ''
|
||||
try
|
||||
payload = JSON.parse(json)
|
||||
throw true unless payload.constructor is Object
|
||||
if Object.keys(payload).length == 0
|
||||
json = ''
|
||||
else
|
||||
json = JSON.stringify(payload)
|
||||
catch
|
||||
alert 'Invalid JSON object.'
|
||||
return
|
||||
if json == ''
|
||||
if with_event_mode is 'yes'
|
||||
alert 'Event is required for this agent to run.'
|
||||
return
|
||||
dry_run_data = data
|
||||
$(button).data('payload', null)
|
||||
else
|
||||
dry_run_data = "event=#{encodeURIComponent(json)}&#{data}"
|
||||
$(button).data('payload', json)
|
||||
$(body).closest('[role=dialog]').on 'hidden.bs.modal', =>
|
||||
@invokeDryRun(url, dry_run_data, cleanup)
|
||||
.modal('hide')
|
||||
$(body).closest('[role=dialog]').on 'shown.bs.modal', ->
|
||||
$(this).find('.btn-primary').focus()
|
||||
title: 'Dry Run'
|
||||
onHide: cleanup
|
||||
|
||||
@invokeDryRun: (url, data, callback) ->
|
||||
$('body').css(cursor: 'progress')
|
||||
$.ajax type: 'POST', url: url, dataType: 'json', data: data
|
||||
$.ajax type: 'POST', url: url, dataType: 'html', data: data
|
||||
.always =>
|
||||
$('body').css(cursor: 'auto')
|
||||
.done (json) =>
|
||||
Utils.showDynamicModal """
|
||||
<!-- Nav tabs -->
|
||||
<ul id="resultTabs" class="nav nav-tabs agent-dry-run-tabs" role="tablist">
|
||||
<li role="presentation"><a href="#tabEvents" aria-controls="tabEvents" role="tab" data-toggle="tab">Events</a></li>
|
||||
<li role="presentation"><a href="#tabLog" aria-controls="tabLog" role="tab" data-toggle="tab">Log</a></li>
|
||||
<li role="presentation"><a href="#tabMemory" aria-controls="tabMemory" role="tab" data-toggle="tab">Memory</a></li>
|
||||
</ul>
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane" id="tabEvents">
|
||||
<pre class="agent-dry-run-events"></pre>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="tabLog">
|
||||
<pre><small class="agent-dry-run-log"></small></pre>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="tabMemory">
|
||||
<pre class="agent-dry-run-memory"></pre>
|
||||
</div>
|
||||
</div>
|
||||
""",
|
||||
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)
|
||||
active = if json.events.match(/^\[?\s*\]?$/) then 'tabLog' else 'tabEvents'
|
||||
$('#resultTabs a[href="#' + active + '"]').tab('show')
|
||||
.done (modal_data) =>
|
||||
Utils.showDynamicModal modal_data,
|
||||
title: 'Dry Run Results',
|
||||
onHide: callback
|
||||
.fail (xhr, status, error) ->
|
||||
|
|
50
app/controllers/agents/dry_runs_controller.rb
Normal file
50
app/controllers/agents/dry_runs_controller.rb
Normal file
|
@ -0,0 +1,50 @@
|
|||
module Agents
|
||||
class DryRunsController < ApplicationController
|
||||
include ActionView::Helpers::TextHelper
|
||||
|
||||
def index
|
||||
@events = if params[:agent_id]
|
||||
current_user.agents.find_by(id: params[:agent_id]).received_events.limit(5)
|
||||
elsif params[:source_ids]
|
||||
Event.where(agent_id: current_user.agents.where(id: params[:source_ids]).pluck(:id))
|
||||
.order("id DESC").limit(5)
|
||||
end
|
||||
|
||||
render layout: false
|
||||
end
|
||||
|
||||
def create
|
||||
attrs = params[:agent] || {}
|
||||
if agent = current_user.agents.find_by(id: params[:agent_id])
|
||||
# POST /agents/:id/dry_run
|
||||
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.name ||= '(Untitled)'
|
||||
|
||||
if agent.valid?
|
||||
if event_payload = params[:event]
|
||||
dummy_agent = Agent.build_for_type('ManualEventAgent', current_user, name: 'Dry-Runner')
|
||||
dummy_agent.readonly!
|
||||
event = dummy_agent.events.build(user: current_user, payload: event_payload)
|
||||
end
|
||||
|
||||
@results = agent.dry_run!(event)
|
||||
else
|
||||
@results = { events: [], memory: [],
|
||||
log: [
|
||||
"#{pluralize(agent.errors.count, "error")} prohibited this Agent from being saved:",
|
||||
*agent.errors.full_messages
|
||||
].join("\n- ") }
|
||||
end
|
||||
|
||||
render layout: false
|
||||
end
|
||||
end
|
||||
end
|
|
@ -48,47 +48,6 @@ class AgentsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def dry_run
|
||||
attrs = params[:agent] || {}
|
||||
if agent = current_user.agents.find_by(id: params[:id])
|
||||
# POST /agents/:id/dry_run
|
||||
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.name ||= '(Untitled)'
|
||||
|
||||
if agent.valid?
|
||||
if event_payload = params[:event]
|
||||
dummy_agent = Agent.build_for_type('ManualEventAgent', current_user, name: 'Dry-Runner')
|
||||
dummy_agent.readonly!
|
||||
event = dummy_agent.events.build(user: current_user, payload: event_payload)
|
||||
end
|
||||
|
||||
results = agent.dry_run!(event)
|
||||
|
||||
render json: {
|
||||
log: results[:log],
|
||||
events: Utils.pretty_print(results[:events], false),
|
||||
memory: Utils.pretty_print(results[:memory] || {}, false),
|
||||
}
|
||||
else
|
||||
render json: {
|
||||
log: [
|
||||
"#{pluralize(agent.errors.count, "error")} prohibited this Agent from being saved:",
|
||||
*agent.errors.full_messages
|
||||
].join("\n- "),
|
||||
events: '',
|
||||
memory: '',
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def type_details
|
||||
@agent = Agent.build_for_type(params[:type], current_user, {})
|
||||
initialize_presenter
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<% if agent.can_dry_run? %>
|
||||
<li>
|
||||
<%= link_to icon_tag('glyphicon-refresh') + ' Dry Run', '#', 'data-action-url' => dry_run_agent_path(agent), 'data-with-event-mode' => agent_dry_run_with_event_mode(agent), tabindex: "-1", onclick: "Utils.handleDryRunButton(this)" %>
|
||||
<%= link_to icon_tag('glyphicon-refresh') + ' Dry Run', '#', 'data-action-url' => agent_dry_runs_path(agent), 'data-with-event-mode' => agent_dry_run_with_event_mode(agent), tabindex: "-1", onclick: "Utils.handleDryRunButton(this)" %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
|
|
|
@ -25,6 +25,6 @@
|
|||
<div class="form-group">
|
||||
<%= submit_tag "Save", :class => "btn btn-primary" %>
|
||||
<% if agent.can_dry_run? %>
|
||||
<%= button_tag class: 'btn btn-default agent-dry-run-button', type: 'button', 'data-action-url' => agent.persisted? ? dry_run_agent_path(agent) : dry_run_agents_path, 'data-with-event-mode' => agent_dry_run_with_event_mode(agent) do %><%= icon_tag('glyphicon-refresh') %> Dry Run<% end %>
|
||||
<%= button_tag class: 'btn btn-default agent-dry-run-button', type: 'button', 'data-action-url' => agent.persisted? ? agent_dry_runs_path(agent) : dry_runs_path(type: agent.type), 'data-with-event-mode' => agent_dry_run_with_event_mode(agent) do %><%= icon_tag('glyphicon-refresh') %> Dry Run<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
18
app/views/agents/dry_runs/create.html.erb
Normal file
18
app/views/agents/dry_runs/create.html.erb
Normal file
|
@ -0,0 +1,18 @@
|
|||
<!-- Nav tabs -->
|
||||
<ul id="resultTabs" class="nav nav-tabs agent-dry-run-tabs" role="tablist">
|
||||
<li role="presentation" class="<%= @results[:events].empty? ? '' : 'active' %>"><a href="#tabEvents" aria-controls="tabEvents" role="tab" data-toggle="tab">Events</a></li>
|
||||
<li role="presentation" class="<%= @results[:events].empty? ? 'active' : '' %>"><a href="#tabLog" aria-controls="tabLog" role="tab" data-toggle="tab">Log</a></li>
|
||||
<li role="presentation"><a href="#tabMemory" aria-controls="tabMemory" role="tab" data-toggle="tab">Memory</a></li>
|
||||
</ul>
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane <%= @results[:events].empty? ? '' : 'active' %>" id="tabEvents">
|
||||
<pre class="agent-dry-run-events"><%= Utils.pretty_print(@results[:events], false) %></pre>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane <%= @results[:events].empty? ? 'active' : ''%>" id="tabLog">
|
||||
<pre><small class="agent-dry-run-log"><%= @results[:log] %></small></pre>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="tabMemory">
|
||||
<pre class="agent-dry-run-memory"><%= Utils.pretty_print(@results[:memory], false) %></pre>
|
||||
</div>
|
||||
</div>
|
20
app/views/agents/dry_runs/index.html.erb
Normal file
20
app/views/agents/dry_runs/index.html.erb
Normal file
|
@ -0,0 +1,20 @@
|
|||
<% if @events && @events.length > 0 %>
|
||||
<h5>Recently received events: </h5>
|
||||
<% @events.each do |event| %>
|
||||
<%= link_to '#', class: 'dry-run-event-sample', 'data-payload' => event.payload.to_json do %>
|
||||
<pre><%= truncate event.payload.to_json, :length => 90, :omission => "" %></pre>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<h5>Event to send<%= params[:with_event_mode] == 'maybe' ? ' (Optional)' : '' %></h5>
|
||||
<form class="dry-run-form" method="post">
|
||||
<div class="form-group">
|
||||
<textarea rows="10" name="event" class="payload-editor" data-height="200">
|
||||
{}
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input value="Dry Run" class="btn btn-primary" type="submit" />
|
||||
</div>
|
||||
</form>
|
|
@ -2,7 +2,6 @@ Huginn::Application.routes.draw do
|
|||
resources :agents do
|
||||
member do
|
||||
post :run
|
||||
post :dry_run
|
||||
post :handle_details_post
|
||||
put :leave_scenario
|
||||
delete :remove_events
|
||||
|
@ -13,7 +12,6 @@ Huginn::Application.routes.draw do
|
|||
put :toggle_visibility
|
||||
post :propagate
|
||||
get :type_details
|
||||
post :dry_run
|
||||
get :event_descriptions
|
||||
post :validate
|
||||
post :complete
|
||||
|
@ -26,6 +24,14 @@ Huginn::Application.routes.draw do
|
|||
end
|
||||
|
||||
resources :events, :only => [:index]
|
||||
|
||||
scope module: :agents do
|
||||
resources :dry_runs, only: [:index, :create]
|
||||
end
|
||||
end
|
||||
|
||||
scope module: :agents do
|
||||
resources :dry_runs, only: [:index, :create]
|
||||
end
|
||||
|
||||
resource :diagram, :only => [:show]
|
||||
|
|
104
spec/controllers/agents/dry_runs_controller_spec.rb
Normal file
104
spec/controllers/agents/dry_runs_controller_spec.rb
Normal file
|
@ -0,0 +1,104 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe Agents::DryRunsController do
|
||||
def valid_attributes(options = {})
|
||||
{
|
||||
type: "Agents::WebsiteAgent",
|
||||
name: "Something",
|
||||
options: agents(:bob_website_agent).options,
|
||||
source_ids: [agents(:bob_weather_agent).id, ""]
|
||||
}.merge(options)
|
||||
end
|
||||
|
||||
before do
|
||||
sign_in users(:bob)
|
||||
end
|
||||
|
||||
describe "GET index" do
|
||||
it "does not load any events without specifing sources" do
|
||||
get :index, type: 'Agents::WebsiteAgent', source_ids: []
|
||||
expect(assigns(:events)).to eq([])
|
||||
end
|
||||
|
||||
context "does not load events when the agent is owned by a different user" do
|
||||
before do
|
||||
@agent = agents(:jane_website_agent)
|
||||
@agent.sources << @agent
|
||||
@agent.save!
|
||||
expect(@agent.events.count).not_to be(0)
|
||||
end
|
||||
|
||||
it "for new agents" do
|
||||
get :index, type: 'Agents::WebsiteAgent', source_ids: [@agent.id]
|
||||
expect(assigns(:events)).to eq([])
|
||||
end
|
||||
|
||||
it "for existing agents" do
|
||||
expect(@agent.events.count).not_to be(0)
|
||||
expect { get :index, agent_id: @agent }.to raise_error(NoMethodError)
|
||||
end
|
||||
end
|
||||
|
||||
context "loads the most recent events" do
|
||||
before do
|
||||
@agent = agents(:bob_website_agent)
|
||||
@agent.sources << @agent
|
||||
@agent.save!
|
||||
end
|
||||
|
||||
it "load the most recent events when providing source ids" do
|
||||
get :index, type: 'Agents::WebsiteAgent', source_ids: [@agent.id]
|
||||
expect(assigns(:events)).to eq([@agent.events.first])
|
||||
end
|
||||
|
||||
it "loads the most recent events for a saved agent" do
|
||||
get :index, agent_id: @agent
|
||||
expect(assigns(:events)).to eq([@agent.events.first])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST create" do
|
||||
before do
|
||||
stub_request(:any, /xkcd/).to_return(body: File.read(Rails.root.join("spec/data_fixtures/xkcd.html")), status: 200)
|
||||
end
|
||||
|
||||
it "does not actually create any agent, event or log" do
|
||||
expect {
|
||||
post :create, agent: valid_attributes
|
||||
}.not_to change {
|
||||
[users(:bob).agents.count, users(:bob).events.count, users(:bob).logs.count]
|
||||
}
|
||||
results = assigns(:results)
|
||||
expect(results[:log]).to be_a(String)
|
||||
expect(results[:log]).to include('Extracting html at')
|
||||
expect(results[:events]).to be_a(Array)
|
||||
expect(results[:events].length).to eq(1)
|
||||
expect(results[:events].map(&:class)).to eq([ActiveSupport::HashWithIndifferentAccess])
|
||||
expect(results[:memory]).to be_a(Hash)
|
||||
end
|
||||
|
||||
it "does not actually update an agent" do
|
||||
agent = agents(:bob_weather_agent)
|
||||
expect {
|
||||
post :create, agent_id: agent, agent: valid_attributes(name: 'New Name')
|
||||
}.not_to change {
|
||||
[users(:bob).agents.count, users(:bob).events.count, users(:bob).logs.count, agent.name, agent.updated_at]
|
||||
}
|
||||
end
|
||||
|
||||
it "accepts an event" do
|
||||
agent = agents(:bob_website_agent)
|
||||
agent.options['url_from_event'] = '{{ url }}'
|
||||
agent.save!
|
||||
url_from_event = "http://xkcd.com/?from_event=1".freeze
|
||||
expect {
|
||||
post :create, agent_id: agent, event: { url: url_from_event }
|
||||
}.not_to change {
|
||||
[users(:bob).agents.count, users(:bob).events.count, users(:bob).logs.count, agent.name, agent.updated_at]
|
||||
}
|
||||
results = assigns(:results)
|
||||
expect(results[:log]).to match(/^\[\d\d:\d\d:\d\d\] INFO -- : Fetching #{Regexp.quote(url_from_event)}$/)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -408,52 +408,6 @@ describe AgentsController do
|
|||
end
|
||||
end
|
||||
|
||||
describe "POST dry_run" do
|
||||
before do
|
||||
stub_request(:any, /xkcd/).to_return(body: File.read(Rails.root.join("spec/data_fixtures/xkcd.html")), status: 200)
|
||||
end
|
||||
|
||||
it "does not actually create any agent, event or log" do
|
||||
sign_in users(:bob)
|
||||
expect {
|
||||
post :dry_run, agent: valid_attributes()
|
||||
}.not_to change {
|
||||
[users(:bob).agents.count, users(:bob).events.count, users(:bob).logs.count]
|
||||
}
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['log']).to be_a(String)
|
||||
expect(json['events']).to be_a(String)
|
||||
expect(JSON.parse(json['events']).map(&:class)).to eq([Hash])
|
||||
expect(json['memory']).to be_a(String)
|
||||
expect(JSON.parse(json['memory'])).to be_a(Hash)
|
||||
end
|
||||
|
||||
it "does not actually update an agent" do
|
||||
sign_in users(:bob)
|
||||
agent = agents(:bob_weather_agent)
|
||||
expect {
|
||||
post :dry_run, id: agent, agent: valid_attributes(name: 'New Name')
|
||||
}.not_to change {
|
||||
[users(:bob).agents.count, users(:bob).events.count, users(:bob).logs.count, agent.name, agent.updated_at]
|
||||
}
|
||||
end
|
||||
|
||||
it "accepts an event" do
|
||||
sign_in users(:bob)
|
||||
agent = agents(:bob_website_agent)
|
||||
agent.options['url_from_event'] = '{{ url }}'
|
||||
agent.save!
|
||||
url_from_event = "http://xkcd.com/?from_event=1".freeze
|
||||
expect {
|
||||
post :dry_run, id: agent, event: { url: url_from_event }
|
||||
}.not_to change {
|
||||
[users(:bob).agents.count, users(:bob).events.count, users(:bob).logs.count, agent.name, agent.updated_at]
|
||||
}
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['log']).to match(/^\[\d\d:\d\d:\d\d\] INFO -- : Fetching #{Regexp.quote(url_from_event)}$/)
|
||||
end
|
||||
end
|
||||
|
||||
describe "DELETE memory" do
|
||||
it "clears memory of the agent" do
|
||||
agent = agents(:bob_website_agent)
|
||||
|
|
Loading…
Add table
Reference in a new issue