refactor JS and fix scheduling clearing bug

Andrew Cantino 10 anos atrás
pai
commit
53b9e47371

+ 3 - 217
app/assets/javascripts/application.js.coffee.erb

@@ -7,220 +7,6 @@
7 7
 #= require jquery.json-editor
8 8
 #= require latlon_and_geo
9 9
 #= require spectrum
10
-#= require ./worker-checker
11
-#= require_self
12
-
13
-window.setupJsonEditor = ($editors = $(".live-json-editor")) ->
14
-  JSONEditor.prototype.ADD_IMG = '<%= image_path 'json-editor/add.png' %>'
15
-  JSONEditor.prototype.DELETE_IMG = '<%= image_path 'json-editor/delete.png' %>'
16
-  editors = []
17
-  $editors.each ->
18
-    $editor = $(this)
19
-    jsonEditor = new JSONEditor($editor, $editor.data('width') || 400, $editor.data('height') || 500)
20
-    jsonEditor.doTruncation true
21
-    jsonEditor.showFunctionButtons()
22
-    editors.push jsonEditor
23
-  return editors
24
-
25
-hideSchedule = ->
26
-  $(".schedule-region .can-be-scheduled").hide()
27
-  $(".schedule-region .cannot-be-scheduled").show()
28
-
29
-showSchedule = (defaultSchedule = null) ->
30
-  if defaultSchedule?
31
-    $(".schedule-region select").val(defaultSchedule).change()
32
-  $(".schedule-region .can-be-scheduled").show()
33
-  $(".schedule-region .cannot-be-scheduled").hide()
34
-
35
-hideLinks = ->
36
-  $(".link-region .select2-container").hide()
37
-  $(".link-region .propagate-immediately").hide()
38
-  $(".link-region .cannot-receive-events").show()
39
-
40
-showLinks = ->
41
-  $(".link-region .select2-container").show()
42
-  $(".link-region .propagate-immediately").show()
43
-  $(".link-region .cannot-receive-events").hide()
44
-  showEventDescriptions()
45
-
46
-hideControlLinks = ->
47
-  $(".control-link-region").hide()
48
-
49
-showControlLinks = ->
50
-  $(".control-link-region").show()
51
-
52
-hideEventCreation = ->
53
-  $(".event-related-region").hide()
54
-
55
-showEventCreation = ->
56
-  $(".event-related-region").show()
57
-
58
-showEventDescriptions = ->
59
-  if $("#agent_source_ids").val()
60
-    $.getJSON "/agents/event_descriptions", { ids: $("#agent_source_ids").val().join(",") }, (json) =>
61
-      if json.description_html?
62
-        $(".event-descriptions").show().html(json.description_html)
63
-      else
64
-        $(".event-descriptions").hide()
65
-  else
66
-    $(".event-descriptions").html("").hide()
67
-
68
-$(document).ready ->
69
-  $('.navbar .dropdown.dropdown-hover').hover \
70
-    -> $(this).addClass('open'),
71
-    -> $(this).removeClass('open')
72
-
73
-  # JSON Editor
74
-  window.jsonEditor = setupJsonEditor()[0]
75
-
76
-  # Flash
77
-  if $(".flash").length
78
-    setTimeout((-> $(".flash").slideUp(-> $(".flash").remove())), 5000)
79
-
80
-  # Help popovers
81
-  $('.hover-help').popover(trigger: 'hover', html: true)
82
-
83
-  # Agent Navigation
84
-  $agentNavigate = $('#agent-navigate')
85
-
86
-  # initialize typeahead listener
87
-  $agentNavigate.bind "typeahead:selected", (event, object, name) ->
88
-    item = object['value']
89
-    $agentNavigate.typeahead('val', '')
90
-    if agentPaths[item]
91
-      $(".spinner").show()
92
-      navigationData = agentPaths[item]
93
-      if !(navigationData instanceof Object) || !navigationData.method || navigationData.method == 'GET'
94
-        window.location = navigationData.url || navigationData
95
-      else
96
-        $("<a href='#{navigationData.url}' data-method='#{navigationData.method}'></a>").appendTo($("body")).click()
97
-
98
-  # substring matcher for typeahead
99
-  substringMatcher = (strings)->
100
-    findMatches = (query, callback) ->
101
-      matches = []
102
-      substrRegex = new RegExp(query, "i")
103
-      $.each strings, (i, str) ->
104
-        matches.push value: str  if substrRegex.test(str)
105
-      callback(matches.slice(0,6))
106
-
107
-  $agentNavigate.typeahead
108
-    minLength: 1,
109
-    highlight: true,
110
-  ,
111
-    source: substringMatcher(agentNames)
112
-
113
-
114
-  # Pressing '/' selects the search box.
115
-  $("body").on "keypress", (e) ->
116
-    if e.keyCode == 47 # The '/' key
117
-      if e.target.nodeName == "BODY"
118
-        e.preventDefault()
119
-        $agentNavigate.focus()
120
-
121
-  # Agent Show
122
-  fetchLogs = (e) ->
123
-    agentId = $(e.target).closest("[data-agent-id]").data("agent-id")
124
-    e.preventDefault()
125
-    $("#logs .spinner").show()
126
-    $("#logs .refresh, #logs .clear").hide()
127
-    $.get "/agents/#{agentId}/logs", (html) =>
128
-      $("#logs .logs").html html
129
-      $("#logs .spinner").stop(true, true).fadeOut ->
130
-        $("#logs .refresh, #logs .clear").show()
131
-
132
-  clearLogs = (e) ->
133
-    if confirm("Are you sure you want to clear all logs for this Agent?")
134
-      agentId = $(e.target).closest("[data-agent-id]").data("agent-id")
135
-      e.preventDefault()
136
-      $("#logs .spinner").show()
137
-      $("#logs .refresh, #logs .clear").hide()
138
-      $.post "/agents/#{agentId}/logs/clear", { "_method": "DELETE" }, (html) =>
139
-        $("#logs .logs").html html
140
-        $("#show-tabs li a.recent-errors").removeClass 'recent-errors'
141
-        $("#logs .spinner").stop(true, true).fadeOut ->
142
-          $("#logs .refresh, #logs .clear").show()
143
-
144
-  $(".agent-show #show-tabs a[href='#logs'], #logs .refresh").on "click", fetchLogs
145
-  $(".agent-show #logs .clear").on "click", clearLogs
146
-
147
-  if tab = window.location.href.match(/tab=(\w+)\b/i)?[1]
148
-    if tab in ["details", "logs"]
149
-      $(".agent-show .nav-pills li a[href='##{tab}']").click()
150
-
151
-  # Editing Agents
152
-  $("#agent_source_ids").on "change", showEventDescriptions
153
-
154
-  $("#agent_type").on "change", ->
155
-    if window.jsonEditor?
156
-      $("#agent-spinner").fadeIn();
157
-      $("#agent_source_ids").select2("val", {});
158
-      $(".event-descriptions").html("").hide()
159
-      $.getJSON "/agents/type_details", { type: $(@).val() }, (json) =>
160
-        if json.can_be_scheduled
161
-          showSchedule(json.default_schedule)
162
-        else
163
-          hideSchedule()
164
-
165
-        if json.can_receive_events
166
-          showLinks()
167
-        else
168
-          hideLinks()
169
-
170
-        if json.can_control_other_agents
171
-          showControlLinks()
172
-        else
173
-          hideControlLinks()
174
-
175
-        if json.can_create_events
176
-          showEventCreation()
177
-        else
178
-          hideEventCreation()
179
-
180
-        $(".description").html(json.description_html) if json.description_html?
181
-
182
-        $('.oauthable-form').html(json.form) if json.form?
183
-
184
-        if $("#agent_options").hasClass("showing-default") || $("#agent_options").val().match(/\A\s*(\{\s*\}|)\s*\Z/g)
185
-          window.jsonEditor.json = json.options
186
-          window.jsonEditor.rebuild()
187
-
188
-        $("#agent-spinner").stop(true, true).fadeOut();
189
-
190
-  $("#agent_type").change() if $("#agent_type").length
191
-
192
-  # Select2 Selects
193
-  $(".select2").select2(width: 'resolve')
194
-
195
-  if $(".schedule-region")
196
-    if $(".schedule-region").data("can-be-scheduled") == true
197
-      showSchedule()
198
-    else
199
-      hideSchedule()
200
-
201
-  if $(".link-region")
202
-    if $(".link-region").data("can-receive-events") == true
203
-      showLinks()
204
-    else
205
-      hideLinks()
206
-
207
-  if $(".control-link-region")
208
-    if $(".control-link-region").data("can-control-other-agents") == true
209
-      showControlLinks()
210
-    else
211
-      hideControlLinks()
212
-
213
-  if $(".event-related-region")
214
-    if $(".event-related-region").data("can-create-events") == true
215
-      showEventCreation()
216
-    else
217
-      hideEventCreation()
218
-
219
-  $('.selectable-text').each ->
220
-    $(this).click ->
221
-      range = document.createRange()
222
-      range.setStartBefore(this.firstChild)
223
-      range.setEndAfter(this.lastChild)
224
-      sel = window.getSelection()
225
-      sel.removeAllRanges();
226
-      sel.addRange(range)
10
+#= require_tree ./components
11
+#= require_tree ./pages
12
+#= require_self

+ 30 - 0
app/assets/javascripts/components/core.js.coffee

@@ -0,0 +1,30 @@
1
+$ ->
2
+  # Flash
3
+  if $(".flash").length
4
+    setTimeout((-> $(".flash").slideUp(-> $(".flash").remove())), 5000)
5
+
6
+  # Help popovers
7
+  $('.hover-help').popover(trigger: 'hover', html: true)
8
+
9
+  # Pressing '/' selects the search box.
10
+  $("body").on "keypress", (e) ->
11
+    if e.keyCode == 47 # The '/' key
12
+      if e.target.nodeName == "BODY"
13
+        e.preventDefault()
14
+        $agentNavigate.focus()
15
+
16
+  # Select2 Selects
17
+  $(".select2").select2(width: 'resolve')
18
+
19
+  # Helper for selecting text when clicked
20
+  $('.selectable-text').each ->
21
+    $(this).click ->
22
+      range = document.createRange()
23
+      range.setStartBefore(this.firstChild)
24
+      range.setEndAfter(this.lastChild)
25
+      sel = window.getSelection()
26
+      sel.removeAllRanges();
27
+      sel.addRange(range)
28
+
29
+  # Agent navbar dropdown
30
+  $('.navbar .dropdown.dropdown-hover').hover (-> $(this).addClass('open')), (-> $(this).removeClass('open'))

+ 14 - 0
app/assets/javascripts/components/json-editor.js.coffee.erb

@@ -0,0 +1,14 @@
1
+window.setupJsonEditor = ($editors = $(".live-json-editor")) ->
2
+  JSONEditor.prototype.ADD_IMG = '<%= image_path 'json-editor/add.png' %>'
3
+  JSONEditor.prototype.DELETE_IMG = '<%= image_path 'json-editor/delete.png' %>'
4
+  editors = []
5
+  $editors.each ->
6
+    $editor = $(this)
7
+    jsonEditor = new JSONEditor($editor, $editor.data('width') || 400, $editor.data('height') || 500)
8
+    jsonEditor.doTruncation true
9
+    jsonEditor.showFunctionButtons()
10
+    editors.push jsonEditor
11
+  return editors
12
+
13
+$ ->
14
+  window.jsonEditor = setupJsonEditor()[0]

+ 29 - 0
app/assets/javascripts/components/search.js.coffee

@@ -0,0 +1,29 @@
1
+$ ->
2
+  $agentNavigate = $('#agent-navigate')
3
+
4
+  # initialize typeahead listener
5
+  $agentNavigate.bind "typeahead:selected", (event, object, name) ->
6
+    item = object['value']
7
+    $agentNavigate.typeahead('val', '')
8
+    if window.agentPaths[item]
9
+      $(".spinner").show()
10
+      navigationData = window.agentPaths[item]
11
+      if !(navigationData instanceof Object) || !navigationData.method || navigationData.method == 'GET'
12
+        window.location = navigationData.url || navigationData
13
+      else
14
+        $("<a href='#{navigationData.url}' data-method='#{navigationData.method}'></a>").appendTo($("body")).click()
15
+
16
+  # substring matcher for typeahead
17
+  substringMatcher = (strings) ->
18
+    findMatches = (query, callback) ->
19
+      matches = []
20
+      substrRegex = new RegExp(query, "i")
21
+      $.each strings, (i, str) ->
22
+        matches.push value: str  if substrRegex.test(str)
23
+      callback(matches.slice(0,6))
24
+
25
+  $agentNavigate.typeahead
26
+    minLength: 1,
27
+    highlight: true,
28
+  ,
29
+    source: substringMatcher(window.agentNames)

+ 14 - 0
app/assets/javascripts/components/utils.js.coffee

@@ -0,0 +1,14 @@
1
+class @Utils
2
+  @navigatePath: (path) ->
3
+    path = "/" + path unless path.match(/^\//)
4
+    window.location.href = path
5
+
6
+  @currentPath: ->
7
+    window.location.href.replace(/https?:\/\/.*?\//g, '')
8
+
9
+  @registerPage: (klass, options = {}) ->
10
+    if options.forPathsMatching?
11
+      if Utils.currentPath().match(options.forPathsMatching)
12
+        window.currentPage = new klass()
13
+    else
14
+      new klass()

app/assets/javascripts/worker-checker.js.coffee → app/assets/javascripts/components/worker-checker.js.coffee


+ 2 - 0
app/assets/javascripts/diagram.js.coffee

@@ -1,3 +1,5 @@
1
+# This is not included in the core application.js bundle.
2
+
1 3
 $ ->
2 4
   svg = document.querySelector('.agent-diagram svg.diagram')
3 5
   overlay = document.querySelector('.agent-diagram .overlay')

+ 2 - 0
app/assets/javascripts/graphing.js.coffee

@@ -2,6 +2,8 @@
2 2
 #= require rickshaw
3 3
 #= require_self
4 4
 
5
+# This is not included in the core application.js bundle.
6
+
5 7
 window.renderGraph = ($chart, data, peaks, name) ->
6 8
   graph = new Rickshaw.Graph
7 9
     element: $chart.find(".chart").get(0)

+ 126 - 0
app/assets/javascripts/pages/agent-edit-page.js.coffee

@@ -0,0 +1,126 @@
1
+class @AgentEditPage
2
+  constructor: ->
3
+    $("#agent_source_ids").on "change", @showEventDescriptions
4
+    @showCorrectRegionsOnStartup()
5
+
6
+    # The type selector is only available on the new agent form.
7
+    if $("#agent_type").length
8
+      $("#agent_type").on "change", => @handleTypeChange(false)
9
+      @handleTypeChange(true)
10
+
11
+  handleTypeChange: (firstTime) ->
12
+    $(".event-descriptions").html("").hide()
13
+    type = $('#agent_type').val()
14
+
15
+    if type == 'Agent'
16
+      $(".agent-settings").hide()
17
+      $(".description").hide()
18
+    else
19
+      $(".agent-settings").show()
20
+      $("#agent-spinner").fadeIn()
21
+      $("#agent_source_ids").select2("val", {})
22
+      $(".model-errors").hide() unless firstTime
23
+      $.getJSON "/agents/type_details", { type: type }, (json) =>
24
+        if json.can_be_scheduled
25
+          if firstTime
26
+            @showSchedule()
27
+          else
28
+            @showSchedule(json.default_schedule)
29
+        else
30
+          @hideSchedule()
31
+
32
+        if json.can_receive_events
33
+          @showLinks()
34
+        else
35
+          @hideLinks()
36
+
37
+        if json.can_control_other_agents
38
+          @showControlLinks()
39
+        else
40
+          @hideControlLinks()
41
+
42
+        if json.can_create_events
43
+          @showEventCreation()
44
+        else
45
+          @hideEventCreation()
46
+
47
+        $(".description").show().html(json.description_html) if json.description_html?
48
+
49
+        $('.oauthable-form').html(json.form) if json.form?
50
+
51
+        unless firstTime
52
+          window.jsonEditor.json = json.options
53
+          window.jsonEditor.rebuild()
54
+
55
+        $("#agent-spinner").stop(true, true).fadeOut();
56
+
57
+  hideSchedule: ->
58
+    $(".schedule-region .can-be-scheduled").hide()
59
+    $(".schedule-region .cannot-be-scheduled").show()
60
+
61
+  showSchedule: (defaultSchedule = null) ->
62
+    if defaultSchedule?
63
+      $(".schedule-region select").val(defaultSchedule).change()
64
+    $(".schedule-region .can-be-scheduled").show()
65
+    $(".schedule-region .cannot-be-scheduled").hide()
66
+
67
+  hideLinks: ->
68
+    $(".link-region .select2-container").hide()
69
+    $(".link-region .propagate-immediately").hide()
70
+    $(".link-region .cannot-receive-events").show()
71
+
72
+  showLinks: ->
73
+    $(".link-region .select2-container").show()
74
+    $(".link-region .propagate-immediately").show()
75
+    $(".link-region .cannot-receive-events").hide()
76
+    @showEventDescriptions()
77
+
78
+  hideControlLinks: ->
79
+    $(".control-link-region").hide()
80
+
81
+  showControlLinks: ->
82
+    $(".control-link-region").show()
83
+
84
+  hideEventCreation: ->
85
+    $(".event-related-region").hide()
86
+
87
+  showEventCreation: ->
88
+    $(".event-related-region").show()
89
+
90
+  showEventDescriptions: ->
91
+    if $("#agent_source_ids").val()
92
+      $.getJSON "/agents/event_descriptions", { ids: $("#agent_source_ids").val().join(",") }, (json) =>
93
+        if json.description_html?
94
+          $(".event-descriptions").show().html(json.description_html)
95
+        else
96
+          $(".event-descriptions").hide()
97
+    else
98
+      $(".event-descriptions").html("").hide()
99
+
100
+  showCorrectRegionsOnStartup: ->
101
+    if $(".schedule-region")
102
+      if $(".schedule-region").data("can-be-scheduled") == true
103
+        @showSchedule()
104
+      else
105
+        @hideSchedule()
106
+
107
+    if $(".link-region")
108
+      if $(".link-region").data("can-receive-events") == true
109
+        @showLinks()
110
+      else
111
+        @hideLinks()
112
+
113
+    if $(".control-link-region")
114
+      if $(".control-link-region").data("can-control-other-agents") == true
115
+        @showControlLinks()
116
+      else
117
+        @hideControlLinks()
118
+
119
+    if $(".event-related-region")
120
+      if $(".event-related-region").data("can-create-events") == true
121
+        @showEventCreation()
122
+      else
123
+        @hideEventCreation()
124
+
125
+$ ->
126
+  Utils.registerPage(AgentEditPage, forPathsMatching: /^agents/)

+ 35 - 0
app/assets/javascripts/pages/agent-show-page.js.coffee

@@ -0,0 +1,35 @@
1
+class @AgentShowPage
2
+  constructor: ->
3
+    $(".agent-show #show-tabs a[href='#logs'], #logs .refresh").on "click", @fetchLogs
4
+    $(".agent-show #logs .clear").on "click", @clearLogs
5
+
6
+    # Trigger tabs when navigated to.
7
+    if tab = window.location.href.match(/tab=(\w+)\b/i)?[1]
8
+      if tab in ["details", "logs"]
9
+        $(".agent-show .nav-pills li a[href='##{tab}']").click()
10
+
11
+  fetchLogs: (e) ->
12
+    agentId = $(e.target).closest("[data-agent-id]").data("agent-id")
13
+    e.preventDefault()
14
+    $("#logs .spinner").show()
15
+    $("#logs .refresh, #logs .clear").hide()
16
+    $.get "/agents/#{agentId}/logs", (html) =>
17
+      $("#logs .logs").html html
18
+      $("#logs .spinner").stop(true, true).fadeOut ->
19
+        $("#logs .refresh, #logs .clear").show()
20
+
21
+  clearLogs: (e) ->
22
+    if confirm("Are you sure you want to clear all logs for this Agent?")
23
+      agentId = $(e.target).closest("[data-agent-id]").data("agent-id")
24
+      e.preventDefault()
25
+      $("#logs .spinner").show()
26
+      $("#logs .refresh, #logs .clear").hide()
27
+      $.post "/agents/#{agentId}/logs/clear", { "_method": "DELETE" }, (html) =>
28
+        $("#logs .logs").html html
29
+        $("#show-tabs li a.recent-errors").removeClass 'recent-errors'
30
+        $("#logs .spinner").stop(true, true).fadeOut ->
31
+          $("#logs .refresh, #logs .clear").show()
32
+
33
+$ ->
34
+  Utils.registerPage(AgentShowPage, forPathsMatching: /^agents\/\d+/)
35
+

+ 2 - 0
app/assets/javascripts/user_credentials.js.coffee

@@ -3,6 +3,8 @@
3 3
 #= require ace/mode-markdown.js
4 4
 #= require_self
5 5
 
6
+# This is not included in the core application.js bundle.
7
+
6 8
 $ ->
7 9
   editor = ace.edit("ace-credential-value")
8 10
   editor.getSession().setTabSize(2)

+ 0 - 1
app/models/agents/adioso_agent.rb

@@ -1,6 +1,5 @@
1 1
 module Agents
2 2
   class AdiosoAgent < Agent
3
-
4 3
     cannot_receive_events!
5 4
 
6 5
   	default_schedule "every_1d"

+ 74 - 70
app/views/agents/_form.html.erb

@@ -1,5 +1,5 @@
1 1
 <% if @agent.errors.any? %>
2
-  <div class="row well">
2
+  <div class="row well model-errors">
3 3
     <h2><%= pluralize(@agent.errors.count, "error") %> prohibited this Agent from being saved:</h2>
4 4
     <% @agent.errors.full_messages.each do |msg| %>
5 5
       <p class='text-warning'><%= msg %></p>
@@ -21,99 +21,103 @@
21 21
           <% if @agent.new_record? %>
22 22
             <div class="form-group type-select">
23 23
               <%= f.label :type %>
24
-              <%= f.select :type, options_for_select(Agent.types.map(&:to_s).sort.map {|type| [type.gsub(/^.*::/, ''), type] }, @agent.type), {}, :class => 'select2 form-control' %>
24
+              <%= f.select :type, options_for_select([['Select an Agent Type', 'Agent']] + Agent.types.map(&:to_s).sort.map {|type| [type.gsub(/^.*::/, ''), type] }, @agent.type), {}, :class => 'select2 form-control' %>
25 25
             </div>
26 26
           <% end %>
27
+        </div>
27 28
 
28
-          <div class="form-group type-select">
29
-            <%= f.label :name %>
30
-            <%= f.text_field :name, :class => 'form-control' %>
31
-          </div>
32
-
33
-          <div class='oauthable-form'>
34
-            <%= render partial: 'oauth_dropdown', locals: { agent: @agent } %>
35
-          </div>
29
+        <div class="agent-settings">
30
+          <div class="col-md-8">
31
+            <div class="form-group">
32
+              <%= f.label :name %>
33
+              <%= f.text_field :name, :class => 'form-control' %>
34
+            </div>
36 35
 
37
-          <div class="form-group">
38
-            <%= f.label :schedule, :class => 'control-label' %>
39
-            <div class="schedule-region" data-can-be-scheduled="<%= @agent.can_be_scheduled? %>">
40
-              <div class="can-be-scheduled">
41
-                <%= f.select :schedule, options_for_select(Agent::SCHEDULES.map {|s| [s.humanize.titleize, s] }, @agent.schedule), {}, :class => 'form-control' %>
42
-              </div>
43
-              <span class='cannot-be-scheduled text-info'>This type of Agent cannot be scheduled.</span>
36
+            <div class='oauthable-form'>
37
+              <%= render partial: 'oauth_dropdown', locals: { agent: @agent } %>
44 38
             </div>
45
-          </div>
46 39
 
47
-          <div class="controller-region" data-has-controllers="<%= !@agent.controllers.empty? %>">
48 40
             <div class="form-group">
49
-              <%= f.label :controllers %>
50
-              <span class="glyphicon glyphicon-question-sign hover-help" data-content="Other than the system-defined schedule above, this agent may be run or controlled by these user-defined Agents."></span>
51
-              <div class="controller-list">
52
-                <%= agent_controllers(@agent) || 'None' %>
41
+              <%= f.label :schedule, :class => 'control-label' %>
42
+              <div class="schedule-region" data-can-be-scheduled="<%= @agent.can_be_scheduled? %>">
43
+                <div class="can-be-scheduled">
44
+                  <%= f.select :schedule, options_for_select(Agent::SCHEDULES.map {|s| [s.humanize.titleize, s] }, @agent.schedule), {}, :class => 'form-control' %>
45
+                </div>
46
+                <span class='cannot-be-scheduled text-info'>This type of Agent cannot be scheduled.</span>
53 47
               </div>
54 48
             </div>
55
-          </div>
56 49
 
57
-          <div class="control-link-region" data-can-control-other-agents="<%= @agent.can_control_other_agents? %>">
58
-            <div class="can-control-other-agents">
50
+            <div class="controller-region" data-has-controllers="<%= !@agent.controllers.empty? %>">
59 51
               <div class="form-group">
60
-                <%= f.label :control_targets %>
61
-                <% eventControlTargets = current_user.agents.select(&:can_be_scheduled?) %>
62
-                <%= f.select(:control_target_ids,
63
-                             options_for_select(eventControlTargets.map {|s| [s.name, s.id] },
64
-                                                @agent.control_target_ids),
65
-                             {}, { multiple: true, size: 5, class: 'select2 form-control' }) %>
52
+                <%= f.label :controllers %>
53
+                <span class="glyphicon glyphicon-question-sign hover-help" data-content="Other than the system-defined schedule above, this agent may be run or controlled by these user-defined Agents."></span>
54
+                <div class="controller-list">
55
+                  <%= agent_controllers(@agent) || 'None' %>
56
+                </div>
66 57
               </div>
67 58
             </div>
68
-          </div>
69 59
 
70
-          <div class='event-related-region' data-can-create-events="<%= @agent.can_create_events? %>">
71
-            <div class="form-group">
72
-              <%= f.label :keep_events_for, "Keep events" %>
73
-              <span class="glyphicon glyphicon-question-sign hover-help" data-content="In order to conserve disk space, you can choose to have events created by this Agent expire after a certain period of time.  Make sure you keep them long enough to allow any subsequent Agents to make use of them."></span>
74
-              <%= f.select :keep_events_for, options_for_select(Agent::EVENT_RETENTION_SCHEDULES, @agent.keep_events_for), {}, :class => 'form-control' %>
60
+            <div class="control-link-region" data-can-control-other-agents="<%= @agent.can_control_other_agents? %>">
61
+              <div class="can-control-other-agents">
62
+                <div class="form-group">
63
+                  <%= f.label :control_targets %>
64
+                  <% eventControlTargets = current_user.agents.select(&:can_be_scheduled?) %>
65
+                  <%= f.select(:control_target_ids,
66
+                               options_for_select(eventControlTargets.map {|s| [s.name, s.id] },
67
+                                                  @agent.control_target_ids),
68
+                               {}, { multiple: true, size: 5, class: 'select2 form-control' }) %>
69
+                </div>
70
+              </div>
75 71
             </div>
76
-          </div>
77 72
 
78
-          <div class="form-group">
79
-            <%= f.label :sources %>
80
-            <div class="link-region" data-can-receive-events="<%= @agent.can_receive_events? %>">
81
-              <% eventSources = (current_user.agents - [@agent]).find_all { |a| a.can_create_events? } %>
82
-              <%= f.select(:source_ids,
83
-                           options_for_select(eventSources.map {|s| [s.name, s.id] },
84
-                                              @agent.source_ids),
85
-                           {}, { :multiple => true, :size => 5, :class => 'select2 form-control' }) %>
86
-              <span class='cannot-receive-events text-info'>This type of Agent cannot receive events.</span>
87
-              <%= f.label :propagate_immediately, :class => 'propagate-immediately' do %>Propagate immediately
88
-                <%= f.check_box :propagate_immediately %> 
89
-              <% end %>
73
+            <div class='event-related-region' data-can-create-events="<%= @agent.can_create_events? %>">
74
+              <div class="form-group">
75
+                <%= f.label :keep_events_for, "Keep events" %>
76
+                <span class="glyphicon glyphicon-question-sign hover-help" data-content="In order to conserve disk space, you can choose to have events created by this Agent expire after a certain period of time.  Make sure you keep them long enough to allow any subsequent Agents to make use of them."></span>
77
+                <%= f.select :keep_events_for, options_for_select(Agent::EVENT_RETENTION_SCHEDULES, @agent.keep_events_for), {}, :class => 'form-control' %>
78
+              </div>
90 79
             </div>
91
-          </div>
92 80
 
93
-          <% if current_user.scenario_count > 0 %>
94 81
             <div class="form-group">
95
-              <%= f.label :scenarios %>
96
-              <span class="glyphicon glyphicon-question-sign hover-help" data-content="Use Scenarios to group sets of Agents, both for organization, and to make them easy to export and share."></span>
97
-              <%= f.select(:scenario_ids,
98
-                           options_for_select(current_user.scenarios.pluck(:name, :id), @agent.scenario_ids),
99
-                           {}, { :multiple => true, :size => 5, :class => 'select2 form-control' }) %>
82
+              <%= f.label :sources %>
83
+              <div class="link-region" data-can-receive-events="<%= @agent.can_receive_events? %>">
84
+                <% eventSources = (current_user.agents - [@agent]).find_all { |a| a.can_create_events? } %>
85
+                <%= f.select(:source_ids,
86
+                             options_for_select(eventSources.map {|s| [s.name, s.id] },
87
+                                                @agent.source_ids),
88
+                             {}, { :multiple => true, :size => 5, :class => 'select2 form-control' }) %>
89
+                <span class='cannot-receive-events text-info'>This type of Agent cannot receive events.</span>
90
+                <%= f.label :propagate_immediately, :class => 'propagate-immediately' do %>Propagate immediately
91
+                  <%= f.check_box :propagate_immediately %>
92
+                <% end %>
93
+              </div>
100 94
             </div>
101
-          <% end %>
102 95
 
103
-        </div>
96
+            <% if current_user.scenario_count > 0 %>
97
+              <div class="form-group">
98
+                <%= f.label :scenarios %>
99
+                <span class="glyphicon glyphicon-question-sign hover-help" data-content="Use Scenarios to group sets of Agents, both for organization, and to make them easy to export and share."></span>
100
+                <%= f.select(:scenario_ids,
101
+                             options_for_select(current_user.scenarios.pluck(:name, :id), @agent.scenario_ids),
102
+                             {}, { :multiple => true, :size => 5, :class => 'select2 form-control' }) %>
103
+              </div>
104
+            <% end %>
104 105
 
105
-        <!-- Form controls full width -->
106
-        <div class="col-md-12">
107
-          <div class="form-group">
108
-            <%= f.label :options %>
109
-            <span class="glyphicon glyphicon-question-sign hover-help" data-content="In this JSON hash, interpolation is available in almost all values using the Liquid templating language.<p>Available template variables include the following:<dl><dt><code>message</code>, <code>url</code>, etc.</dt><dd>Refers to the corresponding key's value of each incoming event's payload.</dd><dt><code>agent</code></dt><dd>Refers to the agent that created each incoming event.  It has attributes like <code>type</code>, <code>name</code> and <code>options</code>, so <code>{{agent.type}}</code> will expand to <code>WebsiteAgent</code> if an incoming event is created by that agent.</dd></dl></p><p>To access user credentials, use the <code>credential</code> tag like this: <code>{% credential <em>bare_key_name</em> %}</code></p>"></span>
110
-            <textarea rows="15" id="agent_options" name="agent[options]" class="form-control live-json-editor <%= (@agent.new_record? && @agent.options == {}) ? "showing-default" : "" %>">
111
-              <%= Utils.jsonify((@agent.new_record? && @agent.options == {}) ? @agent.default_options : @agent.options) %>
112
-            </textarea>
113 106
           </div>
114 107
 
115
-          <div class="form-group">
116
-            <%= f.submit "Save", :class => "btn btn-primary" %>
108
+          <!-- Form controls full width -->
109
+          <div class="col-md-12">
110
+            <div class="form-group">
111
+              <%= f.label :options %>
112
+              <span class="glyphicon glyphicon-question-sign hover-help" data-content="In this JSON hash, interpolation is available in almost all values using the Liquid templating language.<p>Available template variables include the following:<dl><dt><code>message</code>, <code>url</code>, etc.</dt><dd>Refers to the corresponding key's value of each incoming event's payload.</dd><dt><code>agent</code></dt><dd>Refers to the agent that created each incoming event.  It has attributes like <code>type</code>, <code>name</code> and <code>options</code>, so <code>{{agent.type}}</code> will expand to <code>WebsiteAgent</code> if an incoming event is created by that agent.</dd></dl></p><p>To access user credentials, use the <code>credential</code> tag like this: <code>{% credential <em>bare_key_name</em> %}</code></p>"></span>
113
+              <textarea rows="15" id="agent_options" name="agent[options]" class="form-control live-json-editor">
114
+                <%= Utils.jsonify((@agent.new_record? && @agent.options == {}) ? @agent.default_options : @agent.options) %>
115
+              </textarea>
116
+            </div>
117
+
118
+            <div class="form-group">
119
+              <%= f.submit "Save", :class => "btn btn-primary" %>
120
+            </div>
117 121
           </div>
118 122
         </div>
119 123
       </div>

+ 11 - 12
app/views/layouts/application.html.erb

@@ -35,22 +35,21 @@
35 35
     </div>
36 36
 
37 37
     <script>
38
-      var agentPaths = {};
39
-      var agentNames = [];
38
+      window.agentPaths = {};
39
+      window.agentNames = [];
40 40
       <% if current_user.present? -%>
41 41
         var myAgents = <%= Utils.jsonify(current_user.agents.pluck(:name, :id).inject({}) {|m, a| m[a.first] = agent_path(a.last); m }) %>;
42 42
         var myScenarios = <%= Utils.jsonify(current_user.scenarios.pluck(:name, :id).inject({}) {|m, s| m[s.first + " Scenario"] = scenario_path(s.last); m }) %>;
43
-        $.extend(agentPaths, myAgents);
44
-        $.extend(agentPaths, myScenarios);
45
-        agentPaths["All Agents Index"] = <%= Utils.jsonify agents_path %>;
46
-        agentPaths["New Agent"] = <%= Utils.jsonify new_agent_path %>;
47
-        agentPaths["Account"] = <%= Utils.jsonify edit_user_registration_path %>;
48
-        agentPaths["Events Index"] = <%= Utils.jsonify events_path %>;
49
-        agentPaths["View Agent Diagram"] = <%= Utils.jsonify diagram_path %>;
50
-        agentPaths["Run Event Propagation"] = { url: <%= Utils.jsonify propagate_agents_path %>, method: 'POST' };
43
+        $.extend(window.agentPaths, myAgents);
44
+        $.extend(window.agentPaths, myScenarios);
45
+        window.agentPaths["All Agents Index"] = <%= Utils.jsonify agents_path %>;
46
+        window.agentPaths["New Agent"] = <%= Utils.jsonify new_agent_path %>;
47
+        window.agentPaths["Account"] = <%= Utils.jsonify edit_user_registration_path %>;
48
+        window.agentPaths["Events Index"] = <%= Utils.jsonify events_path %>;
49
+        window.agentPaths["View Agent Diagram"] = <%= Utils.jsonify diagram_path %>;
50
+        window.agentPaths["Run Event Propagation"] = { url: <%= Utils.jsonify propagate_agents_path %>, method: 'POST' };
51 51
 
52
-
53
-        $.each(agentPaths, function(name, v) { agentNames.push(name); });
52
+        $.each(window.agentPaths, function(name, v) { window.agentNames.push(name); });
54 53
       <% end -%>
55 54
     </script>
56 55
   </body>