foreman_remote_execution 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.babelrc +9 -0
- data/.eslintignore +3 -0
- data/.eslintrc +49 -0
- data/.gitignore +1 -0
- data/.hound.yml +5 -0
- data/.rubocop.yml +4 -1
- data/.rubocop_todo.yml +63 -35
- data/.travis.yml +6 -0
- data/app/assets/javascripts/foreman_remote_execution/template_invocation.js +1 -1
- data/app/assets/stylesheets/foreman_remote_execution/job_invocations.css.scss +0 -14
- data/app/controllers/job_invocations_controller.rb +18 -0
- data/app/helpers/job_invocations_chart_helper.rb +77 -0
- data/app/helpers/job_invocations_helper.rb +79 -0
- data/app/helpers/remote_execution_helper.rb +10 -50
- data/app/models/job_invocation.rb +4 -0
- data/app/models/remote_execution_provider.rb +4 -0
- data/app/views/job_invocations/_card_results.html.erb +11 -0
- data/app/views/job_invocations/_card_schedule.html.erb +32 -0
- data/app/views/job_invocations/_card_target_hosts.html.erb +33 -0
- data/app/views/job_invocations/_card_user_input.html.erb +16 -0
- data/app/views/job_invocations/_tab_hosts.html.erb +1 -1
- data/app/views/job_invocations/_tab_overview.html.erb +25 -55
- data/app/views/job_invocations/_tab_preview_templates.html.erb +20 -0
- data/app/views/job_invocations/_user_input.html.erb +21 -0
- data/app/views/job_invocations/show.html.erb +14 -8
- data/app/views/job_invocations/show.js.erb +3 -6
- data/config/routes.rb +1 -0
- data/lib/foreman_remote_execution/engine.rb +2 -2
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/package.json +62 -0
- data/test/unit/job_invocation_test.rb +15 -0
- data/webpack/index.js +29 -0
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.js +34 -0
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.test.js +36 -0
- data/webpack/react_app/components/jobInvocations/index.js +58 -0
- data/webpack/react_app/redux/actions/jobInvocations/index.js +74 -0
- data/webpack/react_app/redux/consts.js +6 -0
- data/webpack/react_app/redux/reducers/index.js +6 -0
- data/webpack/react_app/redux/reducers/jobInvocations/index.fixtures.js +78 -0
- data/webpack/react_app/redux/reducers/jobInvocations/index.js +32 -0
- data/webpack/react_app/redux/reducers/jobInvocations/index.test.js +37 -0
- data/webpack/test_setup.js +11 -0
- metadata +26 -2
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal:true
|
2
|
+
|
3
|
+
module JobInvocationsHelper
|
4
|
+
def minicard(icon, number, text)
|
5
|
+
content_tag(:div, :class => 'card-pf card-pf-accented
|
6
|
+
card-pf-aggregate-status card-pf-aggregate-status-mini') do
|
7
|
+
content_tag(:h2, :class => 'card-pf-title', :style => 'line-height: 1.1') do
|
8
|
+
icon_text(icon, '', :kind => 'pficon') +
|
9
|
+
content_tag(:span, number, :class =>'card-pf-aggregate-status-count') +
|
10
|
+
text
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def job_invocation_task_buttons(task)
|
16
|
+
job_invocation = task.task_groups.find { |group| group.class == JobInvocationTaskGroup }.job_invocation
|
17
|
+
buttons = []
|
18
|
+
if authorized_for(hash_for_new_job_invocation_path)
|
19
|
+
buttons << link_to(_('Rerun'), rerun_job_invocation_path(:id => job_invocation.id),
|
20
|
+
:class => 'btn btn-default',
|
21
|
+
:title => _('Rerun the job'))
|
22
|
+
end
|
23
|
+
if authorized_for(hash_for_new_job_invocation_path)
|
24
|
+
buttons << link_to(_('Rerun failed'), rerun_job_invocation_path(:id => job_invocation.id, :failed_only => 1),
|
25
|
+
:class => 'btn btn-default',
|
26
|
+
:disabled => task.sub_tasks.none? { |sub_task| task_failed?(sub_task) },
|
27
|
+
:title => _('Rerun on failed hosts'))
|
28
|
+
end
|
29
|
+
if authorized_for(:permission => :view_foreman_tasks, :auth_object => task)
|
30
|
+
buttons << link_to(_('Job Task'), foreman_tasks_task_path(task),
|
31
|
+
:class => 'btn btn-default',
|
32
|
+
:title => _('See the last task details'))
|
33
|
+
end
|
34
|
+
if authorized_for(:permission => :edit_foreman_tasks, :auth_object => task)
|
35
|
+
buttons << link_to(_('Cancel Job'), cancel_foreman_tasks_task_path(task),
|
36
|
+
:class => 'btn btn-danger',
|
37
|
+
:title => _('Try to cancel the job'),
|
38
|
+
:disabled => !task.cancellable?,
|
39
|
+
:method => :post)
|
40
|
+
end
|
41
|
+
buttons
|
42
|
+
end
|
43
|
+
|
44
|
+
def job_invocations_buttons
|
45
|
+
[
|
46
|
+
documentation_button_rex('3.2ExecutingaJob'),
|
47
|
+
display_link_if_authorized(_('Run Job'), hash_for_new_job_invocation_path)
|
48
|
+
]
|
49
|
+
end
|
50
|
+
|
51
|
+
def template_name_and_provider_link(template)
|
52
|
+
template_name = content_tag(:strong, template.name)
|
53
|
+
provider = template.provider.humanized_name
|
54
|
+
link_content = template_name + ' - ' + provider + ' ' +
|
55
|
+
icon_text('edit', '', :kind => 'pficon')
|
56
|
+
link_to_if_authorized(link_content,
|
57
|
+
hash_for_edit_job_template_path(:id => template.id))
|
58
|
+
end
|
59
|
+
|
60
|
+
def preview_hosts(template_invocation)
|
61
|
+
hosts = template_invocation.targeting.hosts.take(20)
|
62
|
+
hosts.map do |host|
|
63
|
+
collapsed_preview(host) +
|
64
|
+
render(:partial => 'job_invocations/user_input',
|
65
|
+
:locals => { :template_invocation => template_invocation,
|
66
|
+
:target => host })
|
67
|
+
end.reduce(:+)
|
68
|
+
end
|
69
|
+
|
70
|
+
def collapsed_preview(target)
|
71
|
+
title = target.try(:name) || 'N/A'
|
72
|
+
content_tag(:h5,
|
73
|
+
:class => "expander collapsed out",
|
74
|
+
:data => { :toggle => 'collapse',
|
75
|
+
:target => "#preview_#{target.id}" }) do
|
76
|
+
content_tag(:span, '', :class => 'caret') + title
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -8,47 +8,10 @@ module RemoteExecutionHelper
|
|
8
8
|
TemplateInput::TYPES.map { |key, name| [ _(name), key ] }
|
9
9
|
end
|
10
10
|
|
11
|
-
def job_invocation_chart(invocation)
|
12
|
-
options = { :class => 'statistics-pie small', :expandable => true, :border => 0, :show_title => true }
|
13
|
-
|
14
|
-
if invocation.task
|
15
|
-
# Request precise subtask counts only if the task is stopped
|
16
|
-
report = invocation.progress_report
|
17
|
-
flot_pie_chart('status', job_invocation_status(invocation, report[:progress]),
|
18
|
-
[{:label => _('Success'), :data => report[:success], :color => '#5CB85C'},
|
19
|
-
{:label => _('Failed'), :data => report[:failed], :color => '#D9534F'},
|
20
|
-
{:label => _('Pending'), :data => report[:pending], :color => '#DEDEDE'},
|
21
|
-
{:label => _('Cancelled'), :data => report[:cancelled], :color => '#B7312D'}],
|
22
|
-
options)
|
23
|
-
else
|
24
|
-
content_tag(:h4, job_invocation_status(invocation))
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
11
|
def job_hosts_authorizer
|
29
12
|
@job_hosts_authorizer ||= Authorizer.new(User.current, :collection => @hosts)
|
30
13
|
end
|
31
14
|
|
32
|
-
def job_invocation_status(invocation, percent = nil, verbose = true)
|
33
|
-
case invocation.status
|
34
|
-
when HostStatus::ExecutionStatus::QUEUED
|
35
|
-
if verbose && invocation.task
|
36
|
-
_('queued to start executing in %{time}') % {:time => time_ago_in_words(invocation.task.start_at) }
|
37
|
-
else
|
38
|
-
_('queued')
|
39
|
-
end
|
40
|
-
when HostStatus::ExecutionStatus::RUNNING
|
41
|
-
percent ||= invocation.progress_report[:progress]
|
42
|
-
_('running %{percent}%%') % {:percent => percent}
|
43
|
-
when HostStatus::ExecutionStatus::OK
|
44
|
-
_('succeeded')
|
45
|
-
when HostStatus::ExecutionStatus::ERROR
|
46
|
-
_('failed')
|
47
|
-
else
|
48
|
-
_('unknown status')
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
15
|
def host_counter(label, count)
|
53
16
|
content_tag(:div, :class => 'host_counter') do
|
54
17
|
content_tag(:div, label, :class => 'header') + content_tag(:div, count.to_s, :class => 'count')
|
@@ -77,9 +40,17 @@ module RemoteExecutionHelper
|
|
77
40
|
end
|
78
41
|
|
79
42
|
def template_invocation_actions(task, host, job_invocation, template_invocation)
|
43
|
+
host_task = template_invocation.try(:run_host_job_task)
|
80
44
|
[
|
81
45
|
display_link_if_authorized(_('Host detail'), hash_for_host_path(host).merge(:auth_object => host, :permission => :view_hosts, :authorizer => job_hosts_authorizer)),
|
82
46
|
display_link_if_authorized(_('Rerun on %s') % host.name, hash_for_rerun_job_invocation_path(:id => job_invocation, :host_ids => [ host.id ], :authorizer => job_hosts_authorizer)),
|
47
|
+
if host_task.present?
|
48
|
+
display_link_if_authorized(
|
49
|
+
_('Host task'),
|
50
|
+
hash_for_foreman_tasks_task_path(host_task)
|
51
|
+
.merge(:auth_object => host_task, :permission => :view_foreman_tasks)
|
52
|
+
)
|
53
|
+
end
|
83
54
|
]
|
84
55
|
end
|
85
56
|
|
@@ -99,7 +70,6 @@ module RemoteExecutionHelper
|
|
99
70
|
job_invocation = task.task_groups.find { |group| group.class == JobInvocationTaskGroup }.job_invocation
|
100
71
|
task_authorizer = Authorizer.new(User.current, :collection => [task])
|
101
72
|
buttons = []
|
102
|
-
buttons << link_to(_('Refresh'), {}, :class => 'btn btn-default', :title => _('Refresh this page'))
|
103
73
|
if authorized_for(hash_for_new_job_invocation_path)
|
104
74
|
buttons << link_to(_('Rerun'), rerun_job_invocation_path(:id => job_invocation.id),
|
105
75
|
:class => 'btn btn-default',
|
@@ -130,6 +100,7 @@ module RemoteExecutionHelper
|
|
130
100
|
end
|
131
101
|
return buttons
|
132
102
|
end
|
103
|
+
|
133
104
|
# rubocop:enable Metrics/AbcSize
|
134
105
|
|
135
106
|
def template_invocation_task_buttons(task, invocation)
|
@@ -151,7 +122,7 @@ module RemoteExecutionHelper
|
|
151
122
|
:disabled => !task.cancellable?,
|
152
123
|
:method => :post)
|
153
124
|
end
|
154
|
-
|
125
|
+
buttons
|
155
126
|
end
|
156
127
|
|
157
128
|
def link_to_invocation_task_if_authorized(invocation)
|
@@ -200,17 +171,6 @@ module RemoteExecutionHelper
|
|
200
171
|
end
|
201
172
|
end
|
202
173
|
|
203
|
-
def job_invocation_active_tab(tab, params)
|
204
|
-
active = 'active'
|
205
|
-
inactive = ''
|
206
|
-
hosts_tab_active = params[:page].present? || params[:search].present? || params[:order].present?
|
207
|
-
if hosts_tab_active
|
208
|
-
tab == :hosts ? active : inactive
|
209
|
-
else
|
210
|
-
tab == :overview ? active : inactive
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
174
|
def time_in_words_span(time)
|
215
175
|
if time.nil?
|
216
176
|
_('N/A')
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<div id="job-invocation-chart">
|
2
|
+
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
3
|
+
<h2 style="height: 18px;" class="card-pf-title">
|
4
|
+
<a href="#"><%= _('Results') %></a>
|
5
|
+
</h2>
|
6
|
+
<div class="card-pf-body">
|
7
|
+
<div id='status_chart'>
|
8
|
+
</div>
|
9
|
+
</div>
|
10
|
+
</div>
|
11
|
+
</div>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<% if job_invocation.concurrency_level || job_invocation.time_span ||
|
2
|
+
(job_invocation.task && (job_invocation.task.delayed? || job_invocation.task.recurring?)) ||
|
3
|
+
job_invocation.execution_timeout_interval.present? %>
|
4
|
+
<div class="card-pf card-pf-accented">
|
5
|
+
<div class="card-pf-title">
|
6
|
+
<h2 style="height: 18px;" class="card-pf-title">
|
7
|
+
<%= _('Schedule') %>
|
8
|
+
</h2>
|
9
|
+
</div>
|
10
|
+
<div class="card-pf-body">
|
11
|
+
<p>
|
12
|
+
<ul>
|
13
|
+
<% if job_invocation.concurrency_level %>
|
14
|
+
<li><b><%= _("Concurrency level limited to") %></b>: <%= job_invocation.concurrency_level %> <%= _('tasks at a time') %><br></li>
|
15
|
+
<% end %>
|
16
|
+
<% if job_invocation.time_span %>
|
17
|
+
<li><b><%= _("Set to distribute over") %></b>: <%= job_invocation.time_span %> <%= _('seconds') %><br></li>
|
18
|
+
<% end %>
|
19
|
+
<% if job_invocation.start_before %>
|
20
|
+
<li><b><%= _("Scheduled to start before") %></b>: <%= job_invocation.start_before %><br></li>
|
21
|
+
<% end %>
|
22
|
+
<% if job_invocation.task && (job_invocation.task.delayed? || job_invocation.task.recurring?) %>
|
23
|
+
<li><b><%= _("Scheduled to start at") %></b>: <%= job_invocation.task.start_at.try(:in_time_zone) %><br></li>
|
24
|
+
<% end %>
|
25
|
+
<% if job_invocation.execution_timeout_interval.present? %>
|
26
|
+
<li><b><%= _("Timeout to kill after") %></b>: <%= job_invocation.execution_timeout_interval %> <%= _('seconds') %><br></li>
|
27
|
+
<% end %>
|
28
|
+
</ul>
|
29
|
+
</p>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
<% end %>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<% template_invocations = job_invocation.pattern_template_invocations %>
|
2
|
+
<div class="card-pf card-pf-accented">
|
3
|
+
<div class="card-pf-title">
|
4
|
+
<h2 style="height: 18px;" class="card-pf-title">
|
5
|
+
<%= _('Target hosts') %>
|
6
|
+
</h2>
|
7
|
+
</div>
|
8
|
+
<div class="card-pf-body">
|
9
|
+
<p>
|
10
|
+
<% if job_invocation.bookmark.present? %>
|
11
|
+
<%= _('Bookmark') %> <%= job_invocation.bookmark.name %><br>
|
12
|
+
<% else %>
|
13
|
+
<%= _('Manual selection') %>
|
14
|
+
<% end %>
|
15
|
+
<%= _('using ') %>
|
16
|
+
<strong><%= _(Targeting::TYPES[job_invocation.targeting.targeting_type]).downcase %></strong>
|
17
|
+
<pre><%= job_invocation.targeting.search_query %></pre>
|
18
|
+
</p>
|
19
|
+
</div>
|
20
|
+
<div class='card-pf-footer'>
|
21
|
+
<p>
|
22
|
+
<%= _('Evaluated at:') %> <%= job_invocation.targeting.resolved_at %><br>
|
23
|
+
<% if template_invocations.size > 1 %>
|
24
|
+
<% template_invocations.each do |template_invocation| %>
|
25
|
+
<%= host_counter template_invocation.template.provider.humanized_name,
|
26
|
+
ForemanTasks::Task::DynflowTask.
|
27
|
+
for_action(Actions::RemoteExecution::RunHostJob).
|
28
|
+
for_resource(template_invocation).uniq.size %>
|
29
|
+
<% end %>
|
30
|
+
<% end %>
|
31
|
+
</p>
|
32
|
+
</div>
|
33
|
+
</div>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<div class="card-pf card-pf-accented">
|
2
|
+
<div class="card-pf-title">
|
3
|
+
<h2 style="height: 18px;" class="card-pf-title">
|
4
|
+
<%= _('User Inputs') %>
|
5
|
+
</h2>
|
6
|
+
</div>
|
7
|
+
<div class="card-pf-body">
|
8
|
+
<p>
|
9
|
+
<ul>
|
10
|
+
<% template_invocation.input_values.joins(:template_input).each do |input_value| %>
|
11
|
+
<li><b><%= input_value.template_input.name %></b>: <%= trunc_with_tooltip(input_value.value, 255) %></li>
|
12
|
+
<% end %>
|
13
|
+
</ul>
|
14
|
+
</p>
|
15
|
+
</div>
|
16
|
+
</div>
|
@@ -1,59 +1,29 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
<%
|
10
|
-
<%=
|
11
|
-
|
12
|
-
|
13
|
-
<pre><%= job_invocation.targeting.search_query %></pre>
|
14
|
-
|
15
|
-
<%= _('Evaluated at:') %> <%= job_invocation.targeting.resolved_at %><br>
|
16
|
-
<% if job_invocation.pattern_template_invocations.size > 1 %>
|
17
|
-
<% job_invocation.pattern_template_invocations.each do |template_invocation| %>
|
18
|
-
<%= host_counter template_invocation.template.provider.humanized_name, ForemanTasks::Task::DynflowTask.for_action(Actions::RemoteExecution::RunHostJob).for_resource(template_invocation).uniq.size %>
|
19
|
-
<% end %>
|
20
|
-
<% end %>
|
21
|
-
<%= host_counter(_('Total hosts'), job_invocation.total_hosts_count) %>
|
22
|
-
</div>
|
23
|
-
|
24
|
-
<div class="col-md-6 infoblock">
|
25
|
-
<h4><%= _('Providers and templates') %></h4>
|
26
|
-
<% job_invocation.pattern_template_invocations.each do |template_invocation| %>
|
27
|
-
<h5>
|
28
|
-
<b><%= template_invocation.template.name %></b> <%= 'through' %> <%= template_invocation.template.provider.humanized_name %>
|
29
|
-
</h5>
|
30
|
-
<% target = template_invocation.targeting.hosts.with_os.first || template_invocation.targeting.hosts.first %>
|
31
|
-
<%= _('Preview for target %s') % target.try(:name) || 'N/A' %>
|
32
|
-
|
33
|
-
<%= preview_box(template_invocation, target) %>
|
34
|
-
|
1
|
+
<% template_invocations = job_invocation.pattern_template_invocations %>
|
2
|
+
<div class='row'>
|
3
|
+
<div class="col-xs-6 col-sm-6 col-md-6">
|
4
|
+
<%= render :partial => 'card_results' %>
|
5
|
+
<%= render :partial => 'card_schedule', :locals => { :job_invocation => job_invocation } %>
|
6
|
+
</div>
|
7
|
+
<div class='col-xs-12 col-sm-6 col-md-6'>
|
8
|
+
<%= render :partial => 'card_target_hosts', :locals => { :job_invocation => job_invocation } %>
|
9
|
+
<% template_invocations.each do |template_invocation| %>
|
10
|
+
<%= minicard('user', template_invocation.effective_user || Setting[:remote_execution_effective_user],
|
11
|
+
template_invocation.template.name + ' ' + _('effective user')) %>
|
12
|
+
<%= minicard('cluster', job_invocation.total_hosts_count, _('Total hosts')) %>
|
35
13
|
<% if template_invocation.input_values.present? %>
|
36
|
-
<%=
|
37
|
-
<ul>
|
38
|
-
<% template_invocation.input_values.joins(:template_input).each do |input_value| %>
|
39
|
-
<li><b><%= input_value.template_input.name %></b>: <%= trunc_with_tooltip(input_value.value, 255) %></li>
|
40
|
-
<% end %>
|
41
|
-
</ul>
|
42
|
-
<% end %>
|
43
|
-
<% if template_invocation.effective_user %>
|
44
|
-
<b><%= _("Effective user") %></b>: <%= template_invocation.effective_user %><br>
|
45
|
-
<% end %>
|
46
|
-
<% if job_invocation.concurrency_level %>
|
47
|
-
<b><%= _("Concurrency level limited to") %></b>: <%= job_invocation.concurrency_level %> <%= _('tasks at a time') %><br>
|
48
|
-
<% end %>
|
49
|
-
<% if job_invocation.time_span %>
|
50
|
-
<b><%= _("Set to distribute over") %></b>: <%= job_invocation.time_span %> <%= _('seconds') %><br>
|
51
|
-
<% end %>
|
52
|
-
<% if job_invocation.task && (job_invocation.task.delayed? || job_invocation.task.recurring?) %>
|
53
|
-
<b><%= _("Scheduled to start at") %></b>: <%= job_invocation.task.start_at.try(:in_time_zone) %><br>
|
54
|
-
<% end %>
|
55
|
-
<% unless job_invocation.execution_timeout_interval.nil? %>
|
56
|
-
<b><%= _("Timeout to kill after") %></b>: <%= job_invocation.execution_timeout_interval %> <%= _('seconds') %><br>
|
14
|
+
<%= render :partial => 'card_user_input', :locals => { :template_invocation => template_invocation } %>
|
57
15
|
<% end %>
|
58
16
|
<% end %>
|
17
|
+
</div>
|
59
18
|
</div>
|
19
|
+
<hr/>
|
20
|
+
<% if job_invocation.resolved? %>
|
21
|
+
<div id="hosts" data-refresh_required="<%= job_invocation.resolved? ? '' : 'true' %>">
|
22
|
+
<%= render :partial => 'tab_hosts', :locals => { :job_invocation => job_invocation, :hosts => hosts } %>
|
23
|
+
</div>
|
24
|
+
<% else %>
|
25
|
+
<div class="alert alert-warning">
|
26
|
+
<%= _("The dynamic query '#{job_invocation.targeting.search_query}' was not resolved yet. The list of hosts to which it would resolve now can be seen") %>
|
27
|
+
<%= link_to('here.', hosts_url(:search => job_invocation.targeting.search_query)) %>
|
28
|
+
</div>
|
29
|
+
<% end %>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<div class='row'>
|
2
|
+
<div class="col-xs-6 col-sm-12 col-md-12">
|
3
|
+
<div class="card-pf">
|
4
|
+
<div class="card-pf-heading">
|
5
|
+
<h2 style="height: 18px;" class="card-pf-title">
|
6
|
+
<%= _('Providers and templates') %>
|
7
|
+
</h2>
|
8
|
+
</div>
|
9
|
+
<div class="card-pf-body">
|
10
|
+
<p>
|
11
|
+
<% template_invocation = job_invocation.pattern_template_invocations.first %>
|
12
|
+
<h5>
|
13
|
+
<%= template_name_and_provider_link(template_invocation.template) %>
|
14
|
+
</h5>
|
15
|
+
<%= preview_hosts(template_invocation) %>
|
16
|
+
</p>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
</div>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<div id='preview_<%= target.id %>' class='collapse out'>
|
2
|
+
<%= preview_box(template_invocation, target) %>
|
3
|
+
<% if template_invocation.input_values.present? %>
|
4
|
+
<table class='<%= table_css_classes %>'>
|
5
|
+
<thead>
|
6
|
+
<tr>
|
7
|
+
<th><%= _('User input') %></th>
|
8
|
+
<th><%= _('Value') %></th>
|
9
|
+
</tr>
|
10
|
+
</thead>
|
11
|
+
<tbody>
|
12
|
+
<% template_invocation.input_values.joins(:template_input).each do |input_value| %>
|
13
|
+
<tr>
|
14
|
+
<td><b><%= input_value.template_input.name %></b></td>
|
15
|
+
<td><%= input_value.value %></td>
|
16
|
+
</tr>
|
17
|
+
<% end %>
|
18
|
+
</tbody>
|
19
|
+
</table>
|
20
|
+
<% end %>
|
21
|
+
</div>
|