foreman_remote_execution 1.5.0 → 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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>
|