command_proposal 1.0.12 → 1.0.15

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab0271a9e0e80bf0df78d8284cc8e13d292ef2254ab57180b1434f50b351dcb7
4
- data.tar.gz: 21b077ee6cfa9ede8ea83315523297ff9268bf5236de797c9f3acae9f1ef3910
3
+ metadata.gz: 321b3627d2af7cf183da1cd1071775e7f13907b0fda6101acce253f9649f8a42
4
+ data.tar.gz: c9a30e58a53bb372807e05e765a7b92368433ced38325e8d7800e9f6b983eeb8
5
5
  SHA512:
6
- metadata.gz: 52a46842e394c99d8dbb4527c222ab93e93dc437992996b3b9af3850a9bc6571bac4e472268c7f821d6b541c17074d21954d0b18e5e15d2109141a4f04179491
7
- data.tar.gz: eb670b929efd2d6c612997e569276fac67aa494325db38d357a5589496bdba19b0d5335d68696d715022b45e9ed13eae4e2245d4ddc12f53371ad3d611e4987b
6
+ metadata.gz: ddcd08648f107fb5e50c57ae46a7ff93ddb1f7e79ea900e7a052afd6fb31574fd85fae1bf4a2214313a6fae8b46d79e4406d2be6756714319d928c259b612557
7
+ data.tar.gz: 629c1bc1f60e363396a7672122dc0a945c042baed8c43339fbc5ae7d80cb71aa645de0d3c199709d923cc1c1376e3d305b273ef3f71275ae53215899e59e3ef1
@@ -142,14 +142,16 @@ cmdDocReady(function() {
142
142
 
143
143
  console_input.textContent = ""
144
144
 
145
- var result = document.createElement("div")
146
- result.classList.add("result")
145
+ if (!(/^[\s\n]*$/.test(line.textContent))) {
146
+ var result = document.createElement("div")
147
+ result.classList.add("result")
147
148
 
148
- var spinner = document.createElement("i")
149
- spinner.className = "fa fa-circle-o-notch fa-spin cmd-icon-grey"
150
- result.append(spinner)
149
+ var spinner = document.createElement("i")
150
+ spinner.className = "fa fa-circle-o-notch fa-spin cmd-icon-grey"
151
+ result.append(spinner)
151
152
 
152
- line.appendChild(result)
153
+ line.appendChild(result)
154
+ }
153
155
 
154
156
  lines.appendChild(line)
155
157
  stored_entry = undefined
@@ -176,41 +178,77 @@ cmdDocReady(function() {
176
178
  body: JSON.stringify(params),
177
179
  done: function(res, status, req) {
178
180
  if (status == 200) {
179
- var json = JSON.parse(res)
180
- line.querySelector(".result").remove()
181
-
182
- var result = document.createElement("div")
183
- result.classList.add("result")
184
-
185
- if (json.error) {
186
- result.classList.add("cmd-error")
187
- result.textContent = json.error
188
- } else {
189
- var truncate = 2000
190
- if (json.result.length > truncate-3) {
191
- result.textContent = json.result.slice(0, truncate-3) + "..."
192
- var encoded = encodeURIComponent(json.result)
193
-
194
- var download = document.createElement("a")
195
- download.classList.add("cmd-truncated-download")
196
- download.setAttribute("href", "data:application/txt," + encoded)
197
- download.setAttribute("download", "result.txt")
198
- download.textContent = "Output truncated. Click here to download full result."
199
-
200
- line.insertAdjacentElement("afterend", download)
201
- } else {
202
- result.textContent = json.result
203
- }
204
- }
205
-
206
- line.appendChild(result)
181
+ handleSuccessfulCommand(evt, line, JSON.parse(res))
207
182
  } else {
208
183
  console.log("Error: ", res, req);
209
184
  }
210
- evt.finish()
211
185
  }
212
186
  })
213
187
  })
214
188
  }
189
+
190
+ function handleSuccessfulCommand(evt, line, json) {
191
+ if (json.error) {
192
+ addLineResult(line, json.error, "cmd-error")
193
+ } else if (json.status != "started") {
194
+ addLineResult(line, json.result, json.status == "failed" ? "cmd-error" : "")
195
+ } else {
196
+ return setTimeout(function() { pollIteration(evt, line, json.results_endpoint) }, 2000)
197
+ }
198
+
199
+ evt.finish()
200
+ }
201
+
202
+ function addLineResult(line, text, result_class) {
203
+ line.querySelector(".result").remove()
204
+
205
+ if (!text || /^[\s\n]*$/.test(text)) { return }
206
+
207
+ var result = document.createElement("div")
208
+ result.classList.add("result")
209
+ if (result_class) { result.classList.add(result_class) }
210
+
211
+ var truncate = 2000
212
+ if (text.length > truncate-3) {
213
+ result.textContent = text.slice(0, truncate-3) + "..."
214
+ var encoded = encodeURIComponent(text)
215
+
216
+ var download = document.createElement("a")
217
+ download.classList.add("cmd-truncated-download")
218
+ download.setAttribute("href", "data:application/txt," + encoded)
219
+ download.setAttribute("download", "result.txt")
220
+ download.textContent = "Output truncated. Click here to download full result."
221
+
222
+ line.insertAdjacentElement("afterend", download)
223
+ } else {
224
+ result.textContent = text
225
+ }
226
+
227
+ line.appendChild(result)
228
+ }
229
+
230
+ function pollIteration(evt, line, endpoint) {
231
+ var client = new HttpClient()
232
+ client.get(endpoint, {
233
+ headers: {
234
+ "Content-Type": "application/json",
235
+ "X-CSRF-Token": $.rails.csrfToken()
236
+ },
237
+ done: function(res, status, req) {
238
+ if (status == 200) {
239
+ var json = JSON.parse(res)
240
+ if (json.status == "started") {
241
+ setTimeout(function() { pollIteration(evt, line, endpoint) }, 2000)
242
+ } else {
243
+ addLineResult(line, json.result, json.status == "failed" ? "cmd-error" : "")
244
+ evt.finish()
245
+ }
246
+ } else {
247
+ console.log("Error: ", res, req);
248
+ evt.finish()
249
+ }
250
+ }
251
+ })
252
+ }
215
253
  }
216
254
  })
@@ -35,3 +35,20 @@
35
35
  background: lightgrey;
36
36
  }
37
37
  }
38
+
39
+ .cmd-pagination {
40
+ text-align: center;
41
+ margin-top: 10px;
42
+
43
+ .cmd-pagination-link {
44
+ text-decoration: none;
45
+
46
+ &:hover {
47
+ text-decoration: underline;
48
+ }
49
+
50
+ &.current-page {
51
+ font-weight: bold;
52
+ }
53
+ }
54
+ }
@@ -75,4 +75,7 @@
75
75
  font-size: 12px;
76
76
  color: grey;
77
77
  }
78
+ &.cmd-past-iterations tbody tr:nth-child(even) {
79
+ background: whitesmoke;
80
+ }
78
81
  }
@@ -9,6 +9,16 @@ class ::CommandProposal::IterationsController < ::CommandProposal::EngineControl
9
9
 
10
10
  layout "application"
11
11
 
12
+ def show
13
+ @iteration = ::CommandProposal::Iteration.find(params[:id])
14
+
15
+ render json: {
16
+ results_endpoint: cmd_path(@iteration),
17
+ result: @iteration.result,
18
+ status: @iteration.status
19
+ }
20
+ end
21
+
12
22
  def create
13
23
  return error!("You do not have permission to run commands.") unless can_command?
14
24
 
@@ -17,27 +27,32 @@ class ::CommandProposal::IterationsController < ::CommandProposal::EngineControl
17
27
  return error!("Can only run commands on type: :console") unless @task.console?
18
28
  return error!("Session has not been approved.") unless has_approval?(@task)
19
29
 
20
- if @task.iterations.many?
21
- runner = ::CommandProposal.sessions["task:#{@task.id}"]
22
- elsif @task.iterations.one?
30
+ if @task.iterations.one?
23
31
  # Track console details in first iteration
24
32
  @task.first_iteration.update(started_at: Time.current, status: :started)
25
- runner = ::CommandProposal::Services::Runner.new
26
- ::CommandProposal.sessions["task:#{@task.id}"] = runner
27
33
  end
28
34
 
29
- return error!("Session has expired. Please start a new session.") if runner.nil?
30
-
31
35
  @task.user = command_user # Separate from update to ensure it's set first
32
36
  @task.update(code: params[:code]) # Creates a new iteration
33
37
  @iteration = @task.current_iteration
34
38
  @iteration.update(status: :approved) # Task was already approved, and this is line-by-line
35
39
 
36
- # in-sync
37
- runner.execute(@iteration)
40
+ # async, but wait for the job to finish
41
+ ::CommandProposal::CommandRunnerJob.perform_later(@iteration.id, "task:#{@task.id}")
42
+
43
+ max_wait_seconds = 3
44
+ loop do
45
+ break unless max_wait_seconds.positive?
46
+
47
+ max_wait_seconds -= sleep 0.2
48
+
49
+ break if @iteration.reload.complete?
50
+ end
38
51
 
39
52
  render json: {
40
- result: @iteration.result
53
+ results_endpoint: cmd_path(@iteration),
54
+ result: @iteration.result,
55
+ status: @iteration.status
41
56
  }
42
57
  end
43
58
 
@@ -17,7 +17,8 @@ class ::CommandProposal::TasksController < ::CommandProposal::EngineController
17
17
  @tasks = ::CommandProposal::Task.includes(:iterations)
18
18
  @tasks = @tasks.order(Arel.sql("COALESCE(command_proposal_tasks.last_executed_at, command_proposal_tasks.created_at) DESC"))
19
19
  @tasks = @tasks.search(params[:search]) if params[:search].present?
20
- @tasks = @tasks.where(session_type: params[:filter]) if params[:filter].present?
20
+ @tasks = @tasks.by_session(params[:filter])
21
+ @tasks = @tasks.cmd_page(params[:page])
21
22
  end
22
23
 
23
24
  def show
@@ -37,7 +38,8 @@ class ::CommandProposal::TasksController < ::CommandProposal::EngineController
37
38
  end
38
39
 
39
40
  def new
40
- @task = ::CommandProposal::Task.new(session_type: params[:session_type])
41
+ @task = ::CommandProposal::Task.new
42
+ @task.session_type = params[:session_type] if params[:session_type].in?(::CommandProposal::Task.session_types)
41
43
 
42
44
  render "form"
43
45
  end
@@ -51,12 +53,12 @@ class ::CommandProposal::TasksController < ::CommandProposal::EngineController
51
53
  def create
52
54
  @task = ::CommandProposal::Task.new(task_params.except(:code))
53
55
  @task.user = command_user
54
- @task.skip_approval = true unless approval_required?
56
+ @task.skip_approval = true unless approval_required?(@task.session_type)
55
57
 
56
58
  # Cannot create the iteration until the task is created, so save then update
57
59
  if @task.save && @task.update(task_params)
58
60
  if @task.console?
59
- @task.iterations.create(requester: command_user) # Blank iteration to track approval
61
+ @task.code = nil # Creates a blank iteration to track approval
60
62
  redirect_to cmd_path(@task)
61
63
  else
62
64
  redirect_to cmd_path(:edit, @task)
@@ -70,7 +72,7 @@ class ::CommandProposal::TasksController < ::CommandProposal::EngineController
70
72
  def update
71
73
  @task = ::CommandProposal::Task.find_by!(friendly_id: params[:id])
72
74
  @task.user = command_user
73
- @task.skip_approval = true unless approval_required?
75
+ @task.skip_approval = true unless approval_required?(@task.session_type)
74
76
 
75
77
  if @task.update(task_params)
76
78
  redirect_to cmd_path(@task)
@@ -22,6 +22,15 @@ module ::CommandProposal::ParamsHelper
22
22
  end
23
23
  end
24
24
 
25
+ def current_path(new_params={})
26
+ if @task.present?
27
+ new_params.merge!(iteration: @iteration.id) if @iteration.present? && !@iteration.primary_iteration?
28
+ cmd_path(@task, new_params)
29
+ else
30
+ cmd_path(:tasks, current_params(new_params))
31
+ end
32
+ end
33
+
25
34
  def truthy?(val)
26
35
  val.to_s.downcase.in?(["true", "t", "1"])
27
36
  end
@@ -60,4 +69,38 @@ module ::CommandProposal::ParamsHelper
60
69
  return "< 1s" if str_parts.none?
61
70
  str_parts.join(" ")
62
71
  end
72
+
73
+ def div(opts={}, &block)
74
+ "<div #{opts.map { |k, v| "#{k}=\"#{v}\"" }.join(" ")}>#{yield}</div>".html_safe
75
+ end
76
+
77
+ def command_paginate(paged_collection)
78
+ collection = paged_collection.unscope(:limit, :offset)
79
+
80
+ per = ::CommandProposal::PAGINATION_PER
81
+ total_pages = (collection.count / per.to_f).ceil
82
+ current_page = params[:page].presence&.to_i || 1
83
+
84
+ return if total_pages <= 1
85
+
86
+ div(class: "cmd-pagination") do
87
+ links = []
88
+ links << ["<<", { page: 1 }] if current_page > 1
89
+ links << ["<", { page: current_page - 1 }] if current_page > 1
90
+
91
+ (current_page-2..current_page+2).each do |page_window|
92
+ next if page_window < 1
93
+ next if page_window > total_pages
94
+
95
+ links << [page_window, { page: page_window }]
96
+ end
97
+
98
+ links << [">", page: current_page + 1] if current_page < total_pages
99
+ links << [">>", page: total_pages] if current_page < total_pages
100
+
101
+ links.map do |link_text, link_params|
102
+ "<a class=\"cmd-pagination-link #{'current-page' if link_params[:page] == current_page}\" href=\"#{current_path(link_params)}\">#{link_text}</a>"
103
+ end.join("\n")
104
+ end
105
+ end
63
106
  end
@@ -9,7 +9,7 @@ module CommandProposal
9
9
 
10
10
  def can_approve?(iteration)
11
11
  return false unless permitted_to_use?
12
- return true unless approval_required?
12
+ return true unless approval_required?(iteration.task.session_type)
13
13
  return if iteration.nil?
14
14
 
15
15
  command_user.try("#{cmd_config.role_scope}?") && !current_is_author?(iteration)
@@ -17,13 +17,18 @@ module CommandProposal
17
17
 
18
18
  def has_approval?(task)
19
19
  return false unless permitted_to_use?
20
- return true unless approval_required?
20
+ return true unless approval_required?(task.session_type)
21
21
 
22
22
  task&.approved?
23
23
  end
24
24
 
25
- def approval_required?
26
- cmd_config.approval_required?
25
+ def approval_required?(task_type=nil)
26
+ return false unless cmd_config.approval_required?
27
+ return true if task_type.blank?
28
+
29
+ skips = cmd_config.skip_approval_for_types.presence || []
30
+
31
+ Array.wrap(skips).map(&:to_sym).exclude?(task_type.to_sym)
27
32
  end
28
33
 
29
34
  def current_is_author?(iteration)
@@ -2,10 +2,26 @@ module CommandProposal
2
2
  class CommandRunnerJob < ApplicationJob
3
3
  queue_as :default
4
4
 
5
- def perform(iteration_id)
5
+ def perform(iteration_id, runner_key=nil)
6
6
  iteration = ::CommandProposal::Iteration.find(iteration_id)
7
+ runner = ::CommandProposal.sessions[runner_key] if runner_key.present?
7
8
 
8
- ::CommandProposal::Services::Runner.new.execute(iteration)
9
+ if runner_key.present? && runner.blank?
10
+ if iteration.task.console? && iteration.task.iterations.count > 2 # 1 for init, and the 1 for current running code
11
+ return ::CommandProposal::Services::Runner.new.quick_fail(
12
+ iteration,
13
+ "Session has expired. Please start a new session."
14
+ )
15
+ else
16
+ runner = ::CommandProposal::Services::Runner.new
17
+ end
18
+
19
+ ::CommandProposal.sessions[runner_key] = runner if runner_key.present?
20
+ else
21
+ runner ||= ::CommandProposal::Services::Runner.new
22
+ end
23
+
24
+ runner.execute(iteration)
9
25
  end
10
26
  end
11
27
  end
@@ -40,6 +40,12 @@ class ::CommandProposal::Iteration < ApplicationRecord
40
40
  terminated: 7, # Closed via server restart
41
41
  }
42
42
 
43
+ scope :cmd_page, ->(page=nil) {
44
+ page = page.presence&.to_i || 1
45
+ per = ::CommandProposal::PAGINATION_PER
46
+ limit(per).offset(per * (page - 1))
47
+ }
48
+
43
49
  delegate :name, to: :task
44
50
  delegate :description, to: :task
45
51
  delegate :session_type, to: :task
@@ -55,6 +61,10 @@ class ::CommandProposal::Iteration < ApplicationRecord
55
61
  ::CommandProposal::Task.module.where(friendly_id: bring_str.scan(/\s+\:(\w+),?/).flatten)
56
62
  end
57
63
 
64
+ def primary_iteration?
65
+ task.primary_iteration == self
66
+ end
67
+
58
68
  def complete?
59
69
  success? || failed? || cancelled? || terminated?
60
70
  end
@@ -15,12 +15,24 @@ class ::CommandProposal::Task < ApplicationRecord
15
15
  scope :search, ->(text) {
16
16
  where("name ILIKE :q OR description ILIKE :q", q: "%#{text}%")
17
17
  }
18
+ scope :by_session, ->(filter) {
19
+ if filter.present?
20
+ where(session_type: filter) if filter.to_s.in?(session_types.keys)
21
+ else
22
+ where(session_type: :function)
23
+ end
24
+ }
25
+ scope :cmd_page, ->(page=nil) {
26
+ page = page.presence&.to_i || 1
27
+ per = ::CommandProposal::PAGINATION_PER
28
+ limit(per).offset(per * (page - 1))
29
+ }
18
30
 
19
31
  enum session_type: {
20
- # Task will have multiple iterations that are all essentially the same just with code changes
21
- task: 0,
22
32
  # Function iterations are much like tasks
23
33
  function: 1,
34
+ # Task will have multiple iterations that are all essentially the same just with code changes
35
+ task: 0,
24
36
  # Console iterations are actually line by line, so order matters
25
37
  console: 2,
26
38
  # Modules are included in tasks and not run independently
@@ -1,18 +1,18 @@
1
1
  <% if lines.none? && !(skip_empty ||= false) -%><div class="line"></div><% end
2
2
  -%><% lines.each do |iteration| -%>
3
3
  <div class="line"><%= iteration.code
4
- -%><div class="result"><%=
4
+ -%><div class="result <%= 'cmd-error' if iteration.failed? %>"><%=
5
5
  truncate = ::CommandProposal::Iteration::TRUNCATE_COUNT
6
6
  if iteration.result.present?
7
7
  iteration.result.truncate(truncate)
8
- elsif iteration.completed?
8
+ elsif iteration.complete?
9
9
  "Error: No response"
10
10
  else
11
11
  content_tag :i, nil, class: "fa fa-circle-o-notch fa-spin cmd-icon-grey"
12
12
  end
13
13
  %></div
14
14
  ></div><%=
15
- if iteration.result.length > truncate
15
+ if iteration.result&.length.to_i > truncate
16
16
  link_to("Output truncated. Click here to download full result.", "data:application/txt,#{ERB::Util.url_encode(iteration.result)}", class: "cmd-truncated-download", download: "result.txt")
17
17
  end
18
18
  %><% end -%>
@@ -1,27 +1,38 @@
1
- <% if @task.iterations.many? %>
2
- <table class="cmd-table">
1
+ <% if @task.iterations.any? %>
2
+ <table class="cmd-table cmd-past-iterations">
3
3
  <thead>
4
4
  <th>Timestamp / Link</th>
5
5
  <th>Status</th>
6
+ <% if @iteration&.params.present? %>
7
+ <th>Params</th>
8
+ <% end %>
9
+ <th>Result</th>
6
10
  <!-- <th># Comments</th> -->
7
11
  <!-- <th>Diff</th> -->
8
12
  </thead>
9
13
  <tbody>
10
- <% primary_iteration = @task.primary_iteration %>
11
- <% @task.iterations.where.not(id: @iteration&.id).order(created_at: :desc).each do |iteration| %>
14
+ <% paginated_iterations = @task.iterations.cmd_page(params[:page]) %>
15
+ <% paginated_iterations.order(created_at: :desc).each do |iteration| %>
12
16
  <tr>
13
17
  <td>
14
- <% if iteration.id == primary_iteration&.id %>
15
- <%= link_to iteration.created_at.strftime("%b %-d, %Y at %H:%M"), cmd_path(@task) %>
16
- <% else %>
17
- <%= link_to iteration.created_at.strftime("%b %-d, %Y at %H:%M"), cmd_path(@task, iteration: iteration.id) %>
18
- <% end %>
18
+ <%= ">" if iteration == @iteration %>
19
+ <%= link_to iteration.created_at.strftime("%b %-d, %Y at %H:%M"), cmd_path(@task, iteration: iteration.id) %>
19
20
  </td>
20
21
  <td><%= iteration.status.capitalize %></td>
22
+ <% if @iteration&.params.present? %>
23
+ <td>
24
+ <% iteration&.args.each do |arg_k, arg_v| %>
25
+ <span class=cmd-arg""><%= arg_k %>=<%= arg_v.to_s.truncate(50) %></span>
26
+ <% end %>
27
+ </td>
28
+ <% end %>
29
+ <td><%= iteration.result.to_s.truncate(200) %></td>
21
30
  <!-- <td><%#= iteration.comments.count %></td> -->
22
31
  <!-- <td><%#= link_to "Diff", cmd_path(@task, iteration: @iteration.id, diff: iteration.id) %></td> -->
23
32
  </tr>
24
33
  <% end %>
25
34
  </tbody>
26
35
  </table>
36
+
37
+ <%= command_paginate paginated_iterations %>
27
38
  <% end %>
@@ -1,9 +1,11 @@
1
1
  <div class="cmd-wrapper">
2
- <%= link_to "New #{params[:filter].presence&.capitalize || 'Command'}", cmd_path(:new, :task, session_type: params[:filter] || :task) %> <br>
2
+ <% filter_name = params[:filter].presence&.capitalize %>
3
+ <% filter_name = filter_name.blank? || filter_name == "All" ? "Command" : filter_name %>
4
+ <%= link_to "New #{filter_name}", cmd_path(:new, :task, session_type: params[:filter] || :task) %> <br>
3
5
  <br>
4
- <%= link_to "All", cmd_path(:tasks, current_params.except(:filter)), class: "cmd-tab #{:active unless params.key?(:filter)}"
6
+ <%= link_to "All", toggled_param(filter: :all), class: "cmd-tab #{:active if params[:filter] == "all"}"
5
7
  %><% ::CommandProposal::Task.session_types.each_with_index do |(session_type, _session_enum), idx| %><%=
6
- selected = params[:filter] == session_type.to_s
8
+ selected = params[:filter] == session_type.to_s || (!params.key?(:filter) && session_type == "function")
7
9
  # Offset closing RB tags to fix spacing issues
8
10
  link_to session_type.capitalize, toggled_param(filter: session_type), class: "cmd-tab #{:active if selected}"
9
11
  %><% end %>
@@ -42,4 +44,6 @@
42
44
  <% end %>
43
45
  <% end %>
44
46
  </div>
47
+
48
+ <%= command_paginate @tasks %>
45
49
  </div>
@@ -13,6 +13,7 @@ module CommandProposal
13
13
  :approval_callback,
14
14
  :success_callback,
15
15
  :failed_callback,
16
+ :skip_approval_for_types,
16
17
  )
17
18
 
18
19
  def initialize
@@ -30,6 +31,7 @@ module CommandProposal
30
31
  @approval_callback = nil
31
32
  @success_callback = nil
32
33
  @failed_callback = nil
34
+ @skip_approval_for_types = nil
33
35
  end
34
36
 
35
37
  def user_class
@@ -51,6 +51,19 @@ module CommandProposal
51
51
  proposal
52
52
  end
53
53
 
54
+ def quick_fail(iteration, msg)
55
+ @iteration = iteration
56
+ prepare
57
+
58
+ @iteration.status = :failed
59
+ @iteration.result = msg
60
+
61
+ complete
62
+ proposal = ::CommandProposal::Service::ProposalPresenter.new(@iteration)
63
+ @iteration = nil
64
+ proposal
65
+ end
66
+
54
67
  def quick_run(friendly_id)
55
68
  task = ::CommandProposal::Task.module.find_by!(friendly_id: friendly_id)
56
69
  iteration = task&.primary_iteration
@@ -76,7 +89,11 @@ module CommandProposal
76
89
 
77
90
  def run
78
91
  begin
79
- @session.eval("#{bring_function};params = #{@iteration.args || {}}.with_indifferent_access")
92
+ params_str = ""
93
+ unless @iteration.task.console? # Don't bring params into the console
94
+ params_str = "params = #{@iteration.args || {}}.with_indifferent_access"
95
+ end
96
+ @session.eval("#{bring_function};#{params_str}")
80
97
  rescue Exception => e # rubocop:disable Lint/RescueException - Yes, rescue full Exception so that we can catch typos in evals as well
81
98
  return @iteration.result = results_from_exception(e)
82
99
  end
@@ -88,7 +105,7 @@ module CommandProposal
88
105
 
89
106
  running_thread = Thread.new do
90
107
  begin
91
- # Run bring functions in here so we can capture any string outputs
108
+ # Run `bring` functions in here so we can capture any string outputs
92
109
  # OR! Run the full runner and instead of saving to an iteration, return the string for prepending here
93
110
  result = @session.eval("_ = (#{@iteration.code})").inspect # rubocop:disable Security/Eval - Eval is scary, but in this case it's exactly what we need.
94
111
  result = nil unless @iteration.task.console? # Only store final result for consoles
@@ -1,3 +1,3 @@
1
1
  module CommandProposal
2
- VERSION = "1.0.12"
2
+ VERSION = "1.0.15"
3
3
  end
@@ -6,6 +6,8 @@ require "command_proposal/services/shut_down"
6
6
 
7
7
  module CommandProposal
8
8
  class Error < StandardError; end
9
+ PAGINATION_PER = 10
10
+
9
11
  def self.sessions
10
12
  @sessions ||= {}
11
13
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: command_proposal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.12
4
+ version: 1.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rocco Nicholls
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-26 00:00:00.000000000 Z
11
+ date: 2022-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails