[ARVADOS] created: b520aced3c945de5be62e4aa27561029263c742e

Git user git at public.curoverse.com
Mon Aug 22 16:51:39 EDT 2016


        at  b520aced3c945de5be62e4aa27561029263c742e (commit)


commit b520aced3c945de5be62e4aa27561029263c742e
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date:   Mon Aug 22 16:21:59 2016 -0400

    9043: Complete support for editing basic parameter types.
    
    Supported parameter types: boolean, string, int, long, float, double, enum,
    File, Directory.  May be specified required or optional.
    
    Not supported: arrays, unions (other than with "null"), records.

diff --git a/apps/workbench/app/controllers/container_requests_controller.rb b/apps/workbench/app/controllers/container_requests_controller.rb
index ff6105f..34f892a 100644
--- a/apps/workbench/app/controllers/container_requests_controller.rb
+++ b/apps/workbench/app/controllers/container_requests_controller.rb
@@ -23,22 +23,32 @@ class ContainerRequestsController < ApplicationController
 
   def update
     @updates ||= params[@object.class.to_s.underscore.singularize.to_sym]
-    input_obj = @updates[:mounts][:"/var/lib/cwl/cwl.input.json"][:content]
-    workflow = @object.mounts[:"/var/lib/cwl/workflow.json"][:content]
-    workflow[:inputs].each do |input_schema|
-      if input_obj.include? input_schema[:id]
-        required, primary_type, param_id = cwl_input_info(input_schema)
-        if primary_type == "boolean"
-          input_obj[param_id] = input_obj[param_id] == "true"
-        elsif ["int", "long"].include? primary_type
-          input_obj[param_id] = input_obj[param_id].to_i
-        elsif ["float", "double"].include? primary_type
-          input_obj[param_id] = input_obj[param_id].to_f
-        elsif ["File", "Directory"].include? primary_type
-          input_obj[param_id] = {"class" => "File", "location" => "keep:" + input_obj[param_id]}
+    input_obj = @updates[:mounts].andand[:"/var/lib/cwl/cwl.input.json"].andand[:content]
+    if input_obj
+      workflow = @object.mounts[:"/var/lib/cwl/workflow.json"][:content]
+      workflow[:inputs].each do |input_schema|
+        if input_obj.include? input_schema[:id]
+          required, primary_type, param_id = cwl_input_info(input_schema)
+          if input_obj[param_id] == ""
+            input_obj[param_id] = nil
+          elsif primary_type == "boolean"
+            input_obj[param_id] = input_obj[param_id] == "true"
+          elsif ["int", "long"].include? primary_type
+            input_obj[param_id] = input_obj[param_id].to_i
+          elsif ["float", "double"].include? primary_type
+            input_obj[param_id] = input_obj[param_id].to_f
+          elsif ["File", "Directory"].include? primary_type
+            input_obj[param_id].match /^([0-9a-z]{5}-([0-9a-z]{5})-[0-9a-z]{15})(\/.*)?$/ do |re|
+              c = display_value = Collection.find(re[1])
+              input_obj[param_id] = {"class" => primary_type,
+                                     "location" => "keep:#{c.portable_data_hash}#{re[3]}",
+                                     "arv:collection" => input_obj[param_id]}
+            end
+          end
         end
       end
     end
+    params[:merge] = true
     super
   end
 
diff --git a/apps/workbench/app/helpers/application_helper.rb b/apps/workbench/app/helpers/application_helper.rb
index a82c795..27c7504 100644
--- a/apps/workbench/app/helpers/application_helper.rb
+++ b/apps/workbench/app/helpers/application_helper.rb
@@ -424,6 +424,8 @@ module ApplicationHelper
       primary_type = input_schema[:type].select { |n| n != "null" }[0]
     elsif input_schema[:type].is_a? String
       primary_type = input_schema[:type]
+    elsif input_schema[:type].is_a? Hash
+      primary_type = input_schema[:type]
     end
     param_id = input_schema[:id]
     return required, primary_type, param_id
@@ -453,14 +455,25 @@ module ApplicationHelper
     required, primary_type, param_id = cwl_input_info(input_schema)
 
     dn, attrvalue = cwl_input_value(object, input_schema, set_attr_path + [param_id])
-    attrvalue ||= ""
+    attrvalue = if attrvalue.nil? then "" else attrvalue end
 
     id = "#{object.uuid}-#{param_id}"
 
+    opt_empty_selection = if required then [] else [{value: "", text: ""}] end
+
     if ["Directory", "File"].include? primary_type
       chooser_title = "Choose a #{primary_type == 'Directory' ? 'dataset' : 'file'}:"
       selection_param = object.class.to_s.underscore + dn
-      display_value = attrvalue
+      if attrvalue.is_a? Hash
+        display_value = attrvalue[:"arv:collection"] || attrvalue[:location]
+        display_value.match /^([0-9a-z]{5}-([0-9a-z]{5})-[0-9a-z]{15})(\/.*)?$/ do |re|
+          if re[3]
+            display_value = "#{Collection.find(re[1]).name} / #{re[3][1..-1]}"
+          else
+            display_value = Collection.find(re[1]).name
+          end
+        end
+      end
       modal_path = choose_collections_path \
       ({ title: chooser_title,
          filters: [['owner_uuid', '=', object.owner_uuid]].to_json,
@@ -494,7 +507,7 @@ module ApplicationHelper
                      "data-emptytext" => "none",
                      "data-placement" => "bottom",
                      "data-type" => "select",
-                     "data-source" => "[{value: true, text: \"true\"}, {value: false, text: \"false\"}]",
+                     "data-source" => (opt_empty_selection + [{value: "true", text: "true"}, {value: "false", text: "false"}]).to_json,
                      "data-url" => url_for(action: "update", id: object.uuid, controller: object.class.to_s.pluralize.underscore, merge: true),
                      "data-title" => "Set value for #{input_schema[:id]}",
                      "data-name" => dn,
@@ -505,9 +518,23 @@ module ApplicationHelper
                      :class => "editable #{'required' if required} form-control",
                      :id => id
                    }.merge(htmloptions)
-    elsif "enum" == primary_type
-
-    else
+    elsif primary_type.is_a? Hash and primary_type[:type] == "enum"
+      return link_to attrvalue, '#', {
+                     "data-emptytext" => "none",
+                     "data-placement" => "bottom",
+                     "data-type" => "select",
+                     "data-source" => (opt_empty_selection + primary_type[:symbols].map {|i| {:value => i, :text => i} }).to_json,
+                     "data-url" => url_for(action: "update", id: object.uuid, controller: object.class.to_s.pluralize.underscore, merge: true),
+                     "data-title" => "Set value for #{input_schema[:id]}",
+                     "data-name" => dn,
+                     "data-pk" => "{id: \"#{object.uuid}\", key: \"#{object.class.to_s.underscore}\"}",
+                     "data-value" => attrvalue,
+                     # "clear" button interferes with form-control's up/down arrows
+                     "data-clear" => false,
+                     :class => "editable #{'required' if required} form-control",
+                     :id => id
+                   }.merge(htmloptions)
+    elsif primary_type.is_a? String
       if ["float", "double", "int", "long"].include? primary_type
         datatype = "number"
       else
@@ -527,7 +554,9 @@ module ApplicationHelper
                      "data-clear" => false,
                      :class => "editable #{'required' if required} form-control",
                      :id => id
-                   }.merge(htmloptions)
+                     }.merge(htmloptions)
+    else
+      return "Unable to render editing control for parameter type #{primary_type}"
     end
   end
 
diff --git a/apps/workbench/app/views/container_requests/_show_inputs.html.erb b/apps/workbench/app/views/container_requests/_show_inputs.html.erb
index 87b36c1..b365dc5 100644
--- a/apps/workbench/app/views/container_requests/_show_inputs.html.erb
+++ b/apps/workbench/app/views/container_requests/_show_inputs.html.erb
@@ -22,19 +22,19 @@
 <% end %>
 
 <% if n_inputs == 0 %>
-  <p>This workflow does not need any further inputs specified. You can start it by clicking the "Run" button whenever you're ready. (It's not too late to change the settings, though.)</p>
+  <p><i>This workflow does not need any further inputs specified.  Click the "Run" button at the bottom of the page to start the workflow.</i></p>
 <% else %>
-  <%= render_unreadable_inputs_present %>
-
   <p><i>Provide <%= n_inputs > 1 ? 'values' : 'a value' %> for the following <%= n_inputs > 1 ? 'parameters' : 'parameter' %>, then click the "Run" button to start the workflow.</i></p>
-  <% if @object.editable? %>
-    <%= content_for :pi_input_form %>
-      <%= link_to(url_for('container_request[state]' => 'Committed'),
-          class: 'btn btn-primary run-pipeline-button',
-          method: :patch
-          ) do %>
-        Run <i class="fa fa-fw fa-play"></i>
-    <% end %>
-  <% end %>
+<% end %>
 
+<% if @object.editable? %>
+  <%= content_for :pi_input_form %>
+  <%= link_to(url_for('container_request[state]' => 'Committed'),
+        class: 'btn btn-primary run-pipeline-button',
+        method: :patch
+        ) do %>
+    Run <i class="fa fa-fw fa-play"></i>
+  <% end %>
 <% end %>
+
+<%= render_unreadable_inputs_present %>

commit b97fe66a8f8306780a1cefa524a6488c392fda18
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date:   Fri Aug 19 17:33:18 2016 -0400

    9043: Fixup incoming values from x-editable to have correct types.  Work in progress.

diff --git a/apps/workbench/app/controllers/container_requests_controller.rb b/apps/workbench/app/controllers/container_requests_controller.rb
index b82dbbc..ff6105f 100644
--- a/apps/workbench/app/controllers/container_requests_controller.rb
+++ b/apps/workbench/app/controllers/container_requests_controller.rb
@@ -20,4 +20,26 @@ class ContainerRequestsController < ApplicationController
       redirect_to @object
     end
   end
+
+  def update
+    @updates ||= params[@object.class.to_s.underscore.singularize.to_sym]
+    input_obj = @updates[:mounts][:"/var/lib/cwl/cwl.input.json"][:content]
+    workflow = @object.mounts[:"/var/lib/cwl/workflow.json"][:content]
+    workflow[:inputs].each do |input_schema|
+      if input_obj.include? input_schema[:id]
+        required, primary_type, param_id = cwl_input_info(input_schema)
+        if primary_type == "boolean"
+          input_obj[param_id] = input_obj[param_id] == "true"
+        elsif ["int", "long"].include? primary_type
+          input_obj[param_id] = input_obj[param_id].to_i
+        elsif ["float", "double"].include? primary_type
+          input_obj[param_id] = input_obj[param_id].to_f
+        elsif ["File", "Directory"].include? primary_type
+          input_obj[param_id] = {"class" => "File", "location" => "keep:" + input_obj[param_id]}
+        end
+      end
+    end
+    super
+  end
+
 end
diff --git a/apps/workbench/app/helpers/application_helper.rb b/apps/workbench/app/helpers/application_helper.rb
index e364cd9..a82c795 100644
--- a/apps/workbench/app/helpers/application_helper.rb
+++ b/apps/workbench/app/helpers/application_helper.rb
@@ -425,41 +425,34 @@ module ApplicationHelper
     elsif input_schema[:type].is_a? String
       primary_type = input_schema[:type]
     end
-    return required, primary_type
+    param_id = input_schema[:id]
+    return required, primary_type, param_id
   end
 
   def cwl_input_value(object, input_schema, set_attr_path)
-    param_id = input_schema[:id]
     dn = ""
     attrvalue = object
     set_attr_path.each do |a|
       dn += "[#{a}]"
-      attrvalue = attrvalue[a]
+      attrvalue = attrvalue[a.to_sym]
     end
-    dn += "[#{param_id}]"
-    attrvalue = attrvalue[param_id.to_sym]
-    return dn, attrvalue, param_id
+    return dn, attrvalue
   end
 
   def cwl_inputs_required(object, inputs_schema, set_attr_path)
     r = 0
     inputs_schema.each do |input|
-      required, primary_type = cwl_input_info(input)
-      dn, attrvalue = cwl_input_value(object, input, set_attr_path)
+      required, primary_type, param_id = cwl_input_info(input)
+      dn, attrvalue = cwl_input_value(object, input, set_attr_path + [param_id])
       r += 1 if required and attrvalue.nil?
     end
     r
   end
 
   def render_cwl_input(object, input_schema, set_attr_path, htmloptions={})
-    required, primary_type = cwl_input_info(input_schema)
-    if ["float", "double", "int", "long"].include? primary_type
-      datatype = "number"
-    else
-      datatype = "text"
-    end
+    required, primary_type, param_id = cwl_input_info(input_schema)
 
-    dn, attrvalue, param_id = cwl_input_value(object, input_schema, set_attr_path)
+    dn, attrvalue = cwl_input_value(object, input_schema, set_attr_path + [param_id])
     attrvalue ||= ""
 
     id = "#{object.uuid}-#{param_id}"
@@ -496,7 +489,31 @@ module ApplicationHelper
                   })
         end
       end
+    elsif "boolean" == primary_type
+      return link_to attrvalue, '#', {
+                     "data-emptytext" => "none",
+                     "data-placement" => "bottom",
+                     "data-type" => "select",
+                     "data-source" => "[{value: true, text: \"true\"}, {value: false, text: \"false\"}]",
+                     "data-url" => url_for(action: "update", id: object.uuid, controller: object.class.to_s.pluralize.underscore, merge: true),
+                     "data-title" => "Set value for #{input_schema[:id]}",
+                     "data-name" => dn,
+                     "data-pk" => "{id: \"#{object.uuid}\", key: \"#{object.class.to_s.underscore}\"}",
+                     "data-value" => attrvalue,
+                     # "clear" button interferes with form-control's up/down arrows
+                     "data-clear" => false,
+                     :class => "editable #{'required' if required} form-control",
+                     :id => id
+                   }.merge(htmloptions)
+    elsif "enum" == primary_type
+
     else
+      if ["float", "double", "int", "long"].include? primary_type
+        datatype = "number"
+      else
+        datatype = "text"
+      end
+
       return link_to attrvalue, '#', {
                      "data-emptytext" => "none",
                      "data-placement" => "bottom",

commit 9d3428cd6be5084fde380d6f8de4715e796ea6fc
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date:   Fri Aug 19 16:36:46 2016 -0400

    9043: Initial work on rendering input forms for CWL workflows.  Works for
    simple parameters.  Successfully writes back to container request object.

diff --git a/apps/workbench/app/controllers/container_requests_controller.rb b/apps/workbench/app/controllers/container_requests_controller.rb
index f5a68fe..b82dbbc 100644
--- a/apps/workbench/app/controllers/container_requests_controller.rb
+++ b/apps/workbench/app/controllers/container_requests_controller.rb
@@ -5,7 +5,11 @@ class ContainerRequestsController < ApplicationController
   }
 
   def show_pane_list
-    %w(Status Log Advanced)
+    panes = %w(Status Log Graph Advanced)
+    if @object and @object.state == 'Uncommitted'
+      panes = %w(Inputs) + panes - %w(Log)
+    end
+    panes
   end
 
   def cancel
diff --git a/apps/workbench/app/helpers/application_helper.rb b/apps/workbench/app/helpers/application_helper.rb
index a37ecda..e364cd9 100644
--- a/apps/workbench/app/helpers/application_helper.rb
+++ b/apps/workbench/app/helpers/application_helper.rb
@@ -418,6 +418,102 @@ module ApplicationHelper
     lt
   end
 
+  def cwl_input_info(input_schema)
+    required = !(input_schema[:type].include? "null")
+    if input_schema[:type].is_a? Array
+      primary_type = input_schema[:type].select { |n| n != "null" }[0]
+    elsif input_schema[:type].is_a? String
+      primary_type = input_schema[:type]
+    end
+    return required, primary_type
+  end
+
+  def cwl_input_value(object, input_schema, set_attr_path)
+    param_id = input_schema[:id]
+    dn = ""
+    attrvalue = object
+    set_attr_path.each do |a|
+      dn += "[#{a}]"
+      attrvalue = attrvalue[a]
+    end
+    dn += "[#{param_id}]"
+    attrvalue = attrvalue[param_id.to_sym]
+    return dn, attrvalue, param_id
+  end
+
+  def cwl_inputs_required(object, inputs_schema, set_attr_path)
+    r = 0
+    inputs_schema.each do |input|
+      required, primary_type = cwl_input_info(input)
+      dn, attrvalue = cwl_input_value(object, input, set_attr_path)
+      r += 1 if required and attrvalue.nil?
+    end
+    r
+  end
+
+  def render_cwl_input(object, input_schema, set_attr_path, htmloptions={})
+    required, primary_type = cwl_input_info(input_schema)
+    if ["float", "double", "int", "long"].include? primary_type
+      datatype = "number"
+    else
+      datatype = "text"
+    end
+
+    dn, attrvalue, param_id = cwl_input_value(object, input_schema, set_attr_path)
+    attrvalue ||= ""
+
+    id = "#{object.uuid}-#{param_id}"
+
+    if ["Directory", "File"].include? primary_type
+      chooser_title = "Choose a #{primary_type == 'Directory' ? 'dataset' : 'file'}:"
+      selection_param = object.class.to_s.underscore + dn
+      display_value = attrvalue
+      modal_path = choose_collections_path \
+      ({ title: chooser_title,
+         filters: [['owner_uuid', '=', object.owner_uuid]].to_json,
+         action_name: 'OK',
+         action_href: container_request_path(id: object.uuid),
+         action_method: 'patch',
+         preconfigured_search_str: "",
+         action_data: {
+           merge: true,
+           use_preview_selection: primary_type == 'File' ? true : nil,
+           selection_param: selection_param,
+           success: 'page-refresh'
+         }.to_json,
+        })
+
+      return content_tag('div', :class => 'input-group') do
+        html = text_field_tag(dn, display_value,
+                              :class =>
+                              "form-control #{'required' if required}")
+        html + content_tag('span', :class => 'input-group-btn') do
+          link_to('Choose',
+                  modal_path,
+                  { :class => "btn btn-primary",
+                    :remote => true,
+                    :method => 'get',
+                  })
+        end
+      end
+    else
+      return link_to attrvalue, '#', {
+                     "data-emptytext" => "none",
+                     "data-placement" => "bottom",
+                     "data-type" => datatype,
+                     "data-url" => url_for(action: "update", id: object.uuid, controller: object.class.to_s.pluralize.underscore, merge: true),
+                     "data-title" => "Set value for #{input_schema[:id]}",
+                     "data-name" => dn,
+                     "data-pk" => "{id: \"#{object.uuid}\", key: \"#{object.class.to_s.underscore}\"}",
+                     "data-value" => attrvalue,
+                     # "clear" button interferes with form-control's up/down arrows
+                     "data-clear" => false,
+                     :class => "editable #{'required' if required} form-control",
+                     :id => id
+                   }.merge(htmloptions)
+    end
+  end
+
   def render_arvados_object_list_start(list, button_text, button_href,
                                        params={}, *rest, &block)
     show_max = params.delete(:show_max) || 3
diff --git a/apps/workbench/app/views/container_requests/_show_inputs.html.erb b/apps/workbench/app/views/container_requests/_show_inputs.html.erb
new file mode 100644
index 0000000..87b36c1
--- /dev/null
+++ b/apps/workbench/app/views/container_requests/_show_inputs.html.erb
@@ -0,0 +1,40 @@
+<% n_inputs = cwl_inputs_required(@object, @object.mounts[:"/var/lib/cwl/workflow.json"][:content][:inputs], [:mounts, :"/var/lib/cwl/cwl.input.json", :content]) %>
+
+<% content_for :pi_input_form do %>
+<form role="form" style="width:60%">
+  <div class="form-group">
+    <% workflow = @object.mounts[:"/var/lib/cwl/workflow.json"][:content] %>
+    <% workflow[:inputs].each do |input| %>
+      <label for="#input-<%= input[:id] %>">
+        <%= input[:label] || input[:id] %>
+      </label>
+      <div>
+        <p class="form-control-static">
+          <%= render_cwl_input @object, input, [:mounts, :"/var/lib/cwl/cwl.input.json", :content] %>
+        </p>
+      </div>
+      <p class="help-block">
+        <%= input[:doc] %>
+      </p>
+    <% end %>
+  </div>
+</form>
+<% end %>
+
+<% if n_inputs == 0 %>
+  <p>This workflow does not need any further inputs specified. You can start it by clicking the "Run" button whenever you're ready. (It's not too late to change the settings, though.)</p>
+<% else %>
+  <%= render_unreadable_inputs_present %>
+
+  <p><i>Provide <%= n_inputs > 1 ? 'values' : 'a value' %> for the following <%= n_inputs > 1 ? 'parameters' : 'parameter' %>, then click the "Run" button to start the workflow.</i></p>
+  <% if @object.editable? %>
+    <%= content_for :pi_input_form %>
+      <%= link_to(url_for('container_request[state]' => 'Committed'),
+          class: 'btn btn-primary run-pipeline-button',
+          method: :patch
+          ) do %>
+        Run <i class="fa fa-fw fa-play"></i>
+    <% end %>
+  <% end %>
+
+<% end %>

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list