Переглянути джерело

HUE-1055 [jobsub] Support design properties

added is_shared and parameters (oozie properties).
Abraham Elmahrek 12 роки тому
батько
коміт
ef9ebeb

+ 51 - 6
apps/jobsub/src/jobsub/templates/designs.mako

@@ -1,4 +1,3 @@
-## Licensed to Cloudera, Inc. under one
 ## or more contributor license agreements.  See the NOTICE file
 ## distributed with this work for additional information
 ## regarding copyright ownership.  Cloudera, Inc. licenses this file
@@ -50,7 +49,7 @@ ${ commonheader(_('Job Designer'), "jobsub", user, "60px") | n,unicode }
       <button id="submit-design" class="btn" title="${_('Submit')}" data-bind="enable: selectedDesignObjects().length == 1"><i class="icon-play"></i> ${_('Submit')}</button>
       <button id="edit-design" class="btn" title="${_('Edit')}" data-bind="enable: selectedDesignObjects().length == 1 && window.location.hash.substring(0,12) != '#edit-design'"><i class="icon-pencil"></i> ${_('Edit')}</button>
       <button id="delete-designs" class="btn" title="${_('Delete')}" data-bind="enable: selectedDesignObjects().length > 0"><i class="icon-trash"></i> ${_('Delete')}</button>
-      <button id="clone-designs" class="btn" title="${_('Clone')}" data-bind="enable: selectedDesignObjects().length > 0"><i class="icon-share"></i> ${_('Clone')}</button>
+      <button id="copy-designs" class="btn" title="${_('Copy')}" data-bind="enable: selectedDesignObjects().length > 0"><i class="icon-retweet"></i> ${_('Copy')}</button>
     </%def>
 
     <%def name="creation()">
@@ -111,6 +110,7 @@ ${ commonheader(_('Job Designer'), "jobsub", user, "60px") | n,unicode }
           <th>${_('Description')}</th>
           <th>${_('Owner')}</th>
           <th>${_('Type')}</th>
+          <th>${_('Status')}</th>
           <th>${_('Last modified')}</th>
         </tr>
       </thead>
@@ -131,6 +131,14 @@ ${ commonheader(_('Job Designer'), "jobsub", user, "60px") | n,unicode }
     <td data-bind="click: function(data, event) { window.location = '#edit-design/' + $index() }, text: description"></td>
     <td data-bind="click: function(data, event) { window.location = '#edit-design/' + $index() }, text: owner"></td>
     <td data-bind="click: function(data, event) { window.location = '#edit-design/' + $index() }, text: node_type"></td>
+    <td data-bind="click: function(data, event) { window.location = '#edit-design/' + $index() }">
+      <!-- ko if: is_shared -->
+        <span class="label label-info">shared</span>
+      <!-- /ko -->
+      <!-- ko ifnot: is_shared -->
+        <span class="label label-info">personal</span>
+      <!-- /ko -->
+    </td>
     <td data-bind="click: function(data, event) { window.location = '#edit-design/' + $index() }, text: new Date(last_modified() * 1000).format('%B %d, %Y %I:%M %p'), attr: { 'data-sort-value': last_modified() }"></td>
   </tr>
 </script>
@@ -164,6 +172,8 @@ ${ commonheader(_('Job Designer'), "jobsub", user, "60px") | n,unicode }
 </div>
 
 <script type="text/javascript" charset="utf-8">
+var AUTOCOMPLETE_PROPERTIES;
+
 $(document).bind('initialize.designs', function() {
   var designTable, viewModel;
 
@@ -243,11 +253,42 @@ $(document).ready(function() {
     },
     name: {
       name: "${ _('Name') }",
-      popover: "${ _('Name of the design.') }"
+      popover: "${ _('Name of the design.') }",
+      js: {
+        name: 'name'
+      }
     },
     description: {
       name: "${ _('Description') }",
-      popover: "${ _('Description of the design.') }"
+      popover: "${ _('Description of the design.') }",
+      js: {
+        name: 'description'
+      }
+    },
+    is_shared: {
+      name: "${ _('Is shared') }",
+      popover: "${ _('Enable other users to have access to this job.') }",
+      js: {
+        name: 'is_shared'
+      }
+    },
+    parameters: {
+      title: "${ _('Oozie parameters') }",
+      name: "${ _('Name') }",
+      value: "${ _('Value') }",
+      delete: {
+        name: "${ _('Delete') }",
+        func: 'function(data, event) { $parent.removeParameter.call($parent, data, event) }'
+      },
+      add: {
+        name: "${ _('Add') }",
+        func: 'addParameter'
+      },
+      ko: {
+        items: "parameters",
+        error_class: "parameters_error_class",
+        condition: "parameters_condition"
+      }
     },
     user: {
       name: "${ _('User') }",
@@ -690,12 +731,16 @@ $(document).ready(function() {
   $('#delete-designs').click(function() {
     $('#deleteWf').modal('show');
   });
-  $('#clone-designs').click(function() {
+  $('#copy-designs').click(function() {
     designs.cloneDesigns();
   });
   $('#home').click(function() {
     routie('list-designs');
-  })
+  });
+  // load the autocomplete properties
+  $.getJSON("${ url('oozie:autocomplete_properties') }", function (properties) {
+    AUTOCOMPLETE_PROPERTIES = properties;
+  });
 });
 </script>
 

+ 20 - 7
apps/jobsub/src/jobsub/views.py

@@ -78,7 +78,8 @@ def list_designs(request):
           'description': design.description,
           'node_type': design.start.get_child('to').node_type,
           'last_modified': py_time.mktime(design.last_modified.timetuple()),
-          'editable': design.owner.id == request.user.id
+          'editable': design.owner.id == request.user.id,
+          'is_shared': design.is_shared
       }
       designs.append(ko_design)
 
@@ -129,7 +130,9 @@ def get_design(request, design_id):
   node = workflow.start.get_child('to')
   node_dict = model_to_dict(node)
   node_dict['id'] = design_id
+  node_dict['is_shared'] = workflow.is_shared
   node_dict['editable'] = workflow.owner.id == request.user.id
+  node_dict['parameters'] = workflow.parameters
   return render_json(node_dict, js_safe=True);
 
 
@@ -144,9 +147,18 @@ def save_design(request, design_id):
     raise StructuredException(code="INVALID_REQUEST_ERROR", message=_('Error saving design'), data={'errors': form.errors}, error_code=400)
 
   data = format_dict_field_values(request.POST.copy())
+  _save_design(design_id, data)
+
+  return get_design(request, design_id);
+
+
+def _save_design(design_id, data):
   sanitize_node_dict(data)
+  workflow = _get_design(design_id)
   workflow.name = data['name']
-  workflow.description = data['description']
+  workflow.description = data.setdefault('description', '')
+  workflow.is_shared = str(data.setdefault('is_shared', 'true')).lower() == "true"
+  workflow.parameters = data.setdefault('parameters', '[]')
   node = workflow.start.get_child('to').get_full_node()
   node_id = node.id
   for key in data:
@@ -156,9 +168,6 @@ def save_design(request, design_id):
   node.save()
   workflow.save()
 
-  data['id'] = workflow.id
-  return render_json(data);
-
 
 def new_design(request, node_type):
   """
@@ -187,13 +196,17 @@ def new_design(request, node_type):
   action.save()
   workflow.start.add_node(action)
   action.add_node(workflow.end)
+
+  # Action form validates name and description.
   workflow.name = request.POST.get('name')
   workflow.description = request.POST.get('description')
   workflow.save()
 
+  # Save design again to update all fields.
   data = format_dict_field_values(request.POST.copy())
-  data['id'] = workflow.id
-  return render_json(data)
+  _save_design(workflow.id, data)
+
+  return get_design(request, workflow.id)
 
 
 def clone_design(request, design_id):

+ 5 - 1
apps/jobsub/static/css/jobsub.css

@@ -1,3 +1,7 @@
 li.error {
-	list-style: none;
+  list-style: none;
+}
+a.advanced, a.advanced:link, a.advanced:hover {
+  color: black;
+  text-decoration: none;
 }

+ 42 - 24
apps/jobsub/static/js/jobsub.js

@@ -175,30 +175,48 @@ function addFileBrowseButton() {
 }
 
 //// Event handling.
-$(document).bind('add.file.workflow', addFileBrowseButton);
-$(document).bind('remove.file.workflow', addFileBrowseButton);
-$(document).bind('add.property.workflow', addFileBrowseButton);
-$(document).bind('remove.property.workflow', addFileBrowseButton);
-$(document).bind('add.archive.workflow', addFileBrowseButton);
-$(document).bind('remove.archive.workflow', addFileBrowseButton);
-$(document).bind('add.arg.workflow', addFileBrowseButton);
-$(document).bind('add.argument.workflow', addFileBrowseButton);
-$(document).bind('add.envvar.workflow', addFileBrowseButton);
-$(document).bind('add.param.workflow', addFileBrowseButton);
-$(document).bind('remove.param.workflow', addFileBrowseButton);
-$(document).bind('add.prepare_delete.workflow', addFileBrowseButton);
-$(document).bind('add.prepare_mkdir.workflow', addFileBrowseButton);
-$(document).bind('remove.prepare.workflow', addFileBrowseButton);
-$(document).bind('add.delete.workflow', addFileBrowseButton);
-$(document).bind('remove.delete.workflow', addFileBrowseButton);
-$(document).bind('add.mkdir.workflow', addFileBrowseButton);
-$(document).bind('remove.mkdir.workflow', addFileBrowseButton);
-$(document).bind('add.chmod.workflow', addFileBrowseButton);
-$(document).bind('remove.chmod.workflow', addFileBrowseButton);
-$(document).bind('add.move.workflow', addFileBrowseButton);
-$(document).bind('remove.move.workflow', addFileBrowseButton);
-$(document).bind('add.touchz.workflow', addFileBrowseButton);
-$(document).bind('remove.touchz.workflow', addFileBrowseButton);
+var events = [
+  'add.file.workflow',
+  'add.property.workflow',
+  'add.archive.workflow',
+  'add.arg.workflow',
+  'add.argument.workflow',
+  'add.envvar.workflow',
+  'add.param.workflow',
+  'add.prepare_delete.workflow',
+  'add.prepare_mkdir.workflow',
+  'add.delete.workflow',
+  'add.mkdir.workflow',
+  'add.chmod.workflow',
+  'add.move.workflow',
+  'add.touchz.workflow',
+  'add.parameter.workflow',
+  'remove.file.workflow',
+  'remove.property.workflow',
+  'remove.archive.workflow',
+  'remove.arg.workflow',
+  'remove.argument.workflow',
+  'remove.envvar.workflow',
+  'remove.param.workflow',
+  'remove.prepare_delete.workflow',
+  'remove.prepare_mkdir.workflow',
+  'remove.delete.workflow',
+  'remove.mkdir.workflow',
+  'remove.chmod.workflow',
+  'remove.move.workflow',
+  'remove.touchz.workflow',
+  'remove.parameter.workflow',
+  'error.design'
+]
+$.each(events, function(index, event) {
+  $(document).bind(event, addFileBrowseButton);
+  $(document).bind(event, function() {
+    $(".propKey").typeahead({
+      source:(typeof AUTOCOMPLETE_PROPERTIES != 'undefined') ? AUTOCOMPLETE_PROPERTIES : []
+    });
+  });
+});
+
 $(document).bind('error.design', addFileBrowseButton);
 $(document).bind('save.design', function() {designs.load();});
 $(document).bind('delete.design', function() {designs.load();});

+ 63 - 3
apps/jobsub/static/js/jobsub.ko.js

@@ -53,10 +53,49 @@ var Design = (function($, ko, NodeFields) {
       }
 
       // @see http://knockoutjs.com/documentation/plugins-mapping.html
-      // MAPPING_OPTIONS comes from /oozie/static/js/models.js
+      // MAPPING_OPTIONS comes from /oozie/static/js/workflow.models.js
       // We don't update the observed object using ko.mapping because
       // the plugin does not work with mixed objects.
-      ko.mapping.fromJS(self.model, MAPPING_OPTIONS, self);
+      ko.mapping.fromJS(self.model, $.extend({
+        is_shared: {
+          create: function(options) {
+            return ko.observable(($.type(options.data) == "string") ? value.toLowerCase() == "true" : new Boolean(options.data).valueOf());
+          },
+          update: function(options) {
+            return ($.type(options.data) == "string") ? value.toLowerCase() == "true" : new Boolean(options.data);
+          }
+        },
+        parameters: {
+          // Will receive individual objects to subscribe.
+          // Containing array is mapped automagically
+          create: function(options) {
+            var parent = options.parent;
+            var subscribe = function(mapping) {
+              mapping.name.subscribe(function(value) {
+                parent.parameters.valueHasMutated();
+              });
+              mapping.value.subscribe(function(value) {
+                parent.parameters.valueHasMutated();
+              });
+            };
+
+            return map_params(options, subscribe);
+          },
+          update: function(options) {
+            var parent = options.parent;
+            var subscribe = function(mapping) {
+              mapping.name.subscribe(function(value) {
+                parent.parameters.valueHasMutated();
+              });
+              mapping.value.subscribe(function(value) {
+                parent.parameters.valueHasMutated();
+              });
+            };
+
+            return map_params(options, subscribe);
+          }
+        }
+      }, MAPPING_OPTIONS), self);
 
       // hack on '<key>ErrorClass' and '<key>Condition'.
       $.each(self.__ko_mapping__, function(key, enabled) {
@@ -157,6 +196,25 @@ var Design = (function($, ko, NodeFields) {
         }
       }, options);
       this.request('/jobsub/designs/' + self.id() + '/delete', options);
+    },
+
+    // More node field methods
+    addParameter: function(data) {
+      var self = this;
+      var prop = { name: ko.observable(""), value: ko.observable("") };
+      prop.name.subscribe(function(value) {
+        self.parameters.valueHasMutated();
+      });
+      prop.value.subscribe(function(value) {
+        self.parameters.valueHasMutated();
+      });
+      self.parameters.push(prop);
+      $(document).trigger('add.parameter.workflow', [data]);
+    },
+    removeParameter: function(data) {
+      var self = this;
+      self.parameters.remove(data);
+      $(document).trigger('remove.parameter.workflow', [data]);
     }
   });
 
@@ -310,7 +368,9 @@ var Designs = (function($, ko, NodeModelChooser) {
       var self = this;
       var design = self.createDesign({
         id: null,
-        node_type: node_type
+        node_type: node_type,
+        is_shared: true,
+        parameters: '[{"name":"oozie.use.system.libpath","value":"true"}]'
       });
       // Reversing the order of the next two statements may cause KO to break.
       self.temporary().template(node_type);

+ 5 - 0
apps/jobsub/static/js/jobsub.templates.js

@@ -37,6 +37,11 @@ var Templates = (function($, ko) {
         distcp: 'static/templates/actions/distcp.html',
       },
       partials: {
+        name: 'static/templates/widgets/text.html',
+        description: 'static/templates/widgets/text.html',
+        is_shared: 'static/templates/widgets/checkbox.html',
+        // Oozie parameters
+        parameters: 'static/templates/widgets/parameters.html',
         archives: 'static/templates/widgets/filechooser.html',
         files: 'static/templates/widgets/filechooser.html',
         mkdirs: 'static/templates/widgets/filechooser.html',

+ 22 - 16
apps/jobsub/static/templates/actions/distcp.html

@@ -2,24 +2,30 @@
   <h1>{{ title }}</h1>
   <form class="form-horizontal" id="workflowForm" action="#list-designs" method="POST">
     <fieldset>
-      <div class="control-group" rel="popover" data-original-title="{{ name.name }}" data-content="{{ name.popover }}" data-bind="attr: {'class': ( errors.name().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ name.name }}</label>
-        <div class="controls">
-          <input id="distcp-name" type="text" name="name" data-bind="value: name" />
-          <ul class="help-inline" data-bind="foreach: errors.name()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+      {{#name}}
+        {{>name}}
+      {{/name}}
+
+      {{#description}}
+        {{>description}}
+      {{/description}}
+
+      <div class="control-group ">
+        <label class="control-label">
+          <a href="javascript:void(0);" onclick="$('div.advanced').toggle('hide')" class="advanced">
+            <i class="icon-share-alt"></i>
+            advanced
+          </a>
+        </label>
       </div>
+      <div class="advanced hide">
+        {{#is_shared}}
+          {{>is_shared}}
+        {{/is_shared}}
 
-      <div class="control-group" rel="popover" data-original-title="{{ description.name }}" data-content="{{ description.popover }}" data-bind="attr: {'class': ( errors.description().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ description.name }}</label>
-        <div class="controls">
-          <input id="distcp-description" type="text" name="description" data-bind="value: description" />
-          <ul class="help-inline" data-bind="foreach: errors.description()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+        {{#parameters}}
+          {{>parameters}}
+        {{/parameters}}
       </div>
 
       <hr/>

+ 22 - 16
apps/jobsub/static/templates/actions/email.html

@@ -2,24 +2,30 @@
   <h1>{{ title }}</h1>
   <form class="form-horizontal" id="workflowForm" action="#list-designs" method="POST">
     <fieldset>
-      <div class="control-group" rel="popover" data-original-title="{{ name.name }}" data-content="{{ name.popover }}" data-bind="attr: {'class': ( errors.name().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ name.name }}</label>
-        <div class="controls">
-          <input id="email-name" type="text" name="name" data-bind="value: name" />
-          <ul class="help-inline" data-bind="foreach: errors.name()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+      {{#name}}
+        {{>name}}
+      {{/name}}
+
+      {{#description}}
+        {{>description}}
+      {{/description}}
+
+      <div class="control-group ">
+        <label class="control-label">
+          <a href="javascript:void(0);" onclick="$('div.advanced').toggle('hide')" class="advanced">
+            <i class="icon-share-alt"></i>
+            advanced
+          </a>
+        </label>
       </div>
+      <div class="advanced hide">
+        {{#is_shared}}
+          {{>is_shared}}
+        {{/is_shared}}
 
-      <div class="control-group" rel="popover" data-original-title="{{ description.name }}" data-content="{{ description.popover }}" data-bind="attr: {'class': ( errors.description().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ description.name }}</label>
-        <div class="controls">
-          <input id="email-description" type="text" name="description" data-bind="value: description" />
-          <ul class="help-inline" data-bind="foreach: errors.description()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+        {{#parameters}}
+          {{>parameters}}
+        {{/parameters}}
       </div>
 
       <hr/>

+ 23 - 17
apps/jobsub/static/templates/actions/fs.html

@@ -2,24 +2,30 @@
   <h1>{{ title }}</h1>
   <form class="form-horizontal" id="workflowForm" action="#list-designs" method="POST">
     <fieldset>
-      <div class="control-group" rel="popover" data-original-title="{{ name.name }}" data-content="{{ name.popover }}" data-bind="attr: {'class': ( errors.name().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ name.name }}</label>
-        <div class="controls">
-          <input id="fs-name" type="text" name="name" data-bind="value: name" />
-          <ul class="help-inline" data-bind="foreach: errors.name()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+      {{#name}}
+        {{>name}}
+      {{/name}}
+
+      {{#description}}
+        {{>description}}
+      {{/description}}
+
+      <div class="control-group ">
+        <label class="control-label">
+          <a href="javascript:void(0);" onclick="$('div.advanced').toggle('hide')" class="advanced">
+            <i class="icon-share-alt"></i>
+            advanced
+          </a>
+        </label>
       </div>
-
-      <div class="control-group" rel="popover" data-original-title="{{ description.name }}" data-content="{{ description.popover }}" data-bind="attr: {'class': ( errors.description().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ description.name }}</label>
-        <div class="controls">
-          <input id="fs-description" type="text" name="description" data-bind="value: description" />
-          <ul class="help-inline" data-bind="foreach: errors.description()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+      <div class="advanced hide">
+        {{#is_shared}}
+          {{>is_shared}}
+        {{/is_shared}}
+
+        {{#parameters}}
+          {{>parameters}}
+        {{/parameters}}
       </div>
 
       <hr/>

+ 22 - 16
apps/jobsub/static/templates/actions/hive.html

@@ -2,24 +2,30 @@
   <h1>{{ title }}</h1>
   <form class="form-horizontal" id="workflowForm" action="#list-designs" method="POST">
     <fieldset>
-      <div class="control-group" rel="popover" data-original-title="{{ name.name }}" data-content="{{ name.popover }}" data-bind="attr: {'class': ( errors.name().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ name.name }}</label>
-        <div class="controls">
-          <input id="hive-name" type="text" name="name" data-bind="value: name" />
-          <ul class="help-inline" data-bind="foreach: errors.name()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+      {{#name}}
+        {{>name}}
+      {{/name}}
+
+      {{#description}}
+        {{>description}}
+      {{/description}}
+
+      <div class="control-group ">
+        <label class="control-label">
+          <a href="javascript:void(0);" onclick="$('div.advanced').toggle('hide')" class="advanced">
+            <i class="icon-share-alt"></i>
+            advanced
+          </a>
+        </label>
       </div>
+      <div class="advanced hide">
+        {{#is_shared}}
+          {{>is_shared}}
+        {{/is_shared}}
 
-      <div class="control-group" rel="popover" data-original-title="{{ description.name }}" data-content="{{ description.popover }}" data-bind="attr: {'class': ( errors.description().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ description.name }}</label>
-        <div class="controls">
-          <input id="hive-description" type="text" name="description" data-bind="value: description" />
-          <ul class="help-inline" data-bind="foreach: errors.description()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+        {{#parameters}}
+          {{>parameters}}
+        {{/parameters}}
       </div>
 
       <hr/>

+ 22 - 16
apps/jobsub/static/templates/actions/java.html

@@ -2,24 +2,30 @@
   <h1>{{ title }}</h1>
   <form class="form-horizontal" id="workflowForm" action="#list-designs" method="POST">
     <fieldset>
-      <div class="control-group" rel="popover" data-original-title="{{ name.name }}" data-content="{{ name.popover }}" data-bind="attr: {'class': ( errors.name().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ name.name }}</label>
-        <div class="controls">
-          <input id="java-name" type="text" name="name" data-bind="value: name" />
-          <ul class="help-inline" data-bind="foreach: errors.name()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+      {{#name}}
+        {{>name}}
+      {{/name}}
+
+      {{#description}}
+        {{>description}}
+      {{/description}}
+
+      <div class="control-group ">
+        <label class="control-label">
+          <a href="javascript:void(0);" onclick="$('div.advanced').toggle('hide')" class="advanced">
+            <i class="icon-share-alt"></i>
+            advanced
+          </a>
+        </label>
       </div>
+      <div class="advanced hide">
+        {{#is_shared}}
+          {{>is_shared}}
+        {{/is_shared}}
 
-      <div class="control-group" rel="popover" data-original-title="{{ description.name }}" data-content="{{ description.popover }}" data-bind="attr: {'class': ( errors.description().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ description.name }}</label>
-        <div class="controls">
-          <input id="java-description" type="text" name="description" data-bind="value: description" />
-          <ul class="help-inline" data-bind="foreach: errors.description()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+        {{#parameters}}
+          {{>parameters}}
+        {{/parameters}}
       </div>
 
       <hr/>

+ 22 - 16
apps/jobsub/static/templates/actions/mapreduce.html

@@ -2,24 +2,30 @@
   <h1>{{ title }}</h1>
   <form class="form-horizontal" id="workflowForm" action="#list-designs" method="POST">
     <fieldset>
-      <div class="control-group" rel="popover" data-original-title="{{ name.name }}" data-content="{{ name.popover }}" data-bind="attr: {'class': ( errors.name().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ name.name }}</label>
-        <div class="controls">
-          <input id="mapreduce-name" type="text" name="name" data-bind="value: name" />
-          <ul class="help-inline" data-bind="foreach: errors.name()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+      {{#name}}
+        {{>name}}
+      {{/name}}
+
+      {{#description}}
+        {{>description}}
+      {{/description}}
+
+      <div class="control-group ">
+        <label class="control-label">
+          <a href="javascript:void(0);" onclick="$('div.advanced').toggle('hide')" class="advanced">
+            <i class="icon-share-alt"></i>
+            advanced
+          </a>
+        </label>
       </div>
+      <div class="advanced hide">
+        {{#is_shared}}
+          {{>is_shared}}
+        {{/is_shared}}
 
-      <div class="control-group" rel="popover" data-original-title="{{ description.name }}" data-content="{{ description.popover }}" data-bind="attr: {'class': ( errors.description().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ description.name }}</label>
-        <div class="controls">
-          <input id="mapreduce-description" type="text" name="description" data-bind="value: description" />
-          <ul class="help-inline" data-bind="foreach: errors.description()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+        {{#parameters}}
+          {{>parameters}}
+        {{/parameters}}
       </div>
 
       <hr/>

+ 22 - 16
apps/jobsub/static/templates/actions/pig.html

@@ -2,24 +2,30 @@
   <h1>{{ title }}</h1>
   <form class="form-horizontal" id="workflowForm" action="#list-designs" method="POST">
     <fieldset>
-      <div class="control-group" rel="popover" data-original-title="{{ name.name }}" data-content="{{ name.popover }}" data-bind="attr: {'class': ( errors.name().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ name.name }}</label>
-        <div class="controls">
-          <input id="pig-name" type="text" name="name" data-bind="value: name" />
-          <ul class="help-inline" data-bind="foreach: errors.name()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+      {{#name}}
+        {{>name}}
+      {{/name}}
+
+      {{#description}}
+        {{>description}}
+      {{/description}}
+
+      <div class="control-group ">
+        <label class="control-label">
+          <a href="javascript:void(0);" onclick="$('div.advanced').toggle('hide')" class="advanced">
+            <i class="icon-share-alt"></i>
+            advanced
+          </a>
+        </label>
       </div>
+      <div class="advanced hide">
+        {{#is_shared}}
+          {{>is_shared}}
+        {{/is_shared}}
 
-      <div class="control-group" rel="popover" data-original-title="{{ description.name }}" data-content="{{ description.popover }}" data-bind="attr: {'class': ( errors.description().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ description.name }}</label>
-        <div class="controls">
-          <input id="pig-description" type="text" name="description" data-bind="value: description" />
-          <ul class="help-inline" data-bind="foreach: errors.description()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+        {{#parameters}}
+          {{>parameters}}
+        {{/parameters}}
       </div>
 
       <hr/>

+ 22 - 16
apps/jobsub/static/templates/actions/shell.html

@@ -2,24 +2,30 @@
   <h1>{{ title }}</h1>
   <form class="form-horizontal" id="workflowForm" action="#list-designs" method="POST">
     <fieldset>
-      <div class="control-group" rel="popover" data-original-title="{{ name.name }}" data-content="{{ name.popover }}" data-bind="attr: {'class': ( errors.name().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ name.name }}</label>
-        <div class="controls">
-          <input id="shell-name" type="text" name="name" data-bind="value: name" />
-          <ul class="help-inline" data-bind="foreach: errors.name()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+      {{#name}}
+        {{>name}}
+      {{/name}}
+
+      {{#description}}
+        {{>description}}
+      {{/description}}
+
+      <div class="control-group ">
+        <label class="control-label">
+          <a href="javascript:void(0);" onclick="$('div.advanced').toggle('hide')" class="advanced">
+            <i class="icon-share-alt"></i>
+            advanced
+          </a>
+        </label>
       </div>
+      <div class="advanced hide">
+        {{#is_shared}}
+          {{>is_shared}}
+        {{/is_shared}}
 
-      <div class="control-group" rel="popover" data-original-title="{{ description.name }}" data-content="{{ description.popover }}" data-bind="attr: {'class': ( errors.description().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ description.name }}</label>
-        <div class="controls">
-          <input id="shell-description" type="text" name="description" data-bind="value: description" />
-          <ul class="help-inline" data-bind="foreach: errors.description()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+        {{#parameters}}
+          {{>parameters}}
+        {{/parameters}}
       </div>
 
       <hr/>

+ 22 - 16
apps/jobsub/static/templates/actions/sqoop.html

@@ -2,24 +2,30 @@
   <h1>{{ title }}</h1>
   <form class="form-horizontal" id="workflowForm" action="#list-designs" method="POST">
     <fieldset>
-      <div class="control-group" rel="popover" data-original-title="{{ name.name }}" data-content="{{ name.popover }}" data-bind="attr: {'class': ( errors.name().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ name.name }}</label>
-        <div class="controls">
-          <input id="sqoop-name" type="text" name="name" data-bind="value: name" />
-          <ul class="help-inline" data-bind="foreach: errors.name()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+      {{#name}}
+        {{>name}}
+      {{/name}}
+
+      {{#description}}
+        {{>description}}
+      {{/description}}
+
+      <div class="control-group ">
+        <label class="control-label">
+          <a href="javascript:void(0);" onclick="$('div.advanced').toggle('hide')" class="advanced">
+            <i class="icon-share-alt"></i>
+            advanced
+          </a>
+        </label>
       </div>
+      <div class="advanced hide">
+        {{#is_shared}}
+          {{>is_shared}}
+        {{/is_shared}}
 
-      <div class="control-group" rel="popover" data-original-title="{{ description.name }}" data-content="{{ description.popover }}" data-bind="attr: {'class': ( errors.description().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ description.name }}</label>
-        <div class="controls">
-          <input id="sqoop-description" type="text" name="description" data-bind="value: description" />
-          <ul class="help-inline" data-bind="foreach: errors.description()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+        {{#parameters}}
+          {{>parameters}}
+        {{/parameters}}
       </div>
 
       <hr/>

+ 22 - 16
apps/jobsub/static/templates/actions/ssh.html

@@ -2,24 +2,30 @@
   <h1>{{ title }}</h1>
   <form class="form-horizontal" id="workflowForm" action="#list-designs" method="POST">
     <fieldset>
-      <div class="control-group" rel="popover" data-original-title="{{ name.name }}" data-content="{{ name.popover }}" data-bind="attr: {'class': ( errors.name().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ name.name }}</label>
-        <div class="controls">
-          <input id="ssh-name" type="text" name="name" data-bind="value: name" />
-          <ul class="help-inline" data-bind="foreach: errors.name()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+      {{#name}}
+        {{>name}}
+      {{/name}}
+
+      {{#description}}
+        {{>description}}
+      {{/description}}
+
+      <div class="control-group ">
+        <label class="control-label">
+          <a href="javascript:void(0);" onclick="$('div.advanced').toggle('hide')" class="advanced">
+            <i class="icon-share-alt"></i>
+            advanced
+          </a>
+        </label>
       </div>
+      <div class="advanced hide">
+        {{#is_shared}}
+          {{>is_shared}}
+        {{/is_shared}}
 
-      <div class="control-group" rel="popover" data-original-title="{{ description.name }}" data-content="{{ description.popover }}" data-bind="attr: {'class': ( errors.description().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ description.name }}</label>
-        <div class="controls">
-          <input id="ssh-description" type="text" name="description" data-bind="value: description" />
-          <ul class="help-inline" data-bind="foreach: errors.description()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+        {{#parameters}}
+          {{>parameters}}
+        {{/parameters}}
       </div>
 
       <hr/>

+ 22 - 16
apps/jobsub/static/templates/actions/streaming.html

@@ -2,24 +2,30 @@
   <h1>{{ title }}</h1>
   <form class="form-horizontal" id="workflowForm" action="#list-designs" method="POST">
     <fieldset>
-      <div class="control-group" rel="popover" data-original-title="{{ name.name }}" data-content="{{ name.popover }}" data-bind="attr: {'class': ( errors.name().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ name.name }}</label>
-        <div class="controls">
-          <input id="streaming-name" type="text" name="name" data-bind="value: name" />
-          <ul class="help-inline" data-bind="foreach: errors.name()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+      {{#name}}
+        {{>name}}
+      {{/name}}
+
+      {{#description}}
+        {{>description}}
+      {{/description}}
+
+      <div class="control-group ">
+        <label class="control-label">
+          <a href="javascript:void(0);" onclick="$('div.advanced').toggle('hide')" class="advanced">
+            <i class="icon-share-alt"></i>
+            advanced
+          </a>
+        </label>
       </div>
+      <div class="advanced hide">
+        {{#is_shared}}
+          {{>is_shared}}
+        {{/is_shared}}
 
-      <div class="control-group" rel="popover" data-original-title="{{ description.name }}" data-content="{{ description.popover }}" data-bind="attr: {'class': ( errors.description().length > 0 ) ? 'control-group error' : 'control-group'}">
-        <label class="control-label">{{ description.name }}</label>
-        <div class="controls">
-          <input id="streaming-description" type="text" name="description" data-bind="value: description" />
-          <ul class="help-inline" data-bind="foreach: errors.description()">
-            <li class="error" data-bind="html: $data"></li>
-          </ul>
-        </div>
+        {{#parameters}}
+          {{>parameters}}
+        {{/parameters}}
       </div>
 
       <hr/>

+ 2 - 0
apps/jobsub/static/templates/designs.html

@@ -6,6 +6,7 @@
       <th>{{ description }}</th>
       <th>{{ owner }}</th>
       <th>{{ type }}</th>
+      <th>{{ status }}</th>
       <th>{{ last_modified }}</th>
     </tr>
   </thead>
@@ -18,6 +19,7 @@
       <td data-bind="text: description"></td>
       <td data-bind="text: owner"></td>
       <td data-bind="text: type"></td>
+      <td data-bind="text: is_shared"></td>
       <td data-sort-value="${time.mktime(design.mtime.timetuple())}" data-bind="text: last_modified"></td>
     </tr>
   </tbody>

+ 6 - 0
apps/jobsub/static/templates/widgets/checkbox.html

@@ -0,0 +1,6 @@
+<div class="control-group" rel="popover" data-original-title="{{ name }}" data-content="{{ popover }}">
+  <label class="control-label">{{ name }}</label>
+  <div class="controls">
+    <input type="checkbox" name="{{ js.name }}" id="{{ js.name }}" data-bind="checked: {{ js.name }}" />
+  </div>
+</div>

+ 22 - 0
apps/jobsub/static/templates/widgets/parameters.html

@@ -0,0 +1,22 @@
+<div class="control-group" data-bind="attr: {'class': {{ ko.error_class }} }">
+  <label class="control-label">{{ title }}</label>
+  <div class="controls">
+    <table class="table-condensed designTable" data-bind="if: {{ ko.condition }}">
+      <thead>
+        <tr>
+          <th>{{ name }}</th>
+          <th>{{ value }}</th>
+          <th />
+        </tr>
+      </thead>
+      <tbody data-bind="foreach: {{ ko.items }}">
+        <tr>
+          <td><input type="text" class="span3 required propKey" data-bind="value: name, uniqueName: false" /></td>
+          <td><input type="text" class="span4 required" data-bind="value: value, uniqueName: false" /></td>
+          <td><a class="btn btn-small" href="javascript:void(0);" data-bind="click: {{ delete.func }}">{{ delete.name }}</a></td>
+        </tr>
+      </tbody>
+    </table>
+    <button class="btn" data-bind="click: {{ add.func }}">{{ add.name }}</button>
+  </div>
+</div>

+ 9 - 0
apps/jobsub/static/templates/widgets/text.html

@@ -0,0 +1,9 @@
+<div class="control-group" rel="popover" data-original-title="{{ name }}" data-content="{{ popover }}" data-bind="attr: {'class': ( errors.{{ js.name }}().length > 0 ) ? 'control-group error' : 'control-group'}">
+  <label class="control-label">{{ name }}</label>
+  <div class="controls">
+    <input id="{{ js.name }}" type="text" name="{{ js.name }}" data-bind="value: {{ js.name }}" />
+    <ul class="help-inline" data-bind="foreach: errors.{{ js.name }}()">
+      <li class="error" data-bind="html: $data"></li>
+    </ul>
+  </div>
+</div>