2961: Don't call #render_index from #index on folders_controller because #index
[arvados.git] / apps / workbench / app / controllers / pipeline_instances_controller.rb
1 class PipelineInstancesController < ApplicationController
2   skip_before_filter :find_object_by_uuid, only: :compare
3   before_filter :find_objects_by_uuid, only: :compare
4   include PipelineInstancesHelper
5
6   def graph(pipelines)
7     return nil, nil if params['tab_pane'] != "Graph"
8
9     count = {}
10     provenance = {}
11     pips = {}
12     n = 1
13
14     pipelines.each do |p|
15       collections = []
16
17       p.components.each do |k, v|
18         j = v[:job] || next
19
20         # The graph is interested in whether the component is
21         # indicated as persistent, more than whether the job
22         # satisfying it (which could have been reused, or someone
23         # else's) is.
24         j[:output_is_persistent] = v[:output_is_persistent]
25
26         uuid = j[:uuid].intern
27         provenance[uuid] = j
28         pips[uuid] = 0 unless pips[uuid] != nil
29         pips[uuid] |= n
30
31         collections << j[:output]
32         ProvenanceHelper::find_collections(j[:script_parameters]).each do |k|
33           collections << k
34         end
35
36         uuid = j[:script_version].intern
37         provenance[uuid] = {:uuid => uuid}
38         pips[uuid] = 0 unless pips[uuid] != nil
39         pips[uuid] |= n
40       end
41
42       Collection.where(uuid: collections.compact).each do |c|
43         uuid = c.uuid.intern
44         provenance[uuid] = c
45         pips[uuid] = 0 unless pips[uuid] != nil
46         pips[uuid] |= n
47       end
48
49       n = n << 1
50     end
51
52     return provenance, pips
53   end
54
55   def show
56     @pipelines = [@object]
57
58     if params[:compare]
59       PipelineInstance.where(uuid: params[:compare]).each do |p|
60         @pipelines << p
61       end
62     end
63
64     provenance, pips = graph(@pipelines)
65     if provenance
66       @prov_svg = ProvenanceHelper::create_provenance_graph provenance, "provenance_svg", {
67         :request => request,
68         :all_script_parameters => true,
69         :combine_jobs => :script_and_version,
70         :script_version_nodes => true,
71         :pips => pips }
72     end
73
74     super
75   end
76
77   def compare
78     @breadcrumb_page_name = 'compare'
79
80     @rows = []          # each is {name: S, components: [...]}
81
82     # Build a table: x=pipeline y=component
83     @objects.each_with_index do |pi, pi_index|
84       pipeline_jobs(pi).each do |component|
85         # Find a cell with the same name as this component but no
86         # entry for this pipeline
87         target_row = nil
88         @rows.each_with_index do |row, row_index|
89           if row[:name] == component[:name] and !row[:components][pi_index]
90             target_row = row
91           end
92         end
93         if !target_row
94           target_row = {name: component[:name], components: []}
95           @rows << target_row
96         end
97         target_row[:components][pi_index] = component
98       end
99     end
100
101     @rows.each do |row|
102       # Build a "normal" pseudo-component for this row by picking the
103       # most common value for each attribute. If all values are
104       # equally common, there is no "normal".
105       normal = {}              # attr => most common value
106       highscore = {}           # attr => how common "normal" is
107       score = {}               # attr => { value => how common }
108       row[:components].each do |pj|
109         next if pj.nil?
110         pj.each do |k,v|
111           vstr = for_comparison v
112           score[k] ||= {}
113           score[k][vstr] = (score[k][vstr] || 0) + 1
114           highscore[k] ||= 0
115           if score[k][vstr] == highscore[k]
116             # tie for first place = no "normal"
117             normal.delete k
118           elsif score[k][vstr] == highscore[k] + 1
119             # more pipelines have v than anything else
120             highscore[k] = score[k][vstr]
121             normal[k] = vstr
122           end
123         end
124       end
125
126       # Add a hash in component[:is_normal]: { attr => is_the_value_normal? }
127       row[:components].each do |pj|
128         next if pj.nil?
129         pj[:is_normal] = {}
130         pj.each do |k,v|
131           pj[:is_normal][k] = (normal.has_key?(k) && normal[k] == for_comparison(v))
132         end
133       end
134     end
135
136     provenance, pips = graph(@objects)
137
138     @pipelines = @objects
139
140     @prov_svg = ProvenanceHelper::create_provenance_graph provenance, "provenance_svg", {
141       :request => request,
142       :all_script_parameters => true,
143       :combine_jobs => :script_and_version,
144       :script_version_nodes => true,
145       :pips => pips }
146   end
147
148   def show_pane_list
149     panes = %w(Components Graph Attributes Metadata JSON API)
150     if @object and @object.state.in? ['New', 'Ready']
151       panes = %w(Inputs) + panes
152     end
153     panes
154   end
155
156   def compare_pane_list
157     %w(Compare Graph)
158   end
159
160   def index
161     @limit = 20
162     super
163   end
164
165   protected
166   def for_comparison v
167     if v.is_a? Hash or v.is_a? Array
168       v.to_json
169     else
170       v.to_s
171     end
172   end
173
174   def find_objects_by_uuid
175     @objects = model_class.where(uuid: params[:uuids])
176   end
177
178 end