myexperiment-hackers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[myexperiment-hackers] [2799] branches/datasets: initial datasets implem


From: noreply
Subject: [myexperiment-hackers] [2799] branches/datasets: initial datasets implementation
Date: Thu, 10 Nov 2011 09:35:11 -0500 (EST)

Revision
2799
Author
dgc
Date
2011-11-10 09:35:11 -0500 (Thu, 10 Nov 2011)

Log Message

initial datasets implementation

Modified Paths

Added Paths

Diff

Modified: branches/datasets/app/controllers/workflows_controller.rb (2798 => 2799)


--- branches/datasets/app/controllers/workflows_controller.rb	2011-11-10 14:18:07 UTC (rev 2798)
+++ branches/datasets/app/controllers/workflows_controller.rb	2011-11-10 14:35:11 UTC (rev 2799)
@@ -20,6 +20,8 @@
   before_filter :check_custom_workflow_type, : [:create, :create_version]
   
   before_filter :check_is_owner, : [:edit, :update]
+  
+  before_filter :get_example_data_sets, : [:tag_suggestions, :extra_metadata]
 
   # declare sweepers and which actions should invoke them
   cache_sweeper :workflow_sweeper, : [ :create, :create_version, :launch, :update, :update_version, :destroy_version, :destroy ]
@@ -637,11 +639,20 @@
   end
   
   def tag_suggestions
+
     @suggestions = @workflow.get_tag_suggestions
+
   end
 
+  def extra_metadata
+  end
+
   def process_tag_suggestions
 
+    def form_name(*bits)
+      bits.join("_")
+    end
+
     if params[:workflow] && params[:workflow][:body]
       @workflow.body = params[:workflow][:body]
       @workflow.save
@@ -651,6 +662,184 @@
       @workflow.add_tag(tag.strip, current_user)
     end
 
+    begin
+
+      # Fetch the existing data structure
+
+      data_sets = DataSet.find(:all,
+          :conditions => ["contributable_type = ? AND contributable_id = ? AND category = ? AND user_id = ?",
+          @workflow.class.name, @workflow.id, 'example', current_user])
+
+      # Parse form data
+
+      form_data = (0..params[form_name(["ds", "count"])].to_i - 1).map do |s|
+        {
+          ".id"   => params[form_name(["ds", s, ".id"])],
+          "title" => params[form_name(["ds", s, "title"])],
+          "desc"  => params[form_name(["ds", s, "desc"])],
+
+          "inputs" => (0..params[form_name(["ds", s, "input",  "count"])].to_i - 1).map do |i|
+            { ".id"   => params[form_name(["ds", s, "input", i, ".id"])],
+              "label" => params[form_name(["ds", s, "input", i, "label"])],
+              "data"  => params[form_name(["ds", s, "input", i, "data"])]
+            }
+          end,
+
+          "outputs" => (0..params[form_name(["ds", s, "output", "count"])].to_i - 1).map do |o|
+            { ".id"   => params[form_name(["ds", s, "output", o, ".id"])],
+              "label" => params[form_name(["ds", s, "output", o, "label"])],
+              "data"  => params[form_name(["ds", s, "output", o, "data"])]
+            }
+          end
+        }
+      end
+
+      # Update the data structure
+
+      pre_ds_ids  = data_sets.map do |ds| ds.id end
+      post_ds_ids = (form_data.map do |ds| ds[".id"] end - [nil]).map do |id| id.to_i end
+
+      # Update data sets
+
+      data_sets.each do |ds_ob|
+
+        if post_ds_ids.include?(ds_ob.id)
+
+          form_ds = form_data.select do |ds| ds[".id"] && (ds[".id"].to_i == ds_ob.id) end.first
+
+          update_ds = false
+
+          if ds_ob.title != form_ds["title"]
+            ds_ob.title = form_ds["title"]
+            updated_ds = true
+          end
+
+          if ds_ob.description != form_ds["desc"]
+            ds_ob.description = form_ds["desc"]
+            updated_ds = true
+          end
+
+          input_obs  = ds_ob.data_items.select do |di| di.category == "input"  end
+          output_obs = ds_ob.data_items.select do |di| di.category == "output" end
+
+          pre_input_ids  = input_obs.map  do |di| di.id end
+          pre_output_ids = output_obs.map do |di| di.id end
+
+          post_input_ids  = (form_ds["inputs"].map do |input| input[".id"] end - [nil]).map do |input| input.to_i end
+
+          post_output_ids = (form_ds["outputs"].map do |output| output[".id"] end - [nil]).map do |output| output.to_i end
+
+          # Update inputs
+
+          input_obs.each do |input_ob|
+
+            if post_input_ids.include?(input_ob.id)
+
+              updated_input = false
+
+              form_input = form_ds["inputs"].select do |input| input[".id"] && (input[".id"].to_i == input_ob.id) end.first
+
+              if input_ob.label != form_input["label"]
+                input_ob.label = form_input["label"]
+                updated_input = true
+              end
+
+              if input_ob.data != form_input["data"]
+                input_ob.data = ""
+                updated_input = true
+              end
+
+              if updated_input
+                input_ob.save
+                updated_ds = true
+              end
+            end
+          end
+
+          # Create inputs
+
+          form_ds["inputs"].select do |input| input[".id"].nil? end.each do |input|
+            DataItem.create(:data_set => ds_ob, :category => "input",
+                :label => input["label"], :data ="" input["data"])
+          end
+            
+          # Delete inputs
+
+          (pre_input_ids - post_input_ids).each do |id|
+            DataItem.destroy(id)
+          end
+
+          # Update outputs
+
+          output_obs.each do |output_ob|
+
+            if post_output_ids.include?(output_ob.id)
+
+              updated_output = false
+
+              form_output = form_ds["outputs"].select do |output| output[".id"] && (output[".id"].to_i == output_ob.id) end.first
+
+              if output_ob.label != form_output["label"]
+                output_ob.label = form_output["label"]
+                updated_output = true
+              end
+
+              if output_ob.data != form_output["data"]
+                output_ob.data = ""
+                updated_output = true
+              end
+
+              if updated_output
+                output_ob.save
+                updated_ds = true
+              end
+            end
+          end
+
+          # Create outputs
+
+          form_ds["outputs"].select do |output| output[".id"].nil? end.each do |output|
+            DataItem.create(:data_set => ds_ob, :category => "output",
+                :label => output["label"], :data ="" output["data"])
+          end
+            
+          # Delete outputs
+
+          (pre_output_ids - post_output_ids).each do |id|
+            DataItem.destroy(id)
+          end
+
+          ds_ob.save if updated_ds
+        end
+      end
+
+      # Create data sets
+
+      form_data.select do |ds| ds[".id"].nil? end.each do |ds|
+
+        ds_ob = DataSet.create(:contributable => @workflow, :user => current_user,
+            :category => 'example', :title => ds["title"], :description => ds["desc"])
+
+        ds["inputs"].each do |input|
+          DataItem.create(:data_set => ds_ob, :category => "input",
+              :label => input["label"], :data ="" input["data"])
+        end
+
+        ds["outputs"].each do |output|
+          DataItem.create(:data_set => ds_ob, :category => "output",
+              :label => output["label"], :data ="" output["data"])
+        end
+      end
+
+      # Delete data sets
+
+      (pre_ds_ids - post_ds_ids).each do |id|
+        DataSet.destroy(id)
+      end
+
+    rescue
+    end
+
     redirect_to(workflow_url(@workflow))
   end
 
@@ -1054,5 +1243,29 @@
     return ok
   end
 
+  def get_example_data_sets
+
+    @data_sets = DataSet.find(:all,
+        :conditions => ["contributable_type = ? AND contributable_id = ? AND category = ? AND user_id = ?",
+        @workflow.class.name, @workflow.id, 'example', current_user.id]).map do |data_set|
+
+      { "title"   => data_set.title,
+        "desc"    => data_set.description,
+        ".id"     => data_set.id,
+
+        "inputs"  => data_set.data_items.select do |item|
+          item.category == 'input'
+        end.map do |input|
+          { ".id" => input.id, "label" => input.label, "data" => input.data }
+        end,
+
+        "outputs" => data_set.data_items.select do |item|
+          item.category == 'output'
+        end.map do |output|
+          { ".id" => output.id, "label" => output.label, "data" => output.data }
+        end
+      }
+    end
+  end
 end
 

Added: branches/datasets/app/views/workflows/_data_sets_form.rhtml (0 => 2799)


--- branches/datasets/app/views/workflows/_data_sets_form.rhtml	                        (rev 0)
+++ branches/datasets/app/views/workflows/_data_sets_form.rhtml	2011-11-10 14:35:11 UTC (rev 2799)
@@ -0,0 +1,6 @@
+<div id="data_sets"></div>
+
+<input type="button"  return false;" value="Add new set of example inputs / outputs" />
+
+<script type="text/_javascript_" src=""
+<script type="text/_javascript_">renderDataSets(<%= data_sets.to_json %>)</script>

Added: branches/datasets/app/views/workflows/extra_metadata.rhtml (0 => 2799)


--- branches/datasets/app/views/workflows/extra_metadata.rhtml	                        (rev 0)
+++ branches/datasets/app/views/workflows/extra_metadata.rhtml	2011-11-10 14:35:11 UTC (rev 2799)
@@ -0,0 +1,14 @@
+<%= _javascript__include_tag :fckeditor %>
+
+<h1>Example inputs / outputs</h1>
+
+<form id="metadata" action="" "/workflows/address@hidden/process_extra_metadata" %>" method="post">
+
+  <%= render :partial => "data_sets_form", :locals => { :data_sets => @data_sets, :default_ports => @default_ports } %>
+
+  <p style="text-align: center">
+    <input id="submit-button" type="submit" value="Update" />
+  </p>
+
+</form>
+

Modified: branches/datasets/app/views/workflows/tag_suggestions.rhtml (2798 => 2799)


--- branches/datasets/app/views/workflows/tag_suggestions.rhtml	2011-11-10 14:18:07 UTC (rev 2798)
+++ branches/datasets/app/views/workflows/tag_suggestions.rhtml	2011-11-10 14:35:11 UTC (rev 2799)
@@ -3,7 +3,7 @@
 
 <h1>Extra workflow metadata</h1>
 
-<form action="" "/workflows/address@hidden/process_tag_suggestions" %>" method="post">
+<form id="metadata" action="" "/workflows/address@hidden/process_tag_suggestions" %>" method="post">
 
   <% if @workflow.body.nil? || @workflow.body == "" %>
 
@@ -38,6 +38,10 @@
 
   <div id="summary-text"></div>
 
+  <h1>Example inputs / outputs</h1>
+
+  <%= render :partial => "data_sets_form", :locals => { :data_sets => @data_sets, :default_ports => @default_ports } %>
+
   <h2>Finish</h2>
 
   <p>Complete the upload process.</p>

Modified: branches/datasets/config/routes.rb (2798 => 2799)


--- branches/datasets/config/routes.rb	2011-11-10 14:18:07 UTC (rev 2798)
+++ branches/datasets/config/routes.rb	2011-11-10 14:35:11 UTC (rev 2799)
@@ -118,6 +118,8 @@
                  :destroy_version => :delete, 
                  :edit_version => :get, 
                  :update_version => :put, 
+                 :process_extra_metadata => :post,
+                 :extra_metadata => :get,
                  :process_tag_suggestions => :post,
                  :tag_suggestions => :get } do |workflow|
     # workflows have nested citations

Modified: branches/datasets/config/schema.d/workflows.xml (2798 => 2799)


--- branches/datasets/config/schema.d/workflows.xml	2011-11-10 14:18:07 UTC (rev 2798)
+++ branches/datasets/config/schema.d/workflows.xml	2011-11-10 14:35:11 UTC (rev 2799)
@@ -51,6 +51,39 @@
 
   </table>
 
+  <table name="data_sets">
+
+    <column type="integer"  name="user_id"/>
+    <column type="string"   name="contributable_type"/>
+    <column type="integer"  name="contributable_id"/>
+    <column type="datetime" name="created_at"/>
+    <column type="datetime" name="updated_at"/>
+    <column type="text"     name="title"/>
+    <column type="text"     name="description"/>
+    <column type="text"     name="description_html"/>
+    <column type="text"     name="category"/>
+
+    <belongs-to target="users"/>
+    <belongs-to target="contributable" polymorphic="true"/>
+
+    <has-many target="data_items" foreign_key="data_set_id" dependent="destroy"/>
+
+  </table>
+
+  <table name="data_items">
+
+    <column type="integer"  name="data_set_id"/>
+    <column type="datetime" name="created_at"/>
+    <column type="datetime" name="updated_at"/>
+    <column type="text"     name="category"/>
+    <column type="text"     name="label"/>
+    <column type="text"     name="data"/>
+
+    <belongs-to target="users"/>
+    <belongs-to target="data_sets"/>
+
+  </table>
+
   <table name="workflow_processors">
 
     <column type="integer"    name="workflow_id"/>

Added: branches/datasets/public/_javascript_s/data_sets.js (0 => 2799)


--- branches/datasets/public/_javascript_s/data_sets.js	                        (rev 0)
+++ branches/datasets/public/_javascript_s/data_sets.js	2011-11-10 14:35:11 UTC (rev 2799)
@@ -0,0 +1,200 @@
+// myExperiment: app/controllers/workflows_controller.rb
+// 
+// Copyright (c) 2010 University of Manchester and the University of Southampton.
+// See license.txt for details.
+
+function form_name() {
+  return Array.prototype.slice.call(arguments).join("_"); 
+}
+
+function saveDataSets() {
+
+  function saveOptionalField(name, key, outputHash) {
+
+    value_el = document.forms["metadata"][name]
+
+    if (value_el == undefined)
+      return;
+
+    outputHash[key] = value_el.value;
+  }
+
+  var data_set_count = parseInt(document.forms["metadata"][form_name("ds", "count")].value)
+
+  var data_sets = [];
+
+  for (var s = 0; s < data_set_count; s++) {
+    var data_set = {
+      "title" : document.forms["metadata"][form_name("ds", s, "title")].value,
+      "desc"  : document.forms["metadata"][form_name("ds", s, "desc")].value
+    };
+
+    saveOptionalField(form_name("ds", s, ".id"), ".id", data_set);
+
+    data_set["inputs"]  = []
+    data_set["outputs"] = []
+
+    var input_count  = parseInt(document.forms["metadata"][form_name("ds", s, "input",  "count")].value);
+    var output_count = parseInt(document.forms["metadata"][form_name("ds", s, "output", "count")].value);
+
+    for (var i = 0; i < input_count; i++) {
+
+      input = {
+        "label" : document.forms["metadata"][form_name("ds", s, "input", i, "label")].value,
+        "data"  : document.forms["metadata"][form_name("ds", s, "input", i, "data")].value
+      };
+     
+      saveOptionalField(form_name("ds", s, "input", i, ".id"), ".id", input);
+
+      data_set["inputs"].push(input);
+    }
+
+    for (var o = 0; o < output_count; o++) {
+
+      output = {
+        "label" : document.forms["metadata"][form_name("ds", s, "output", o, "label")].value,
+        "data"  : document.forms["metadata"][form_name("ds", s, "output", o, "data")].value
+      };
+
+      saveOptionalField(form_name("ds", s, "output", o, ".id"), ".id", output)
+
+      data_set["outputs"].push(output);
+    }
+
+    data_sets.push(data_set);
+  }
+
+  return data_sets;
+}
+
+function renderDataSets(data_sets) {
+
+  function renderOptionalField(name, value) {
+    if (value == undefined) {
+      return "";
+    } else {
+      return "<input type='hidden' name='" + name + "' value='" + value + "'></input>";
+    }
+  }
+
+  var markup = "";
+
+  markup += "<input type='hidden' name='" + form_name("ds", "count") + "' value='" + data_sets.length + "'></input>";
+
+  if (data_sets.length == 0) {
+
+    markup += "<p><i>You have not provided any example data sets.</i></p>";
+
+  } else {
+
+    for (var s = 0; s < data_sets.length; s++) {
+
+      var data_set = data_sets[s];
+
+      markup += "<div class=\"form\">";
+      markup += renderOptionalField(form_name("ds", s, ".id"), data_set[".id"]);
+      markup += "<input type='hidden' name='" + form_name("ds", s, "input", "count") + "' value='" + data_set["inputs"].length + "'></input>"
+      markup += "<input type='hidden' name='" + form_name("ds", s, "output", "count") + "' value='" + data_set["outputs"].length + "'></input>"
+
+      markup += "  <div class=\"dataset\">";
+      markup += "    <div class=\"form-triple\">";
+      markup += "      <div class=\"form-label\">Title</div>";
+      markup += "      <div class=\"form-data\"><input class=\"dataset-title\" name=\"" + form_name("ds", s, "title") + "\" value=\"" + data_set["title"] + "\" /></div>";
+      markup += "      <div class=\"form-action\"></div>";
+      markup += "    </div>";
+      markup += "    <div class=\"form-triple\">";
+      markup += "      <div class=\"form-label\">Description</div>";
+      markup += "      <div class=\"form-data\"><textarea class=\"dataset-description\" id=\"" + form_name("ds", s, "desc") + "\" name=\"" + form_name("ds", s, "desc") + "\">" + data_set["desc"] + "</textarea></div>";
+      markup += "      <div class=\"form-action\"></div>";
+      markup += "    </div>";
+      markup += "    <table class=\"dataset-table\">";
+      markup += "      <thead>";
+      markup += "        <tr>";
+      markup += "          <th class=\"form-label\">Input</th>";
+      markup += "          <th class=\"form-data\">Value</th>";
+      markup += "        </tr>";
+      markup += "      </thead>";
+      markup += "      <tbody>";
+
+      for (var i = 0; i < data_set["inputs"].length; i++) {
+
+        var input = data_set["inputs"][i];
+
+        markup += renderOptionalField(form_name("ds", s, "input", i, ".id"), input[".id"]);
+
+        markup += "        <tr>";
+        markup += "          <td class=\"label\"><input class=\"dataset-io-label\" name=\"" + form_name("ds", s, "input", i, "label") + "\" value=\"" + input["label"] + "\" /></td>";
+        markup += "          <td class=\"data\"><textarea class=\"dataset-io-data\" name=\"" + form_name("ds", s, "input", i, "data") + "\">" + input["data"] + "</textarea></td>";
+        markup += "          <td class=\"action\"><input class=\"dataset-io-action\" type=\"button\" value=\"Delete\"  /></td>";
+        markup += "        </tr>";
+      }
+
+      markup += "      </tbody>";
+      markup += "    </table>";
+      markup += "    <input type='button' value='Add new input'  />";
+      markup += "    <table class=\"dataset-table\">";
+      markup += "      <thead>";
+      markup += "        <tr>";
+      markup += "          <th class=\"form-label\">Output</th>";
+      markup += "          <th class=\"form-data\">Value</th>";
+      markup += "        </tr>";
+      markup += "      </thead>";
+      markup += "      <tbody>";
+      
+      for (var i = 0; i < data_set["outputs"].length; i++) {
+
+        var output = data_set["outputs"][i];
+
+        markup += renderOptionalField(form_name("ds", s, "output", i, ".id"), output[".id"]);
+
+        markup += "        <tr>";
+        markup += "          <td class=\"label\"><input class=\"dataset-io-label\" name=\"" + form_name("ds", s, "output", i, "label") + "\" value=\"" + output["label"] + "\" /></td>";
+        markup += "          <td class=\"data\"><textarea class=\"dataset-io-data\" name=\"" + form_name("ds", s, "output", i, "data") + "\">" + output["data"] + "</textarea></td>";
+        markup += "          <td class=\"action\"><input class=\"dataset-io-action\" type=\"button\" value=\"Delete\"  /></td>";
+        markup += "        </tr>";
+      }
+
+      markup += "      </tbody>";
+      markup += "    </table>";
+      markup += "    <input type='button' value='Add new output'  /></div>";
+      markup += "    <input class='delete-data-set' type='button' value='Delete set of example inputs / outputs'  />";
+      markup += "  <div style='clear: right'></div>";
+      markup += "  </div>";
+      markup += "</div>";
+    }
+  }
+
+  document.getElementById('data_sets').innerHTML = markup;
+
+  for (var s = 0; s < data_sets.length; s++) {
+    var oFCKeditor = new FCKeditor(form_name("ds", s, "desc"), '400px', '80px', 'None');
+    oFCKeditor.BasePath = '/_javascript_s/fckeditor/';
+    oFCKeditor.Config['CustomConfigurationsPath'] = '/_javascript_s/fckcustom.js';
+    oFCKeditor.ReplaceTextarea();
+  }
+}
+
+function deleteDataSet(i) {
+  var data_sets = saveDataSets();
+  data_sets.splice(i, 1);
+  renderDataSets(data_sets);
+}
+
+function addDataSet() {
+  var data_sets = saveDataSets();
+  data_sets.push( { "title" : "", "desc" : "", "inputs" : [], "outputs" : [] } );
+  renderDataSets(data_sets);
+}
+
+function addDataItem(type, s) {
+  var data_sets = saveDataSets();
+  data_sets[s][type].push( { "label" : "", "data" : "" } );
+  renderDataSets(data_sets);
+}
+
+function deleteDataItem(type, s, i) {
+  var data_sets = saveDataSets();
+  data_sets[s][type].splice(i, 1);
+  renderDataSets(data_sets);
+}
+

Modified: branches/datasets/public/stylesheets/styles.css (2798 => 2799)


--- branches/datasets/public/stylesheets/styles.css	2011-11-10 14:18:07 UTC (rev 2798)
+++ branches/datasets/public/stylesheets/styles.css	2011-11-10 14:35:11 UTC (rev 2799)
@@ -2077,6 +2077,78 @@
   padding-top: 1em;
 }
 
+/* Data set form */
+
+.form {
+  background: #e8e8e8;
+  width: 566px;
+  padding: 6px;
+  border: 1px solid #d0d0d0;
+margin-top: 1em;
+margin-bottom: 1em;
+}
+
+.form-triple {
+  margin-top: 0.2em;
+  margin-bottom: 0.2em;
+}
+
+.form-triple * {
+  display: inline-block;
+  vertical-align: top;
+}
+
+.form-label {
+  width: 100px;
+}
+
+.form-data,
+.dataset-title,
+.dataset-description,
+.dataset-io-data,
+.dataset_io-description {
+  width: 400px;
+}
+
+.dataset-description,
+.dataset-io-data,
+.dataset_io-description {
+  height: 80px;
+}
+
+TABLE.dataset-table {
+  margin-top: 1.0em;
+  margin-bottom: 0.5em;
+  border-collapse: collapse;
+}
+
+TABLE.dataset-table TH {
+  color: white;
+  background: gray;
+  border: 1px solid gray;
+}
+
+TABLE.dataset-table TH,
+TABLE.dataset-table TD {
+  text-align: left;
+  vertical-align: top;
+  padding: 4px;
+}
+
+TABLE.dataset-table .label,
+TABLE.dataset-table .data {
+  background: #d0d0d0;
+  border: 1px solid gray;
+}
+
+.dataset-io-label {
+  width: 88px;
+}
+
+.delete-data-set {
+  float: right;
+}
+
 /* Styles Related to topics */
 
 table.topic {

reply via email to

[Prev in Thread] Current Thread [Next in Thread]