Fixed bug when selection list was cleared.
[arvados.git] / apps / workbench / app / helpers / provenance_helper.rb
index 9d9f44b335919dc2e1b698c4984b543cb2f47cfe..fced9da3aa98c6c728df6e950cb788a254e30ec0 100644 (file)
@@ -9,11 +9,13 @@ module ProvenanceHelper
     end
 
     def self.collection_uuid(uuid)
-      m = /^([a-f0-9]{32}(\+[0-9]+)?)(\+.*)?$/.match(uuid.to_s)
+      m = CollectionsHelper.match(uuid)
       if m
-        #if m[2]
-        return m[1]
-        #else
+        if m[2]
+          return m[1]+m[2]
+        else
+          return m[1]
+        end
         #  Collection.where(uuid: ['contains', m[1]]).each do |u|
         #    puts "fixup #{uuid} to #{u.uuid}"
         #    return u.uuid
@@ -24,17 +26,30 @@ module ProvenanceHelper
       end
     end
 
+    def determine_fillcolor(n)
+      fillcolor = %w(aaaaaa aaffaa aaaaff aaaaaa ffaaaa)[n || 0] || 'aaaaaa'
+      "style=filled,fillcolor=\"##{fillcolor}\""
+    end
+
     def describe_node(uuid)
+      bgcolor = determine_fillcolor @opts[:pips][uuid] if @opts[:pips]
+
       rsc = ArvadosBase::resource_class_for_uuid uuid.to_s
       if rsc
         href = "/#{rsc.to_s.underscore.pluralize rsc}/#{uuid}"
-
+      
         #"\"#{uuid}\" [label=\"#{rsc}\\n#{uuid}\",href=\"#{href}\"];\n"
         if rsc == Collection
+          #puts uuid
+          if uuid == :"d41d8cd98f00b204e9800998ecf8427e+0"
+            # special case
+            #puts "empty!"
+            return "\"#{uuid}\" [label=\"(empty collection)\"];\n"
+          end
           if @pdata[uuid] 
             #puts @pdata[uuid]
             if @pdata[uuid][:name]
-              return "\"#{uuid}\" [label=\"#{@pdata[uuid][:name]}\",href=\"#{href}\",shape=oval];\n"
+              return "\"#{uuid}\" [label=\"#{@pdata[uuid][:name]}\",href=\"#{href}\",shape=oval,#{bgcolor}];\n"
             else
               files = nil
               if @pdata[uuid].respond_to? :files
@@ -54,19 +69,21 @@ module ProvenanceHelper
                 if i < files.length
                   label += "\\n&vellip;"
                 end
-                return "\"#{uuid}\" [label=\"#{label}\",href=\"#{href}\",shape=oval];\n"
+                return "\"#{uuid}\" [label=\"#{label}\",href=\"#{href}\",shape=oval,#{bgcolor}];\n"
               end
             end  
           end
-          return "\"#{uuid}\" [label=\"#{rsc}\",href=\"#{href}\"];\n"
+          return "\"#{uuid}\" [label=\"#{rsc}\",href=\"#{href}\",#{bgcolor}];\n"
         end
       end
-      return ""
+      "\"#{uuid}\" [#{bgcolor}];\n"
     end
 
     def job_uuid(job)
-      if @opts[:combine_jobs]
+      if @opts[:combine_jobs] == :script_only
         uuid = "#{job[:script]}"
+      elsif @opts[:combine_jobs] == :script_and_version
+        uuid = "#{job[:script]}_#{job[:script_version]}"
       else
         uuid = "#{job[:uuid]}"
       end
@@ -96,45 +113,45 @@ module ProvenanceHelper
 
     def script_param_edges(job, prefix, sp)
       gr = ""
-      if sp and not sp.empty?
-        case sp
-        when Hash
-          sp.each do |k, v|
-            if prefix.size > 0
-              k = prefix + "::" + k.to_s
-            end
-            gr += script_param_edges(job, k.to_s, v)
-          end
-        when Array
-          i = 0
-          node = ""
-          sp.each do |v|
-            if GenerateGraph::collection_uuid(v)
-              gr += script_param_edges(job, "#{prefix}[#{i}]", v)
-            else
-              node += "', '" unless node == ""
-              node = "['" if node == ""
-              node += "#{v}"
-            end
-            i += 1
-          end
-          unless node == ""
-            node += "']"
-            #puts node
-            #id = "#{job[:uuid]}_#{prefix}"
-            gr += "\"#{node}\" [label=\"#{node}\"];\n"
-            gr += edge(job_uuid(job), node, {:label => prefix})        
+      case sp
+      when Hash
+        sp.each do |k, v|
+          if prefix.size > 0
+            k = prefix + "::" + k.to_s
           end
-        else
-          m = GenerateGraph::collection_uuid(sp)
-          if m
-            gr += edge(job_uuid(job), m, {:label => prefix})
-            gr += generate_provenance_edges(m)
+          gr += script_param_edges(job, k.to_s, v)
+        end
+      when Array
+        i = 0
+        node = ""
+        sp.each do |v|
+          if GenerateGraph::collection_uuid(v)
+            gr += script_param_edges(job, "#{prefix}[#{i}]", v)
           elsif @opts[:all_script_parameters]
-            #id = "#{job[:uuid]}_#{prefix}"
-            gr += "\"#{sp}\" [label=\"#{sp}\"];\n"
-            gr += edge(job_uuid(job), sp, {:label => prefix})
+            node += "', '" unless node == ""
+            node = "['" if node == ""
+            node += "#{v}"
           end
+          i += 1
+        end
+        unless node == ""
+          node += "']"
+          #puts node
+          #id = "#{job[:uuid]}_#{prefix}"
+          gr += "\"#{node}\" [label=\"#{node}\"];\n"
+          gr += edge(job_uuid(job), node, {:label => prefix})        
+        end
+      when String
+        return '' if sp.empty?
+        m = GenerateGraph::collection_uuid(sp)
+        #puts "#{m} pdata is #{@pdata[m.intern]}"
+        if m and (@pdata[m.intern] or (not @opts[:pdata_only]))
+          gr += edge(job_uuid(job), m, {:label => prefix})
+          gr += generate_provenance_edges(m)
+        elsif @opts[:all_script_parameters]
+          #id = "#{job[:uuid]}_#{prefix}"
+          gr += "\"#{sp}\" [label=\"#{sp}\"];\n"
+          gr += edge(job_uuid(job), sp, {:label => prefix})
         end
       end
       gr
@@ -165,6 +182,11 @@ module ProvenanceHelper
         # uuid is a collection
         gr += describe_node(uuid)
 
+        if m == :"d41d8cd98f00b204e9800998ecf8427e+0"
+          # empty collection, don't follow any further
+          return gr
+        end
+
         @pdata.each do |k, job|
           if job[:output] == uuid.to_s
             gr += edge(uuid, job_uuid(job), {:label => "output"})
@@ -185,6 +207,7 @@ module ProvenanceHelper
             gr += script_param_edges(job, "", job[:script_parameters])
 
             if @opts[:script_version_nodes]
+              gr += describe_node(job[:script_version])
               gr += edge(job_uuid(job), job[:script_version], {:label => "script_version"})
             end
           end
@@ -206,25 +229,34 @@ module ProvenanceHelper
       gr
     end
 
-    def add_jobs_href
+    def describe_jobs
       gr = ""
       @jobs.each do |k, v|
         gr += "\"#{k}\" [href=\"/jobs?"
-        script = ""
+        
+        n = 0
         v.each do |u|
           gr += "uuid%5b%5d=#{u[:uuid]}&"
-          script = u[:script]
+          n |= @opts[:pips][u[:uuid].intern] if @opts[:pips] and @opts[:pips][u[:uuid].intern]
         end
+
         gr += "\",label=\""
-        gr += if @opts[:combine_jobs] then "#{script}" else "#{script}\\n#{v[0][:finished_at]}" end
-        gr += "\"];\n"
+        
+        if @opts[:combine_jobs] == :script_only
+          gr += uuid = "#{v[0][:script]}"
+        elsif @opts[:combine_jobs] == :script_and_version
+          gr += uuid = "#{v[0][:script]}"
+        else
+          gr += uuid = "#{v[0][:script]}\\n#{v[0][:finished_at]}"
+        end
+        gr += "\",#{determine_fillcolor n}];\n"
       end
       gr
     end
 
   end
 
-  def self.create_provenance_graph(pdata, opts={})
+  def self.create_provenance_graph(pdata, svgId, opts={})
     if pdata.is_a? Array or pdata.is_a? ArvadosResourceList
       p2 = {}
       pdata.each do |k|
@@ -238,8 +270,8 @@ module ProvenanceHelper
     end
     
     gr = """strict digraph {
-node [fontsize=8,shape=box];
-edge [fontsize=8];
+node [fontsize=10,shape=box];
+edge [fontsize=10];
 """
 
     if opts[:direction] == :bottom_up
@@ -254,7 +286,7 @@ edge [fontsize=8];
       gr += g.generate_provenance_edges(k)
     end
 
-    gr += g.add_jobs_href
+    gr += g.describe_jobs
 
     gr += "}"
     svg = ""
@@ -273,21 +305,22 @@ edge [fontsize=8];
 
     svg = svg.sub(/<\?xml.*?\?>/m, "")
     svg = svg.sub(/<!DOCTYPE.*?>/m, "")
+    svg = svg.sub(/<svg /, "<svg id=\"#{svgId}\" ")
   end
 
   def self.find_collections(sp)
     c = []
-    if sp and not sp.empty?
-      case sp
-      when Hash
-        sp.each do |k, v|
-          c.concat(find_collections(v))
-        end
-      when Array
-        sp.each do |v|
-          c.concat(find_collections(v))
-        end
-      else
+    case sp
+    when Hash
+      sp.each do |k, v|
+        c.concat(find_collections(v))
+      end
+    when Array
+      sp.each do |v|
+        c.concat(find_collections(v))
+      end
+    when String
+      if !sp.empty?
         m = GenerateGraph::collection_uuid(sp)
         if m
           c << m