Эх сурвалжийг харах

HUE-851 [oozie] Simplify Coordinator page

Changed to wizard style
Introduced Routie.js
Removed modals, flattened editing experience
Fixed edit dataset HTTP 500
Fixed jHueRowSelector bug on href=javascript:void(0)
Fixed jHueNotify bug on pages that scroll
Enrico Berti 13 жил өмнө
parent
commit
3a69395

+ 1 - 1
apps/oozie/src/oozie/decorators.py

@@ -35,7 +35,7 @@ from jobsub.models import OozieDesign
 from liboozie.submittion import Submission
 
 from oozie.models import Job, Workflow, Node, Link, History, Coordinator,\
-  Mapreduce, Java, Streaming, Pig, Hive, Sqoop, Ssh, Shell, DistCp, Decision
+  Mapreduce, Java, Streaming, Pig, Hive, Sqoop, Ssh, Shell, DistCp, Decision, Dataset
 from oozie.forms import NodeForm, WorkflowForm, CoordinatorForm, DatasetForm,\
   DefaultLinkForm, design_form_by_type, ImportJobsubDesignForm, ParameterForm
 

+ 2 - 2
apps/oozie/src/oozie/forms.py

@@ -313,10 +313,10 @@ TIME_FORMAT = '%I:%M %p'
 
 class CoordinatorForm(forms.ModelForm):
   start = forms.SplitDateTimeField(input_time_formats=[TIME_FORMAT],
-                                   widget=SplitDateTimeWidget(attrs={'class': 'short', 'id': 'coordinator_start'},
+                                   widget=SplitDateTimeWidget(attrs={'class': 'input-small', 'id': 'coordinator_start'},
                                                               date_format=DATE_FORMAT, time_format=TIME_FORMAT))
   end = forms.SplitDateTimeField(input_time_formats=[TIME_FORMAT],
-                                 widget=SplitDateTimeWidget(attrs={'class': 'short', 'id': 'coordinator_end'},
+                                 widget=SplitDateTimeWidget(attrs={'class': 'input-small', 'id': 'coordinator_end'},
                                                             date_format=DATE_FORMAT, time_format=TIME_FORMAT))
 
   class Meta:

+ 8 - 4
apps/oozie/src/oozie/templates/editor/coordinator_properties.mako

@@ -21,7 +21,7 @@
 <%namespace name="utils" file="../../utils.inc.mako" />
 
 
-<%def name="print_key_value(field, element, initial_value)">
+<%def name="print_key_value(field, element)">
   <div class="control-group ko-${element}" rel="popover"
       data-original-title="${ field.label }" data-content="${ field.help_text }">
     <label class="control-label">${ field.label }</label>
@@ -60,6 +60,10 @@
     }
   </style>
 
+</%def>
+
+<%def name="init_viewmodel(element, initial_value)">
+
   <script type="text/javascript">
     $(document).ready(function(){
       var ViewModel = function(${ element }) {
@@ -78,9 +82,9 @@
           var form = $("#jobForm");
 
           $("<input>").attr("type", "hidden")
-              .attr("name", "${ element }")
-              .attr("value", ko.utils.stringifyJson(self.${ element }))
-              .appendTo(form);
+                  .attr("name", "${ element }")
+                  .attr("value", ko.utils.stringifyJson(self.${ element }))
+                  .appendTo(form);
 
           form.submit();
         };

+ 181 - 67
apps/oozie/src/oozie/templates/editor/create_coordinator.mako

@@ -25,94 +25,208 @@
 ${ commonheader(_("Oozie App"), "oozie", user, "100px") }
 ${ layout.menubar(section='coordinators') }
 
+<style>
+  .steps {
+    min-height: 350px;
+    margin-top: 10px;
+  }
+  .nav {
+    margin-bottom: 0;
+  }
+  .help-block {
+    color: #999999;
+  }
+</style>
 
 <script src="/static/ext/js/knockout-2.1.0.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/ext/js/routie-0.3.0.min.js" type="text/javascript" charset="utf-8"></script>
 
 
 <div class="container-fluid">
-    <h1>${ _('Coordinator') } ${ coordinator.name }</h1>
+  <h1>${ _('Coordinator') } ${ coordinator.name }</h1>
 
-    <div class="well">
-      % if coordinator.workflow:
-      <br/>
-        ${ _('Workflow') }: <a href="${ coordinator.workflow.get_absolute_url() }">${ coordinator.workflow }</a>
-      % endif
-    </div>
+  <div class="row-fluid">
+    <div class="span2">
+      <div class="well sidebar-nav">
+        <ul class="nav nav-list">
+          <li class="nav-header">${ _('Name') }</li>
+          <li id="coordinatorName">${ _('Please choose one') }</li>
 
-  <form class="form-horizontal" id="workflowForm" action="${ url('oozie:create_coordinator') }" method="POST">
-
-    <div class="row-fluid">
-        <div class="span2"></div>
-
-        <div class="span8">
-           <h2>${ _('Coordinator') }</h2>
-           <div class="fieldWrapper">
-             ${ utils.render_field(coordinator_form['name']) }
-             ${ utils.render_field(coordinator_form['description']) }
-             ${ utils.render_field(coordinator_form['workflow']) }
-             ${ coordinator_form['parameters'] }
-             <div class="hide">
-               ${ utils.render_field(coordinator_form['timeout']) }
-               ${ coordinator_form['schema_version'] }
-             </div>
-           </div>
-
-          <hr/>
-          <h2>${ _('Frequency') }</h2>
-
-          <div class="fieldWrapper">
-            <div class="row-fluid">
-              <div class="span6">
-              ${ utils.render_field(coordinator_form['frequency_number']) }
-            </div>
-            <div class="span6">
-              ${ utils.render_field(coordinator_form['frequency_unit']) }
+          <li class="nav-header">${ _('Workflow') }</li>
+          <li id="workflowName">${ _('Please choose one') }</li>
+
+         </ul>
+        </div>
+    </div>
+    <div class="span10">
+      <ul class="nav nav-pills">
+        <li class="active"><a href="#step1" class="step">${ _('Step 1: Details') }</a></li>
+        <li><a href="#step2" class="step">${ _('Step 2: Frequency') }</a></li>
+        <li><a href="#step3" class="step">${ _('Step 3: Inputs') }</a></li>
+        <li><a href="#step4" class="step">${ _('Step 4: Outputs') }</a></li>
+        <li><a href="#step5" class="step">${ _('Step 5: Advanced settings') }</a></li>
+      </ul>
+      <form class="form-horizontal" action="${ url('oozie:create_coordinator') }" method="POST">
+
+        <div class="steps">
+
+          <div id="step1" class="stepDetails">
+            <div class="alert alert-info"><h3>${ _('Coordinator data') }</h3></div>
+            <div class="fieldWrapper">
+              ${ utils.render_field_no_popover(coordinator_form['name'], extra_attrs = {'validate':'true'}) }
+              ${ utils.render_field_no_popover(coordinator_form['description']) }
+              ${ utils.render_field_no_popover(coordinator_form['workflow'], extra_attrs = {'validate':'true'}) }
+              ${ coordinator_form['parameters'] }
+              <div class="hide">
+                ${ utils.render_field(coordinator_form['timeout']) }
+                     ${ coordinator_form['schema_version'] }
+              </div>
             </div>
           </div>
-        </div>
 
-        <div class="fieldWrapper">
-          <div class="row-fluid">
-            <div class="span6">
-              ${ utils.render_field(coordinator_form['start']) }
+          <div id="step2" class="stepDetails hide">
+            <div class="alert alert-info"><h3>${ _('Frequency') }</h3></div>
+            <div class="fieldWrapper">
+              <div class="row-fluid">
+                <div class="span6">
+                  ${ utils.render_field_no_popover(coordinator_form['frequency_number']) }
+                </div>
+                <div class="span6">
+                  ${ utils.render_field_no_popover(coordinator_form['frequency_unit']) }
+                </div>
+              </div>
             </div>
-            <div class="span6">
-              ${ utils.render_field(coordinator_form['end']) }
-             </div>
+            <div class="fieldWrapper">
+              <div class="row-fluid">
+                <div class="span6">
+                  ${ utils.render_field_no_popover(coordinator_form['start']) }
+                </div>
+                <div class="span6">
+                  ${ utils.render_field_no_popover(coordinator_form['end']) }
+                </div>
+              </div>
+              ${ utils.render_field_no_popover(coordinator_form['timezone']) }
             </div>
-            ${ utils.render_field(coordinator_form['timezone']) }
           </div>
+
         </div>
-        <div class="span2"></div>
-    </div>
 
-    <div class="form-actions center">
-      <button data-bind="click: submit" class="btn btn-primary">${ _('Save') }</button>
-      <a class="btn" onclick="history.back()">${ _('Back') }</a>
-    </div>
+        <div class="form-actions">
+          <a id="backBtn" class="btn disabled">${ _('Back') }</a>
+          <a id="nextBtn" class="btn btn-primary">${ _('Next') }</a>
+        </div>
 
-  </form>
+      </form>
+    </div>
 
+  </div>
 </div>
 
-
-<link rel="stylesheet" href="/static/ext/css/jquery-ui-datepicker-1.8.23.css" type="text/css" media="screen" title="no title" charset="utf-8" />
-<link rel="stylesheet" href="/static/ext/css/jquery-timepicker.css" type="text/css" media="screen" title="no title" charset="utf-8" />
-
-<script src="/static/ext/js/jquery/plugins/jquery-ui-datepicker-1.8.23.min.js" type="text/javascript" charset="utf-8"></script>
-<script src="/static/ext/js/jquery/plugins/jquery-timepicker.min.js" type="text/javascript" charset="utf-8"></script>
-
 <script type="text/javascript" charset="utf-8">
-  $(document).ready(function(){
-    var timeOptions = {
-      show24Hours: false,
-      startTime: '00:00',
-      endTime: '23:59',
-      step: 60
-    };
-    $( "input.date" ).datepicker();
-    $( "input.time" ).timePicker(timeOptions);
+  $(document).ready(function () {
+
+    var currentStep = "step1";
+
+    routie({
+      "step1":function () {
+        showStep("step1");
+      },
+      "step2":function () {
+        if (validateStep("step1")) {
+          showStep("step2");
+        }
+        else {
+          routie("step1");
+        }
+      },
+      "step3":function () {
+        if (validateStep("step1") && validateStep("step2")) {
+          $("form").submit();
+        }
+      },
+      "step4":function () {
+        if (validateStep("step1") && validateStep("step2")) {
+          $("form").submit();
+        }
+      },
+      "step5":function () {
+        if (validateStep("step1") && validateStep("step2")) {
+          $("form").submit();
+        }
+      },
+      "submit":function () {
+        if (validateStep("step1") && validateStep("step2")) {
+          $("form").submit();
+        }
+        else {
+          routie("");
+        }
+      }
+    });
+
+    function showStep(step) {
+      currentStep = step;
+      if (step != "step1") {
+        $("#backBtn").removeClass("disabled");
+      }
+      else {
+        $("#backBtn").addClass("disabled");
+      }
+      if (step != $(".stepDetails:last").attr("id")) {
+        $("#nextBtn").removeClass("disabled");
+      }
+      else {
+        $("#nextBtn").addClass("disabled");
+      }
+      $("a.step").parent().removeClass("active");
+      $("a.step[href=#" + step + "]").parent().addClass("active");
+      $(".stepDetails").hide();
+      $("#" + step).show();
+    }
+
+    function validateStep(step) {
+      var proceed = true;
+      $("#" + step).find("[validate=true]").each(function () {
+        if ($(this).val().trim() == "") {
+          proceed = false;
+          $(this).parents(".control-group").addClass("error");
+          $(this).parent().find(".help-inline").remove();
+          $(this).after("<span class=\"help-inline\"><strong>${ _('This field is required.') }</strong></span>");
+        }
+      });
+      return proceed;
+    }
+
+    $("#backBtn").click(function () {
+      var nextStep = (currentStep.substr(4) * 1 - 1);
+      if (nextStep >= 1) {
+        routie("step" + nextStep);
+      }
+    });
+
+    $("#nextBtn").click(function () {
+      var nextStep = (currentStep.substr(4) * 1 + 1);
+      if (nextStep <= $(".step").length) {
+        routie("step" + nextStep);
+      }
+    });
+
+    $("[validate=true]").change(function () {
+      $(this).parents(".control-group").removeClass("error");
+      $(this).parent().find(".help-inline").remove();
+    });
+
+    $("#id_name").change(function () {
+      $("#coordinatorName").text($(this).val());
+    });
+
+    $("#id_workflow").change(function () {
+      $("#workflowName").text($("#id_workflow option[value='" + $(this).val() + "']").text());
+    });
+
   });
 </script>
 
+${ utils.decorate_datetime_fields() }
+
 ${commonfooter(messages)}

+ 8 - 8
apps/oozie/src/oozie/templates/editor/create_coordinator_dataset.mako

@@ -24,15 +24,15 @@
 
 
 <fieldset>
-  ${ utils.render_field(dataset_form['name']) }
-  ${ utils.render_field(dataset_form['description']) }
-  ${ utils.render_field(dataset_form['start']) }
+  ${ utils.render_field_no_popover(dataset_form['name']) }
+  ${ utils.render_field_no_popover(dataset_form['description']) }
+  ${ utils.render_field_no_popover(dataset_form['start']) }
   <div class="row-fluid">
     <div class="span6">
-      ${ utils.render_field(dataset_form['frequency_number']) }
+      ${ utils.render_field_no_popover(dataset_form['frequency_number']) }
     </div>
     <div class="span6">
-      ${ utils.render_field(dataset_form['frequency_unit']) }
+      ${ utils.render_field_no_popover(dataset_form['frequency_unit']) }
     </div>
   </div>
 
@@ -46,8 +46,8 @@
     % endfor
     .
   </div>
-  ${ utils.render_field(dataset_form['uri']) }
+  ${ utils.render_field_no_popover(dataset_form['uri']) }
 
-  ${ utils.render_field(dataset_form['timezone']) }
-  ${ utils.render_field(dataset_form['done_flag']) }
+  ${ utils.render_field_no_popover(dataset_form['timezone']) }
+  ${ utils.render_field_no_popover(dataset_form['done_flag']) }
 </fieldset>

+ 591 - 408
apps/oozie/src/oozie/templates/editor/edit_coordinator.mako

@@ -27,489 +27,672 @@
 ${ commonheader(_("Oozie App"), "oozie", user, "100px") }
 ${ layout.menubar(section='coordinators') }
 
+<style>
+  .steps {
+    min-height: 350px;
+    margin-top: 10px;
+  }
+  #add-dataset-form, #edit-dataset-form {
+    display: none;
+  }
+  .nav {
+    margin-bottom: 0;
+  }
+  .help-block {
+    color: #999999;
+  }
+</style>
+
+<script src="/static/ext/js/knockout-2.1.0.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/ext/js/routie-0.3.0.min.js" type="text/javascript" charset="utf-8"></script>
+
 
 <div class="container-fluid">
   <h1>${ _('Coordinator') } ${ coordinator.name }</h1>
 
-  <div class="well">
-    ${ _('Description') }: ${ coordinator.description or _("N/A") }
-    % if coordinator.workflow:
-    <br/>
-      ${ _('Workflow') }: <a href="${ coordinator.workflow.get_absolute_url() }">${ coordinator.workflow }</a>
-    % endif
-  </div>
+  <div class="row-fluid">
+    <div class="span2">
+      <div class="well sidebar-nav">
+        <ul class="nav nav-list">
+          <li class="nav-header">${ _('Name') }</li>
+          <li><a id="coordinatorName" href="#steps">${ coordinator.name }</a></li>
 
-  <ul class="nav nav-tabs">
-    <li class="active"><a href="#editor" data-toggle="tab">${ _('Editor') }</a></li>
-    <li><a href="#datasets" data-toggle="tab">${ _('Datasets') }</a></li>
-    % if coordinator.is_editable(user):
-      <li><a href="#history" data-toggle="tab">${ _('History') }</a></li>
-    % endif
-  </ul>
-
-  <form class="form-horizontal" id="jobForm" action="${ url('oozie:edit_coordinator', coordinator=coordinator.id) }" method="POST">
-    <div class="tab-content">
-      <div class="tab-pane active" id="editor">
-        <div class="row-fluid">
-          <div class="span2">
-          </div>
-          <div class="span8">
-             <h2>${ _('Coordinator') }</h2>
-             <div class="fieldWrapper">
-               ${ utils.render_field(coordinator_form['name']) }
-               ${ utils.render_field(coordinator_form['description']) }
-
-               <div class="control-group ">
-                 <label class="control-label">
-                   <a href="#" id="advanced-btn" onclick="$('#advanced-container').toggle('hide')">
-                     <i class="icon-share-alt"></i> ${ _('advanced') }
-                   </a>
-                 </label>
-                 <div class="controls"></div>
-               </div>
-
-               <div id="advanced-container" class="hide">
-                 ${ utils.render_field(coordinator_form['is_shared']) }
-                 ${ utils.render_field(coordinator_form['workflow']) }
-                 ${ properties.print_key_value(coordinator_form['parameters'], 'parameters', parameters) }
-                 ${ utils.render_field(coordinator_form['timeout']) }
-                 <div class="row-fluid">
-                   <div class="span6">
-                     ${ utils.render_field(coordinator_form['concurrency']) }
-                   </div>
-                   <div class="span6">
-                     ${ utils.render_field(coordinator_form['throttle']) }
-                   </div>
-                 </div>
-                 ${ utils.render_field(coordinator_form['execution']) }
-                 ${ coordinator_form['schema_version'] }
-              </div>
-             </div>
+          % if coordinator.workflow:
+            <li class="nav-header">${ _('Workflow') }</li>
+            <li id="workflowName"><a href="${ coordinator.workflow.get_absolute_url() }" target="_blank">${ coordinator.workflow }</a></li>
+          % endif
 
-            <hr/>
-            <h2>${ _('Frequency') }</h2>
+          <li class="nav-header">${ _('Datasets') }</li>
+          % if coordinator.is_editable(user):
+          <li><a href="#createDataset">${ _('Create new') }</a></li>
+          % endif
+          <li><a href="#listDataset">${ _('Show existing') }</a></li>
+
+          % if coordinator.is_editable(user):
+              <li class="nav-header">${ _('History') }</li>
+              <li><a href="#listHistory">${ _('Show history') }</a></li>
+          % endif
 
+        </ul>
+      </div>
+    </div>
+    <div class="span10">
+      <form id="jobForm" class="form-horizontal" action="${ url('oozie:edit_coordinator', coordinator=coordinator.id) }" method="POST">
+      <div id="steps" class="section">
+        <ul class="nav nav-pills">
+          <li class="active"><a href="#step1" class="step">${ _('Step 1: General') }</a></li>
+          <li><a href="#step2" class="step">${ _('Step 2: Frequency') }</a></li>
+          <li><a href="#step3" class="step">${ _('Step 3: Inputs') }</a></li>
+          <li><a href="#step4" class="step">${ _('Step 4: Outputs') }</a></li>
+          <li><a href="#step5" class="step">${ _('Step 5: Advanced settings') }</a></li>
+        </ul>
+        ${ dataset_formset.management_form }
+        ${ data_input_formset.management_form }
+        ${ data_output_formset.management_form }
+        ${ properties.init_viewmodel('parameters', parameters) }
+        <div class="steps">
+
+          <div id="step1" class="stepDetails">
+            <div class="alert alert-info"><h3>${ _('Coordinator data') }</h3></div>
+            <div class="fieldWrapper">
+              ${ utils.render_field_no_popover(coordinator_form['name'], extra_attrs = {'validate':'true'}) }
+              ${ utils.render_field_no_popover(coordinator_form['description']) }
+              ${ utils.render_field_no_popover(coordinator_form['workflow'], extra_attrs = {'validate':'true'}) }
+              ${ coordinator_form['parameters'] }
+              <div class="hide">
+                ${ utils.render_field(coordinator_form['timeout']) }
+                ${ coordinator_form['schema_version'] }
+              </div>
+            </div>
+          </div>
+
+          <div id="step2" class="stepDetails hide">
+            <div class="alert alert-info"><h3>${ _('Frequency') }</h3></div>
             <div class="fieldWrapper">
               <div class="row-fluid">
                 <div class="span6">
-                  ${ utils.render_field(coordinator_form['frequency_number']) }
+                ${ utils.render_field_no_popover(coordinator_form['frequency_number']) }
                 </div>
                 <div class="span6">
-                  ${ utils.render_field(coordinator_form['frequency_unit']) }
+                ${ utils.render_field_no_popover(coordinator_form['frequency_unit']) }
                 </div>
               </div>
             </div>
-
             <div class="fieldWrapper">
               <div class="row-fluid">
-                 <div class="span6">
-                ${ utils.render_field(coordinator_form['start']) }
-              </div>
-              <div class="span6">
-                 ${ utils.render_field(coordinator_form['end']) }
+                <div class="span6">
+                ${ utils.render_field_no_popover(coordinator_form['start']) }
+                </div>
+                <div class="span6">
+                ${ utils.render_field_no_popover(coordinator_form['end']) }
+                </div>
               </div>
+            ${ utils.render_field_no_popover(coordinator_form['timezone']) }
             </div>
-              ${ utils.render_field(coordinator_form['timezone']) }
           </div>
 
-          ${ dataset_formset.management_form }
-          ${ data_input_formset.management_form }
-          ${ data_output_formset.management_form }
-
-          % if coordinator.id:
-            <hr/>
-            <h2>Data</h2>
-            <br/>
-            <p>
-              % if coordinator.workflow:
-                ${ _('The inputs and outputs of the workflow must be mapped to some data.') }
-                ${ _('The data is represented by some datasets that can be created on the ') }
-                <a href="#" id="datasets-btn" class="btn">${ _('Datasets') }</a> ${ _('page') }.
-              % endif
-            </p>
-            </br>
-            <div class="row-fluid">
-              <h3>${ _('Inputs') }</h3>
-
-              % if data_input_formset.forms:
-                <table class="table table-striped table-condensed" cellpadding="0" cellspacing="0" data-missing="#dataset_input_missing">
-                  <thead>
-                    <tr>
-                      <th width="10%">${ _('Name') }</th>
-                      <th width="10%">${ _('Dataset') }</th>
-                      <th>${ _('Path') }</th>
-                      % if coordinator.is_editable(user):
-                        <th width="1%">${ _('Delete') }</th>
-                      % endif
-                    </tr>
-                  </thead>
-                  <tbody>
-                    % for form in data_input_formset.forms:
-                      <tr>
-                         ${ form['id'] }
-                         <td>${ form['name'] }</td>
-                         <td>${ form['dataset'] }</td>
-                         <td>${ form['dataset'].form.instance.dataset.uri }</td>
-                         % if coordinator.is_editable(user):
-                           <td><a class="btn btn-small delete-row" href="javascript:void(0);">${ _('Delete') }${ form['DELETE'] }</a></td>
-                         % endif
-                      </tr>
-                    % endfor
-                  </tbody>
-                </table>
-              % endif
-              <br/>
-              <div id="dataset_input_missing" data-missing-bind="true" class="alert alert-error
-                % if data_input_formset.forms:
-                  hide
-                % endif
-              ">
-                ${ _('No inputs') }
+          <div id="step3" class="stepDetails hide">
+            % if coordinator.workflow:
+              <div class="alert alert-info"><h3>${ _('Inputs') }</h3>
+              ${ _('The inputs and outputs of the workflow must be mapped to some data.') }
+              ${ _('The data is represented by some datasets that can be created ') }<a href="#createDataset" class="btn btn-small">${ _('here') }</a>.
               </div>
-
-              % if coordinator.is_editable(user):
-                ${ coordinator_data.print_datasets(_('Datasets'), 'dataset_input', new_data_input_formset, 'input', not len(data_input_formset.forms)) }
-              % endif
-            </div>
-
-            <br/>
-            <br/>
-            <br/>
-
-            <div class="row-fluid">
-              <h3>${ _('Outputs') }</h3>
-              % if data_output_formset.forms:
-              <table class="table table-striped table-condensed" cellpadding="0" cellspacing="0" data-missing="#dataset_output_missing">
+            % else:
+              <div class="alert alert-info"><h3>${ _('Inputs') }</h3></div>
+              <div class="alert">${ _('This type of coordinator does not require any dataset.') }</div>
+            % endif
+            % if data_input_formset.forms:
+              <table class="table table-striped table-condensed" cellpadding="0" cellspacing="0" data-missing="#dataset_input_missing">
                 <thead>
-                  <tr>
-                    <th width="10%">${ _('Name') }</th>
-                    <th width="10%">${ _('Dataset') }</th>
-                    <th>${ _('Path') }</th>
-                    % if coordinator.is_editable(user):
-                      <th width="1%">${ _('Delete') }</th>
-                    % endif
-                  </tr>
+                <tr>
+                  <th width="10%">${ _('Name') }</th>
+                  <th width="10%">${ _('Dataset') }</th>
+                  <th>${ _('Path') }</th>
+                % if coordinator.is_editable(user):
+                  <th width="1%">${ _('Delete') }</th>
+                % endif
+                </tr>
                 </thead>
                 <tbody>
-                  % for form in data_output_formset.forms:
-                    <tr>
-                      ${ form['id'] }
-                      <td>${ form['name'] }</td>
-                      <td>${ form['dataset'] }</td>
-                      <td>${ form['dataset'].form.instance.dataset.uri }</td>
-                      % if coordinator.is_editable(user):
-                        <td><a class="btn btn-small delete-row" href="javascript:void(0);">${ _('Delete') }${ form['DELETE'] }</a></td>
-                      % endif
-                    </tr>
-                  % endfor
+                % for form in data_input_formset.forms:
+                <tr>
+                ${ form['id'] }
+                  <td>${ form['name'] }</td>
+                  <td>${ form['dataset'] }</td>
+                  <td>${ form['dataset'].form.instance.dataset.uri }</td>
+                % if coordinator.is_editable(user):
+                  <td><a class="btn btn-small delete-row" href="javascript:void(0);">${ _('Delete') }${ form['DELETE'] }</a></td>
+                % endif
+                </tr>
+                % endfor
                 </tbody>
               </table>
-              % endif
-              <br/>
-              <div id="dataset_output_missing" data-missing-bind="true" class="alert alert-error
-                % if data_output_formset.forms:
-                  hide
-                % endif
-              ">
-                ${ _('No outputs') }
-              </div>
-
-              % if coordinator.is_editable(user):
-                ${ coordinator_data.print_datasets(_('Datasets'), 'dataset_output', new_data_output_formset, 'output', not len(data_output_formset.forms)) }
-              % endif
+            % endif
+            <br/>
+            <%
+              klass = "alert alert-error"
+              if data_input_formset.forms:
+                klass += " hide"
+            %>
+            <div id="dataset_input_missing" data-missing-bind="true" class="${klass}">
+              ${ _('There are currently no defined inputs.') }
             </div>
-          % endif
-        </div>
-      </div>
-    </div>
 
-    <div class="tab-pane" id="datasets">
-      <div class="row-fluid">
-          <div class="span1">
             % if coordinator.is_editable(user):
-              <table cellpadding="5">
-                <thead>
-                  <tr>
-                    <th>${ _('Add a new dataset') }</th>
-                  </tr>
-                </thead>
-                <tbody>
+              ${ coordinator_data.print_datasets(_('Datasets'), 'dataset_input', new_data_input_formset, 'input', not len(data_input_formset.forms)) }
+            % endif
+          </div>
+
+          <div id="step4" class="stepDetails hide">
+            % if coordinator.workflow:
+              <div class="alert alert-info"><h3>${ _('Outputs') }</h3>
+                ${ _('The inputs and outputs of the workflow must be mapped to some data.') }
+                ${ _('The data is represented by some datasets that can be created ') }<a href="#createDataset" class="btn btn-small">${ _('here') }</a>.
+              </div>
+            % else:
+              <div class="alert alert-info"><h3>${ _('Outputs') }</h3></div>
+              <div class="alert">${ _('This type of coordinator does not require any dataset.') }</div>
+            % endif
+
+            % if data_output_formset.forms:
+            <table class="table table-striped table-condensed" cellpadding="0" cellspacing="0" data-missing="#dataset_output_missing">
+              <thead>
+                <tr>
+                  <th width="10%">${ _('Name') }</th>
+                  <th width="10%">${ _('Dataset') }</th>
+                  <th>${ _('Path') }</th>
+                  % if coordinator.is_editable(user):
+                    <th width="1%">${ _('Delete') }</th>
+                  % endif
+                </tr>
+              </thead>
+              <tbody>
+                % for form in data_output_formset.forms:
                   <tr>
-                    <td><a class="btn" data-toggle="modal" href="#add-dataset-modal">${ _('Create') }</a></td>
+                    ${ form['id'] }
+                    <td>${ form['name'] }</td>
+                    <td>${ form['dataset'] }</td>
+                    <td>${ form['dataset'].form.instance.dataset.uri }</td>
+                    % if coordinator.is_editable(user):
+                      <td><a class="btn btn-small delete-row" href="javascript:void(0);">${ _('Delete') }${ form['DELETE'] }</a></td>
+                    % endif
                   </tr>
-                </tbody>
-              </table>
+                % endfor
+              </tbody>
+            </table>
+            % endif
+            <br/>
+            <%
+              klass = "alert alert-error"
+              if data_output_formset.forms:
+                klass += " hide"
+            %>
+            <div id="dataset_output_missing" data-missing-bind="true" class="${klass}">
+            ${ _('There are currently no defined outputs.') }
+            </div>
+
+            % if coordinator.is_editable(user):
+              ${ coordinator_data.print_datasets(_('Datasets'), 'dataset_output', new_data_output_formset, 'output', not len(data_output_formset.forms)) }
             % endif
           </div>
 
-          <div class="span9">
-            % if coordinator.id:
-              <div>
-                <table class="table table-striped table-condensed" cellpadding="0" cellspacing="0" data-missing="#dataset_missing">
-                  <thead>
-                    <tr>
-                      <th>${ _('Name') }</th>
-                      <th>${ _('Description') }</th>
-                      <th>${ _('Frequency') }</th>
-                      <th>${ _('Start') }</th>
-                      <th>${ _('URI') }</th>
-                      <th>${ _('Timezone') }</th>
-                      <th>${ _('Done flag') }</th>
-                      % if coordinator.is_editable(user):
-                        <th>${ _('Delete') }</th>
-                      % endif
-                    </tr>
-                  </thead>
-                  <tbody>
-                   % for form in dataset_formset.forms:
-                    % for hidden in form.hidden_fields():
-                      ${ hidden }
-                    % endfor
-                    <tr>
-                      <td>
-                        % if coordinator.is_editable(user):
-                          <a href="javascript:modalRequest('${ url('oozie:edit_coordinator_dataset', dataset=form.instance.id) }', '#edit-dataset-modal');"
-                             data-row-selector="true"/>
-                        % endif
-                        ${ form.instance.name }
-                      </td>
-                      <td>${ form.instance.description }</td>
-                      <td>${ form.instance.text_frequency }</td>
-                      <td>${ form.instance.start }</td>
-                      <td>${ form.instance.uri }</td>
-                      <td>${ form.instance.timezone }</td>
-                      <td>${ form.instance.done_flag }</td>
-                      % if coordinator.is_editable(user):
-                        <td data-row-selector-exclude="true">
-                          <a class="btn btn-small delete-row" href="javascript:void(0);">${ _('Delete') }${ form['DELETE'] }</a>
-                        </td>
-                      % endif
-                    </tr>
-
-                     <div class="hide">
-                       % for field in form.visible_fields():
-                          ${ field.errors }
-                          ${ field.label }: ${ field }
-                       % endfor
-                     </div>
-
-                   % endfor
-                  </tbody>
-                </table>
+          <div id="step5" class="stepDetails hide">
+            <div class="alert alert-info"><h3>${ _('Advanced settings') }</h3></div>
+            ${ utils.render_field_no_popover(coordinator_form['is_shared']) }
+            ${ properties.print_key_value(coordinator_form['parameters'], 'parameters') }
+            ${ utils.render_field_no_popover(coordinator_form['timeout']) }
+            <div class="row-fluid">
+              <div class="span6">
+                ${ utils.render_field_no_popover(coordinator_form['concurrency']) }
               </div>
-              <div id="dataset_missing" data-missing-bind="true" class="alert alert-error
-                % if dataset_formset.forms:
-                  hide
-                % endif
-              ">
-                ${ _('No datasets') }
+              <div class="span6">
+                ${ utils.render_field_no_popover(coordinator_form['throttle']) }
               </div>
-            % endif
+            </div>
+            ${ utils.render_field_no_popover(coordinator_form['execution']) }
+            ${ coordinator_form['schema_version'] }
           </div>
-       </div>
-    </div>
 
-    % if coordinator.is_editable(user):
-      <div class="tab-pane" id="history">
-        <table class="table">
-          <thead>
-            <tr>
-              <th>${ _('Date') }</th>
-              <th>${ _('Id') }</th>
-            </tr>
-          </thead>
-          <tbody>
-            % if not history:
-              <tr>
-                <td>${ _('N/A') }</td><td></td>
-              </tr>
-            % endif
-            % for record in history:
+        </div>
+
+        <div class="form-actions">
+          <a id="backBtn" class="btn disabled">${ _('Back') }</a>
+          <a id="nextBtn" class="btn btn-primary">${ _('Next') }</a>
+          % if coordinator.is_editable(user):
+            <a class="btn btn-primary save" data-bind="visible: isSaveVisible()" style="margin-left: 30px">${ _('Save coordinator') }</a>
+          % endif
+        </div>
+
+        </div>
+
+        <div id="createDataset" class="section hide">
+          <div class="alert alert-info"><h3>${ _('Create a new dataset') }</h3></div>
+          <div class="alert alert-warning"><b>${ _('Warning') }</b>: ${ _('Save your modifications before creating a new dataset.') }</div>
+          <div id="add-dataset-body">
+            <%include file="create_coordinator_dataset.mako"/>
+          </div>
+          <div class="form-actions">
+            <a href="#" class="btn btn-primary" id="add-dataset-btn">${ _('Create dataset') }</a>
+          </div>
+        </div>
+
+        <div id="editDataset" class="section hide">
+          <div class="alert alert-info"><h3>${ _('Edit dataset') }</h3></div>
+          <div class="alert alert-warning"><b>${ _('Warning') }</b>: ${ _('Save your modifications before editing a dataset.') }</div>
+          <div id="edit-dataset-body">
+          </div>
+          <div class="form-actions">
+            <a href="#" class="btn btn-primary" id="update-dataset-btn">${ _('Update dataset') }</a>
+            <a href="#listDataset" class="btn">${ _('Cancel') }</a>
+          </div>
+        </div>
+
+
+        <div id="listDataset" class="section hide">
+          <div class="alert alert-info"><h3>${ _('Existing datasets') }</h3></div>
+          % if coordinator.id:
+          <div>
+            % if dataset_formset.forms:
+            <table class="table table-striped table-condensed" cellpadding="0" cellspacing="0" data-missing="#dataset_missing">
+              <thead>
+                <tr>
+                  <th>${ _('Name') }</th>
+                  <th>${ _('Description') }</th>
+                  <th>${ _('Frequency') }</th>
+                  <th>${ _('Start') }</th>
+                  <th>${ _('URI') }</th>
+                  <th>${ _('Timezone') }</th>
+                  <th>${ _('Done flag') }</th>
+                  % if coordinator.is_editable(user):
+                    <th>${ _('Delete') }</th>
+                  % endif
+                </tr>
+              </thead>
+              <tbody>
+              % for form in dataset_formset.forms:
+                % for hidden in form.hidden_fields():
+                  ${ hidden }
+                % endfor
                 <tr>
                   <td>
-                    <a href="${ url('oozie:list_history_record', record_id=record.id) }" data-row-selector="true"></a>
-                    ${ utils.format_date(record.submission_date) }
+                  % if coordinator.is_editable(user):
+                    <a href="javascript:void(0)" class="editDataset" data-url="${ url('oozie:edit_coordinator_dataset', dataset=form.instance.id) }" data-row-selector="true"/>
+                  % endif
+                  ${ form.instance.name }
                   </td>
-                  <td>${ record.oozie_job_id }</td>
+                  <td>${ form.instance.description }</td>
+                  <td>${ form.instance.text_frequency }</td>
+                  <td>${ form.instance.start }</td>
+                  <td>${ form.instance.uri }</td>
+                  <td>${ form.instance.timezone }</td>
+                  <td>${ form.instance.done_flag }</td>
+                  % if coordinator.is_editable(user):
+                    <td data-row-selector-exclude="true">
+                      <a class="btn btn-small delete-row" href="javascript:void(0);">${ _('Delete') }${ form['DELETE'] }</a>
+                    </td>
+                  % endif
                 </tr>
-            % endfor
-          </tbody>
-        </table>
-      </div>
-    % endif
-
-    <br/>
-  </div>
 
-  <div class="form-actions center">
-    % if coordinator.is_editable(user):
-      <input class="btn btn-primary" data-bind="click: submit" type="submit" value="${ _('Save') }"></input>
-    % endif
-    <a href="${ url('oozie:list_coordinators') }" class="btn">${ _('Back') }</a>
-  </div>
+                <div class="hide">
+                  % for field in form.visible_fields():
+                  ${ field.errors }
+                  ${ field.label }: ${ field }
+                  % endfor
+                </div>
+              % endfor
+              </tbody>
+            </table>
+            % endif
+          </div>
+          <%
+            klass = "alert alert-error"
+            if dataset_formset.forms:
+              klass += " hide"
+          %>
+          <div id="dataset_missing" data-missing-bind="true" class="${klass}">
+            ${ _('There are currently no datasets.') } <a href="#createDataset">${ _('Do you want to create a new dataset ?') }</a>
+          </div>
+            % if dataset_formset.forms and coordinator.is_editable(user):
+            <div class="form-actions" style="padding-left:10px">
+              <a class="btn btn-primary save">${ _('Save coordinator') }</a>
+            </div>
+            % endif
+          % endif
+        </div>
 
-  </form>
+        <div id="listHistory" class="section hide">
+          <div class="alert alert-info"><h3>${ _('History') }</h3></div>
+          % if coordinator.is_editable(user):
+          <div class="tab-pane" id="history">
+            <table class="table">
+              <thead>
+              <tr>
+                <th>${ _('Date') }</th>
+                <th>${ _('Id') }</th>
+              </tr>
+              </thead>
+              <tbody>
+              % if not history:
+              <tr>
+                <td>${ _('N/A') }</td><td></td>
+              </tr>
+              % endif
+              % for record in history:
+              <tr>
+                <td>
+                  <a href="${ url('oozie:list_history_record', record_id=record.id) }" data-row-selector="true"></a>
+                ${ utils.format_date(record.submission_date) }
+                </td>
+                <td>${ record.oozie_job_id }</td>
+              </tr>
+              % endfor
+              </tbody>
+            </table>
+          </div>
+          % endif
+        </div>
 
-% if coordinator.id:
-  <div class="modal hide" id="add-dataset-modal" style="z-index:1500;width:850px">
-    <form class="form-horizontal" id="add-dataset-form">
-      <div class="modal-header">
-        <button class="close" data-dismiss="modal">&times;</button>
-        <h3>${ _('Create a dataset') }</h3>
-        <hr/>
-        <div class="alert alert-warning"><b>${ _('Warning') }</b>: ${ _('Save your modifications before creating a new dataset.') }</div>
-      </div>
+      </form>
 
-      <div class="modal-body" id="add-dataset-body">
-          <%include file="create_coordinator_dataset.mako"/>
-      </div>
+    </div>
 
-      <div class="modal-footer">
-        <a href="#" class="btn" data-dismiss="modal">${ _('Close') }</a>
-        <a href="#" class="btn btn-primary" id="add-dataset-btn">${ _('Add dataset') }</a>
-      </div>
-    </form>
   </div>
 
-  <div class="modal hide" id="edit-dataset-modal" style="z-index:1500;width:850px">
-
-  </div>
 </div>
 
-<style type="text/css">
-  .delete-row input {
-    display: none;
-  }
-</style>
 
-<link rel="stylesheet" href="/static/ext/css/jquery-ui-datepicker-1.8.23.css" type="text/css" media="screen" title="no title" charset="utf-8" />
-<link rel="stylesheet" href="/static/ext/css/jquery-timepicker.css" type="text/css" media="screen" title="no title" charset="utf-8" />
 
-<script src="/static/ext/js/jquery/plugins/jquery-ui-datepicker-1.8.23.min.js" type="text/javascript" charset="utf-8"></script>
-<script src="/static/ext/js/jquery/plugins/jquery-timepicker.min.js" type="text/javascript" charset="utf-8"></script>
-<script src="/static/ext/js/knockout-2.1.0.js" type="text/javascript" charset="utf-8"></script>
+<form class="form-horizontal" id="add-dataset-form"></form>
+<form class="form-horizontal" id="edit-dataset-form"></form>
 
-<script type="text/javascript" charset="utf-8">
-  var timeOptions = {
-    show24Hours: false,
-    startTime: '00:00',
-    endTime: '23:59',
-    step: 60
-  };
-
-  function modalRequest(url, el) {
-    $.ajax({
-         url: url,
-         beforeSend: function(xhr){
-             xhr.setRequestHeader("X-Requested-With", "Hue");
-         },
-         dataType: "html",
-         success: function(data){
-             $(el).html(data);
-             $(el).modal("show");
-             $("input.date").datepicker();
-             $("input.time").timePicker(timeOptions);
-         }
-     });
-  }
 
 
-  /**
-   * Initial state is used to define when to display the "initial state" of a table.
-   * IE: if there are no formset forms to display, show an "empty" message.
-   *
-   * First, we build a registry of all functions that need to pass in order for us to display the initial state.
-   * Things that 'remove' or 'add' elements will need to trigger 'reinit' and 'initOff' events on their respective 'initial state' elements.
-   * 'Initial state' elements should have 'data-missing-bind="true"' so that custom events can be binded to them.
-   *
-   * args:
-   *  test_func - function that, if true, will indicate that the initial state should be shown.
-   *  hook - If we do show the initial state, run this function before showing it.
-   */
-  var initialStateRegistry = {};
-
-  $("*[data-missing-bind='true']").on('register', function(e, test_func, hook) {
-    var id = $(this).attr('id');
-    if (!initialStateRegistry[id]) {
-      initialStateRegistry[id] = [];
-    }
-    initialStateRegistry[id].push({ test: test_func, hook: hook });
-  });
-
-  $("*[data-missing-bind='true']").on('reinit', function(e) {
-    var show = true;
-    var id = $(this).attr('id');
-    for (var i in initialStateRegistry[id]) {
-      show = show && initialStateRegistry[id][i].test();
+% if coordinator.id:
+
+  <div class="modal hide" id="edit-dataset-modal" style="z-index:1500;width:850px"></div>
+
+
+  <style type="text/css">
+    .delete-row input {
+      display: none;
     }
-    if (show) {
+  </style>
+
+  <script src="/static/ext/js/knockout-2.1.0.js" type="text/javascript" charset="utf-8"></script>
+
+  <script type="text/javascript" charset="utf-8">
+
+    /**
+     * Initial state is used to define when to display the "initial state" of a table.
+     * IE: if there are no formset forms to display, show an "empty" message.
+     *
+     * First, we build a registry of all functions that need to pass in order for us to display the initial state.
+     * Things that 'remove' or 'add' elements will need to trigger 'reinit' and 'initOff' events on their respective 'initial state' elements.
+     * 'Initial state' elements should have 'data-missing-bind="true"' so that custom events can be binded to them.
+     *
+     * args:
+     *  test_func - function that, if true, will indicate that the initial state should be shown.
+     *  hook - If we do show the initial state, run this function before showing it.
+     */
+    var initialStateRegistry = {};
+
+    $("*[data-missing-bind='true']").on('register', function (e, test_func, hook) {
+      var id = $(this).attr('id');
+      if (!initialStateRegistry[id]) {
+        initialStateRegistry[id] = [];
+      }
+      initialStateRegistry[id].push({ test:test_func, hook:hook });
+    });
+
+    $("*[data-missing-bind='true']").on('reinit', function (e) {
+      var show = true;
+      var id = $(this).attr('id');
       for (var i in initialStateRegistry[id]) {
-        if (!!initialStateRegistry[id][i].hook) {
-          initialStateRegistry[id][i].hook();
+        show = show && initialStateRegistry[id][i].test();
+      }
+      if (show) {
+        for (var i in initialStateRegistry[id]) {
+          if (!!initialStateRegistry[id][i].hook) {
+            initialStateRegistry[id][i].hook();
+          }
         }
+        $(this).show();
       }
-      $(this).show();
-    }
-  });
+    });
+
+    $("*[data-missing-bind='true']").on('initOff', function (e) {
+      $(this).hide();
+    });
 
-  $("*[data-missing-bind='true']").on('initOff', function(e) {
-    $(this).hide();
-  });
 
+    $(document).ready(function () {
+
+      % if not coordinator.is_editable(user):
+        $("#jobForm input, select").attr("disabled", "disabled");
+        $("#jobForm .btn").not("#nextBtn, #backBtn").attr("disabled", "disabled").addClass("btn-disabled");
+      % endif
+
+      $("#datasets-btn").click(function () {
+        $('[href=#datasets]').tab('show');
+      });
+
+      $('#add-dataset-btn').click(function () {
+        $("#add-dataset-form").empty();
+        $("#add-dataset-body").find("input, select").each(function () {
+          $(this).clone().appendTo($("#add-dataset-form"));
+        });
+        $.post("${ url('oozie:create_coordinator_dataset', coordinator=coordinator.id) }",
+                $("#add-dataset-form").serialize(),
+                function (response) {
+                  if (response['status'] != 0) {
+                    $("#add-dataset-form").empty();
+                    $('#add-dataset-body').html(response['data']);
+                    decorateDateTime();
+                  } else {
+                    window.location.replace(response['data']);
+                    window.location.reload();
+                  }
+                }
+        );
+      });
+
+      $(".editDataset").click(function () {
+        var el = $(this);
+        $("#edit-dataset-body").data("url", el.data("url"));
+        $.ajax({
+          url:el.data("url"),
+          beforeSend:function (xhr) {
+            xhr.setRequestHeader("X-Requested-With", "Hue");
+          },
+          dataType:"json",
+          success:function (response) {
+            $("#edit-dataset-body").html(response['data']);
+            decorateDateTime();
+            routie("editDataset");
+          }
+        });
+      });
+
+      $('#update-dataset-btn').click(function () {
+        $("#edit-dataset-form").empty();
+        $("#edit-dataset-body").find("input, select").each(function () {
+          $(this).clone().appendTo($("#edit-dataset-form"));
+        });
+        $.post($("#edit-dataset-body").data("url"),
+                $("#edit-dataset-form").serialize(),
+                function (response) {
+                  if (response['status'] != 0) {
+                    $("#edit-dataset-form").empty();
+                    $('#edit-dataset-body').html(response['data']);
+                    decorateDateTime();
+                  } else {
+                    window.location.replace(response['data']);
+                    window.location.reload();
+                  }
+                }
+        );
+      });
+
+      $('.delete-row').click(function () {
+        var el = $(this);
+        var row = el.closest('tr');
+        var table = el.closest('table');
+        el.find(':input').attr('checked', 'checked');
+        row.hide();
+        $(table.attr('data-missing')).trigger('reinit', table);
+      });
+
+      $('.delete-row').closest('table').each(function () {
+        var table = $(this);
+        var id = table.attr('data-missing');
+        if (!!id) {
+          $(id).trigger('register', [ function () {
+            return table.find('tbody tr').length == table.find('tbody tr:hidden').length;
+          }, function () {
+            table.hide();
+          } ]);
+        }
+      });
 
-  $(document).ready(function() {
-    $("input.date").datepicker();
-    $("input.time").timePicker(timeOptions);
+      $("a[data-row-selector='true']").jHueRowSelector();
 
-    $("#datasets-btn").click(function() {
-      $('[href=#datasets]').tab('show');
-    });
+      window.viewModel.isSaveVisible = ko.observable(false);
+      ko.applyBindings(window.viewModel);
 
-    $('#add-dataset-btn').click(function() {
-      $.post("${ url('oozie:create_coordinator_dataset', coordinator=coordinator.id) }",
-        $("#add-dataset-form").serialize(),
-        function(response) {
-          if (response['status'] != 0) {
-            $('#add-dataset-body').html(response['data']);
-          } else {
-            window.location.replace(response['data']);
+      $("*[rel=popover]").popover({
+        placement:'top',
+        trigger:'hover'
+      });
+
+      var currentStep = "step1";
+
+      routie({
+        "step1":function () {
+          showStep("step1");
+          window.viewModel.isSaveVisible(false);
+        },
+        "step2":function () {
+          if (validateStep("step1")) {
+            showStep("step2");
+            window.viewModel.isSaveVisible(false);
+          }
+        },
+        "step3":function () {
+          if (validateStep("step1") && validateStep("step2")) {
+            showStep("step3");
+            window.viewModel.isSaveVisible(false);
+          }
+        },
+        "step4":function () {
+          if (validateStep("step1") && validateStep("step2")) {
+            showStep("step4");
+            window.viewModel.isSaveVisible(true);
+          }
+        },
+        "step5":function () {
+          if (validateStep("step1") && validateStep("step2")) {
+            showStep("step5");
+            window.viewModel.isSaveVisible(true);
+          }
+        },
+        "steps":function () {
+          showSection("steps");
+        },
+        "createDataset":function () {
+          showSection("createDataset");
+        },
+        "editDataset":function () {
+          if ($("#edit-dataset-body").children().length > 0) {
+            showSection("editDataset");
+          }
+          else {
+            routie("listDataset");
           }
+        },
+        "listDataset":function () {
+          showSection("listDataset");
+        },
+        "listHistory":function () {
+          showSection("listHistory");
         }
-      );
-    });
+      });
 
-    $('.delete-row').click(function() {
-      var el = $(this);
-      var row = el.closest('tr');
-      var table = el.closest('table');
-      el.find(':input').attr('checked', 'checked');
-      row.hide();
-      $(table.attr('data-missing')).trigger('reinit', table);
-    });
+      function showStep(step) {
+        showSection("steps");
+        currentStep = step;
+        if (step != "step1") {
+          $("#backBtn").removeClass("disabled");
+        }
+        else {
+          $("#backBtn").addClass("disabled");
+        }
+        if (step != $(".stepDetails:last").attr("id")) {
+          $("#nextBtn").removeClass("disabled");
+        }
+        else {
+          $("#nextBtn").addClass("disabled");
+        }
+        $("a.step").parent().removeClass("active");
+        $("a.step[href=#" + step + "]").parent().addClass("active");
+        $(".stepDetails").hide();
+        $("#" + step).show();
+      }
 
-    $('.delete-row').closest('table').each(function() {
-      var table = $(this);
-      var id = table.attr('data-missing');
-      if (!!id) {
-        $( id ).trigger('register', [ function() {
-          return table.find('tbody tr').length == table.find('tbody tr:hidden').length;
-        }, function() {
-          table.hide();
-        } ] );
+      function showSection(section) {
+        $(".section").hide();
+        $("#" + section).show();
       }
-    });
 
-    $("a[data-row-selector='true']").jHueRowSelector();
+      function validateStep(step) {
+        var proceed = true;
+        $("#" + step).find("[validate=true]").each(function () {
+          if ($(this).val().trim() == "") {
+            proceed = false;
+            routie(step);
+            $(this).parents(".control-group").addClass("error");
+            $(this).parent().find(".help-inline").remove();
+            $(this).after("<span class=\"help-inline\"><strong>${ _('This field is required.') }</strong></span>");
+          }
+        });
+        return proceed;
+      }
+
+      $("#backBtn").click(function () {
+        var nextStep = (currentStep.substr(4) * 1 - 1);
+        if (nextStep >= 1) {
+          routie("step" + nextStep);
+        }
+      });
+
+      $("#nextBtn").click(function () {
+        var nextStep = (currentStep.substr(4) * 1 + 1);
+        if (nextStep <= $(".step").length) {
+          routie("step" + nextStep);
+        }
+      });
+
+      $("[validate=true]").change(function () {
+        $(this).parents(".control-group").removeClass("error");
+        $(this).parent().find(".help-inline").remove();
+      });
 
-    ko.applyBindings(window.viewModel);
+      $("#id_name").change(function () {
+        $("#coordinatorName").text($(this).val());
+      });
 
-    $("*[rel=popover]").popover({
-      placement: 'right',
-      trigger: 'hover'
+      $("#id_workflow").change(function () {
+        $("#workflowName").text($("#id_workflow option[value='" + $(this).val() + "']").text());
+      });
+
+      $(".save").click(function () {
+        window.viewModel.submit();
+      });
     });
- });
-</script>
+  </script>
 
 % endif
 
-${ commonfooter(messages) }
+
+${ utils.decorate_datetime_fields() }
+
+${ commonfooter(messages) }

+ 0 - 16
apps/oozie/src/oozie/templates/editor/edit_coordinator_dataset.mako

@@ -21,15 +21,6 @@
 
 
 <%namespace name="utils" file="../utils.inc.mako" />
-
-
-<form class="form-horizontal" id="edit-dataset-form" method="POST" action="${path}">
-  <div class="modal-header">
-    <button class="close" data-dismiss="modal">&times;</button>
-    <h3>${ _('Edit dataset') }</h3>
-  </div>
-
-  <div class="modal-body" id="edit-dataset-body">
     <fieldset>
       ${ utils.render_field(dataset_form['name']) }
       ${ utils.render_field(dataset_form['description']) }
@@ -58,10 +49,3 @@
       ${ utils.render_field(dataset_form['timezone']) }
       ${ utils.render_field(dataset_form['done_flag']) }
     </fieldset>
-  </div>
-
-  <div class="modal-footer">
-    <a href="#" class="btn" data-dismiss="modal">${ _('Close') }</a>
-    <button type="submit" class="btn btn-primary" id="edit-dataset-btn">${ _('Save') }</button>
-  </div>
-</form>

+ 127 - 0
apps/oozie/src/oozie/templates/utils.inc.mako

@@ -183,6 +183,27 @@
   %endif
 </%def>
 
+<%def name="render_field_no_popover(field, show_label=True, extra_attrs={})">
+  % if not field.is_hidden:
+    <% group_class = field.errors and "error" or "" %>
+    <div class="control-group ${group_class}">
+    % if show_label:
+        <label class="control-label">${ field.label | h }</label>
+    % endif
+    <div class="controls">
+    <% field.field.widget.attrs.update(extra_attrs) %>
+    ${ field }
+    % if field.errors:
+        <span class="help-inline">${ unicode(field.errors) }</span>
+    % endif
+    % if field.help_text:
+        <span class="help-block">${ field.help_text }</span>
+    % endif
+    </div>
+    </div>
+  %endif
+</%def>
+
 
 <%def name="render_field_with_error_js(field, error_name, show_label=True, extra_attrs={})">
   % if not field.is_hidden:
@@ -303,3 +324,109 @@
   </script>
 </%def>
 
+
+<%def name="decorate_datetime_fields()">
+
+  <link rel="stylesheet" href="/static/ext/css/bootstrap-datepicker.min.css" type="text/css" media="screen" title="no title" charset="utf-8" />
+  <link rel="stylesheet" href="/static/ext/css/bootstrap-timepicker.min.css" type="text/css" media="screen" title="no title" charset="utf-8" />
+
+  <style>
+    .datepicker {
+      z-index: 4999;
+    }
+  </style>
+
+  <script src="/static/ext/js/moment.min.js" type="text/javascript" charset="utf-8"></script>
+  <script src="/static/ext/js/bootstrap-datepicker.min.js" type="text/javascript" charset="utf-8"></script>
+  <script src="/static/ext/js/bootstrap-timepicker.min.js" type="text/javascript" charset="utf-8"></script>
+
+  <script type="text/javascript" charset="utf-8">
+
+    var DATE_FORMAT = "MM/DD/YYYY";
+    var TIME_FORMAT = "hh:mm A";
+    var DATETIME_FORMAT = DATE_FORMAT + " " + TIME_FORMAT;
+
+    function decorateDateTime () {
+      $(".date").each(function () {
+        $(this).removeClass("date").addClass("dateInput").wrap($("<div>").addClass("input-append").addClass("date").css("marginRight", "8px"));
+        $(this).parent().data("date", $(this).val());
+        $("<span>").addClass("add-on").html('<i class="icon-th"></i>').appendTo($(this).parent());
+      });
+
+      $("input[name='end_0']").data("original-val", $("input[name='end_0']").val());
+
+      $(".dateInput").parent().datepicker({
+        format:DATE_FORMAT.toLowerCase()
+      });
+
+      $("input[name='start_0']").parent().datepicker().on("changeDate", function () {
+        rangeHandler(true);
+      });
+
+      $("input[name='end_0']").parent().datepicker().on("changeDate", function () {
+        rangeHandler(false);
+      });
+
+      $(".time").each(function () {
+        $(this).attr("class", "input-mini timepicker-default").wrap($("<div>").addClass("input-append").addClass("date").addClass("bootstrap-timepicker-component"));
+        $("<span>").addClass("add-on").html('<i class="icon-time"></i>').appendTo($(this).parent());
+      });
+
+      $(".timepicker-default").timepicker({
+        defaultTime:"value"
+      });
+
+      $("input[name='start_1']").on("change", function (e) {
+        // the timepicker plugin doesn't have a change event handler
+        // so we need to wait a bit to handle in with the default field event
+        window.setTimeout(function () {
+          rangeHandler(true)
+        }, 200);
+      });
+
+      $("input[name='end_1']").on("change", function () {
+        window.setTimeout(function () {
+          rangeHandler(true)
+        }, 200);
+      });
+
+      function rangeHandler(isStart) {
+        var startDate = moment($("input[name='start_0']").val() + " " + $("input[name='start_1']").val(), DATETIME_FORMAT);
+        var endDate = moment($("input[name='end_0']").val() + " " + $("input[name='end_1']").val(), DATETIME_FORMAT);
+        if (startDate.valueOf() > endDate.valueOf()) {
+          if (isStart) {
+            $("input[name='end_0']").val(startDate.format(DATE_FORMAT));
+            $("input[name='end_0']").parent().datepicker('setValue', startDate.format(DATE_FORMAT));
+            $("input[name='end_0']").data("original-val", $("input[name='end_0']").val());
+            $("input[name='end_1']").val(startDate.format(TIME_FORMAT));
+          }
+          else {
+            if ($("input[name='end_0']").val() == $("input[name='start_0']").val()) {
+              $("input[name='end_1']").val(startDate.format(TIME_FORMAT));
+              $("input[name='end_1']").data("timepicker").setValues(startDate.format(TIME_FORMAT));
+            }
+            else {
+              $("input[name='end_0']").val($("input[name='end_0']").data("original-val"));
+              $("input[name='end_0']").parent().datepicker("setValue", $("input[name='end_0']").data("original-val"));
+            }
+            // non-sticky error notification
+            $.jHueNotify.notify({
+              level:"ERROR",
+              message:"${ _("The end cannot be before the starting moment") }"
+            });
+          }
+        }
+        else {
+          $("input[name='end_0']").data("original-val", $("input[name='end_0']").val());
+          $("input[name='start_0']").parent().datepicker("hide");
+          $("input[name='end_0']").parent().datepicker("hide");
+        }
+      }
+    }
+
+    $(document).ready(function(){
+      decorateDateTime();
+    });
+  </script>
+
+</%def>

+ 16 - 10
apps/oozie/src/oozie/views/editor.py

@@ -255,7 +255,7 @@ def create_coordinator(request, workflow=None):
 
     if coordinator_form.is_valid():
       coordinator = coordinator_form.save()
-      return redirect(reverse('oozie:edit_coordinator', kwargs={'coordinator': coordinator.id}))
+      return redirect(reverse('oozie:edit_coordinator', kwargs={'coordinator': coordinator.id}) + "#step3")
     else:
       request.error(_('Errors on the form: %s') % coordinator_form.errors)
   else:
@@ -352,8 +352,8 @@ def create_coordinator_dataset(request, coordinator):
     if dataset_form.is_valid():
       dataset_form.save()
       response['status'] = 0
-      response['data'] = reverse('oozie:edit_coordinator', kwargs={'coordinator': coordinator.id})
-      request.info(_('Dataset created'));
+      response['data'] = reverse('oozie:edit_coordinator', kwargs={'coordinator': coordinator.id}) + "#listDataset"
+      request.info(_('Dataset created'))
     else:
       dataset_form = DatasetForm(request.POST, instance=dataset, prefix='create')
   else:
@@ -374,23 +374,29 @@ def create_coordinator_dataset(request, coordinator):
 def edit_coordinator_dataset(request, dataset):
   """Returns HTML for modal to edit datasets"""
 
+  response = {'status': -1, 'data': 'None'}
+
   if request.method == 'POST':
     dataset_form = DatasetForm(request.POST, instance=dataset)
 
     if dataset_form.is_valid():
       dataset_form.save()
-      request.info(_('Dataset modified'));
-      return redirect(reverse('oozie:edit_coordinator', kwargs={'coordinator': dataset.coordinator.id}))
+      response['status'] = 0
+      response['data'] = reverse('oozie:edit_coordinator', kwargs={'coordinator': dataset.coordinator.id}) + "#listDataset"
+      request.info(_('Dataset modified'))
     else:
       dataset_form = DatasetForm(request.POST, instance=dataset)
   else:
     dataset_form = DatasetForm(instance=dataset)
 
-  return render('editor/edit_coordinator_dataset.mako', request, {
-    'coordinator': dataset.coordinator,
-    'dataset_form': dataset_form,
-    'path': request.path,
-  }, force_template=True)
+  if response['status'] != 0:
+    response['data'] = render('editor/edit_coordinator_dataset.mako', request, {
+                          'coordinator': dataset.coordinator,
+                          'dataset_form': dataset_form,
+                          'path': request.path,
+                        }, force_template=True).content
+
+  return HttpResponse(json.dumps(response), mimetype="application/json")
 
 
 @check_job_access_permission()

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 6 - 0
desktop/core/static/ext/css/bootstrap-datepicker.min.css


+ 8 - 0
desktop/core/static/ext/css/bootstrap-timepicker.min.css

@@ -0,0 +1,8 @@
+/*!
+ * Timepicker for Bootstrap
+ *
+ * Copyright 2012 Joris de Wit, Stefan Petre, Andrew Rowls
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */.bootstrap-timepicker.dropdown-menu{top:0;left:0;padding:4px;margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;display:none;min-width:10px;z-index:99999}.bootstrap-timepicker.dropdown-menu.open{display:inline-block}.bootstrap-timepicker.dropdown-menu:before{content:'';border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,0.2);position:absolute;top:-7px;left:6px}.bootstrap-timepicker.dropdown-menu:after{content:'';border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:7px}.bootstrap-timepicker.modal{top:30%;margin-top:0;width:200px;margin-left:-100px}.bootstrap-timepicker.modal .modal-content{padding:0}.bootstrap-timepicker table{width:100%;margin:0}.bootstrap-timepicker table td{text-align:center;height:30px;margin:0;padding:2px}.bootstrap-timepicker table td span{width:100%}.bootstrap-timepicker table td a{border:1px transparent solid;width:3em;display:inline-block;margin:0;padding:8px 0;outline:0;color:#333}.bootstrap-timepicker table td a:hover{text-decoration:none;background-color:#eee;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border-color:#ddd}.bootstrap-timepicker table td a i{margin-top:2px}.bootstrap-timepicker table td input{width:25px;margin:0;text-align:center}.bootstrap-timepicker-component .add-on{cursor:pointer}.bootstrap-timepicker-component .add-on i{display:block;width:16px;height:16px}

+ 0 - 38
desktop/core/static/ext/css/jquery-timepicker.css

@@ -1,38 +0,0 @@
-div.time-picker {
-  position: absolute;
-  height: 191px;
-  width:4em; /* needed for IE */
-  overflow: auto;
-  background: #fff;
-  border: 1px solid #aaa;
-  z-index: 1501;
-  margin: 0;
-}
-div.time-picker-12hours {
-  width:6em; /* needed for IE */
-}
-
-div.time-picker ul {
-  list-style-type: none;
-  margin: 0;
-  padding: 0;
-}
-div.time-picker li {
-  cursor: pointer;
-  height: 10px;
-  font: 12px/1 Helvetica, Arial, sans-serif;
-  padding: 4px 3px;
-}
-div.time-picker li.selected {
-  background: #0063CE;
-  color: #fff;
-}
-
-/** Custom magic **/
-input.short {
-  clear: right;
-  display: block;
-  float: left;
-  margin: 0px 10px 0px 0px;
-  width: 95px;
-}

+ 0 - 352
desktop/core/static/ext/css/jquery-ui-datepicker-1.8.23.css

@@ -1,352 +0,0 @@
-/*!
- * jQuery UI CSS Framework 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- */
-
-/* Layout helpers
-----------------------------------*/
-.ui-helper-hidden { display: none; }
-.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
-.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
-.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
-.ui-helper-clearfix:after { clear: both; }
-.ui-helper-clearfix { zoom: 1; }
-.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
-
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-disabled { cursor: default !important; }
-
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Overlays */
-.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
-
-
-/*!
- * jQuery UI CSS Framework 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- *
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Helvetica,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=2px&bgColorHeader=dddddd&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=50&borderColorHeader=dddddd&fcHeader=444444&iconColorHeader=0073ea&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=dddddd&fcContent=444444&iconColorContent=ff0084&bgColorDefault=f6f6f6&bgTextureDefault=03_highlight_soft.png&bgImgOpacityDefault=100&borderColorDefault=dddddd&fcDefault=0073ea&iconColorDefault=666666&bgColorHover=0073ea&bgTextureHover=03_highlight_soft.png&bgImgOpacityHover=25&borderColorHover=0073ea&fcHover=ffffff&iconColorHover=ffffff&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=dddddd&fcActive=ff0084&iconColorActive=454545&bgColorHighlight=ffffff&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=cccccc&fcHighlight=444444&iconColorHighlight=0073ea&bgColorError=ffffff&bgTextureError=01_flat.png&bgImgOpacityError=55&borderColorError=ff0084&fcError=222222&iconColorError=ff0084&bgColorOverlay=eeeeee&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=80&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=60&thicknessShadow=4px&offsetTopShadow=-4px&offsetLeftShadow=-4px&cornerRadiusShadow=0px
- */
-
-
-/* Component containers
-----------------------------------*/
-.ui-widget { font-family: Helvetica, Arial, sans-serif; font-size: 1.1em; }
-.ui-widget .ui-widget { font-size: 1em; }
-.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Helvetica, Arial, sans-serif; font-size: 1em; }
-.ui-widget-content { border: 1px solid #dddddd; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #444444; }
-.ui-widget-content a { color: #444444; }
-.ui-widget-header { border: 1px solid #dddddd; background: #dddddd url(images/ui-bg_highlight-soft_50_dddddd_1x100.png) 50% 50% repeat-x; color: #444444; font-weight: bold; }
-.ui-widget-header a { color: #444444; }
-
-/* Interaction states
-----------------------------------*/
-.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #dddddd; background: #f6f6f6 url(images/ui-bg_highlight-soft_100_f6f6f6_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #0073ea; }
-.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #0073ea; text-decoration: none; }
-.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #0073ea; background: #0073ea url(images/ui-bg_highlight-soft_25_0073ea_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #ffffff; }
-.ui-state-hover a, .ui-state-hover a:hover { color: #ffffff; text-decoration: none; }
-.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #dddddd; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #ff0084; }
-.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #ff0084; text-decoration: none; }
-.ui-widget :active { outline: none; }
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #cccccc; background: #ffffff url(images/ui-bg_flat_55_ffffff_40x100.png) 50% 50% repeat-x; color: #444444; }
-.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #444444; }
-.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #ff0084; background: #ffffff url(images/ui-bg_flat_55_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
-.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #222222; }
-.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #222222; }
-.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
-.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
-.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_ff0084_256x240.png); }
-.ui-widget-content .ui-icon {background-image: url(images/ui-icons_ff0084_256x240.png); }
-.ui-widget-header .ui-icon {background-image: url(images/ui-icons_0073ea_256x240.png); }
-.ui-state-default .ui-icon { background-image: url(images/ui-icons_666666_256x240.png); }
-.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
-.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
-.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_0073ea_256x240.png); }
-.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ff0084_256x240.png); }
-
-/* positioning */
-.ui-icon-carat-1-n { background-position: 0 0; }
-.ui-icon-carat-1-ne { background-position: -16px 0; }
-.ui-icon-carat-1-e { background-position: -32px 0; }
-.ui-icon-carat-1-se { background-position: -48px 0; }
-.ui-icon-carat-1-s { background-position: -64px 0; }
-.ui-icon-carat-1-sw { background-position: -80px 0; }
-.ui-icon-carat-1-w { background-position: -96px 0; }
-.ui-icon-carat-1-nw { background-position: -112px 0; }
-.ui-icon-carat-2-n-s { background-position: -128px 0; }
-.ui-icon-carat-2-e-w { background-position: -144px 0; }
-.ui-icon-triangle-1-n { background-position: 0 -16px; }
-.ui-icon-triangle-1-ne { background-position: -16px -16px; }
-.ui-icon-triangle-1-e { background-position: -32px -16px; }
-.ui-icon-triangle-1-se { background-position: -48px -16px; }
-.ui-icon-triangle-1-s { background-position: -64px -16px; }
-.ui-icon-triangle-1-sw { background-position: -80px -16px; }
-.ui-icon-triangle-1-w { background-position: -96px -16px; }
-.ui-icon-triangle-1-nw { background-position: -112px -16px; }
-.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
-.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
-.ui-icon-arrow-1-n { background-position: 0 -32px; }
-.ui-icon-arrow-1-ne { background-position: -16px -32px; }
-.ui-icon-arrow-1-e { background-position: -32px -32px; }
-.ui-icon-arrow-1-se { background-position: -48px -32px; }
-.ui-icon-arrow-1-s { background-position: -64px -32px; }
-.ui-icon-arrow-1-sw { background-position: -80px -32px; }
-.ui-icon-arrow-1-w { background-position: -96px -32px; }
-.ui-icon-arrow-1-nw { background-position: -112px -32px; }
-.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
-.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
-.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
-.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
-.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
-.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
-.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
-.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
-.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
-.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
-.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
-.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
-.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
-.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
-.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
-.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
-.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
-.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
-.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
-.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
-.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
-.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
-.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
-.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
-.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
-.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
-.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
-.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
-.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
-.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
-.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
-.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
-.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
-.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
-.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
-.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
-.ui-icon-arrow-4 { background-position: 0 -80px; }
-.ui-icon-arrow-4-diag { background-position: -16px -80px; }
-.ui-icon-extlink { background-position: -32px -80px; }
-.ui-icon-newwin { background-position: -48px -80px; }
-.ui-icon-refresh { background-position: -64px -80px; }
-.ui-icon-shuffle { background-position: -80px -80px; }
-.ui-icon-transfer-e-w { background-position: -96px -80px; }
-.ui-icon-transferthick-e-w { background-position: -112px -80px; }
-.ui-icon-folder-collapsed { background-position: 0 -96px; }
-.ui-icon-folder-open { background-position: -16px -96px; }
-.ui-icon-document { background-position: -32px -96px; }
-.ui-icon-document-b { background-position: -48px -96px; }
-.ui-icon-note { background-position: -64px -96px; }
-.ui-icon-mail-closed { background-position: -80px -96px; }
-.ui-icon-mail-open { background-position: -96px -96px; }
-.ui-icon-suitcase { background-position: -112px -96px; }
-.ui-icon-comment { background-position: -128px -96px; }
-.ui-icon-person { background-position: -144px -96px; }
-.ui-icon-print { background-position: -160px -96px; }
-.ui-icon-trash { background-position: -176px -96px; }
-.ui-icon-locked { background-position: -192px -96px; }
-.ui-icon-unlocked { background-position: -208px -96px; }
-.ui-icon-bookmark { background-position: -224px -96px; }
-.ui-icon-tag { background-position: -240px -96px; }
-.ui-icon-home { background-position: 0 -112px; }
-.ui-icon-flag { background-position: -16px -112px; }
-.ui-icon-calendar { background-position: -32px -112px; }
-.ui-icon-cart { background-position: -48px -112px; }
-.ui-icon-pencil { background-position: -64px -112px; }
-.ui-icon-clock { background-position: -80px -112px; }
-.ui-icon-disk { background-position: -96px -112px; }
-.ui-icon-calculator { background-position: -112px -112px; }
-.ui-icon-zoomin { background-position: -128px -112px; }
-.ui-icon-zoomout { background-position: -144px -112px; }
-.ui-icon-search { background-position: -160px -112px; }
-.ui-icon-wrench { background-position: -176px -112px; }
-.ui-icon-gear { background-position: -192px -112px; }
-.ui-icon-heart { background-position: -208px -112px; }
-.ui-icon-star { background-position: -224px -112px; }
-.ui-icon-link { background-position: -240px -112px; }
-.ui-icon-cancel { background-position: 0 -128px; }
-.ui-icon-plus { background-position: -16px -128px; }
-.ui-icon-plusthick { background-position: -32px -128px; }
-.ui-icon-minus { background-position: -48px -128px; }
-.ui-icon-minusthick { background-position: -64px -128px; }
-.ui-icon-close { background-position: -80px -128px; }
-.ui-icon-closethick { background-position: -96px -128px; }
-.ui-icon-key { background-position: -112px -128px; }
-.ui-icon-lightbulb { background-position: -128px -128px; }
-.ui-icon-scissors { background-position: -144px -128px; }
-.ui-icon-clipboard { background-position: -160px -128px; }
-.ui-icon-copy { background-position: -176px -128px; }
-.ui-icon-contact { background-position: -192px -128px; }
-.ui-icon-image { background-position: -208px -128px; }
-.ui-icon-video { background-position: -224px -128px; }
-.ui-icon-script { background-position: -240px -128px; }
-.ui-icon-alert { background-position: 0 -144px; }
-.ui-icon-info { background-position: -16px -144px; }
-.ui-icon-notice { background-position: -32px -144px; }
-.ui-icon-help { background-position: -48px -144px; }
-.ui-icon-check { background-position: -64px -144px; }
-.ui-icon-bullet { background-position: -80px -144px; }
-.ui-icon-radio-off { background-position: -96px -144px; }
-.ui-icon-radio-on { background-position: -112px -144px; }
-.ui-icon-pin-w { background-position: -128px -144px; }
-.ui-icon-pin-s { background-position: -144px -144px; }
-.ui-icon-play { background-position: 0 -160px; }
-.ui-icon-pause { background-position: -16px -160px; }
-.ui-icon-seek-next { background-position: -32px -160px; }
-.ui-icon-seek-prev { background-position: -48px -160px; }
-.ui-icon-seek-end { background-position: -64px -160px; }
-.ui-icon-seek-start { background-position: -80px -160px; }
-/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
-.ui-icon-seek-first { background-position: -80px -160px; }
-.ui-icon-stop { background-position: -96px -160px; }
-.ui-icon-eject { background-position: -112px -160px; }
-.ui-icon-volume-off { background-position: -128px -160px; }
-.ui-icon-volume-on { background-position: -144px -160px; }
-.ui-icon-power { background-position: 0 -176px; }
-.ui-icon-signal-diag { background-position: -16px -176px; }
-.ui-icon-signal { background-position: -32px -176px; }
-.ui-icon-battery-0 { background-position: -48px -176px; }
-.ui-icon-battery-1 { background-position: -64px -176px; }
-.ui-icon-battery-2 { background-position: -80px -176px; }
-.ui-icon-battery-3 { background-position: -96px -176px; }
-.ui-icon-circle-plus { background-position: 0 -192px; }
-.ui-icon-circle-minus { background-position: -16px -192px; }
-.ui-icon-circle-close { background-position: -32px -192px; }
-.ui-icon-circle-triangle-e { background-position: -48px -192px; }
-.ui-icon-circle-triangle-s { background-position: -64px -192px; }
-.ui-icon-circle-triangle-w { background-position: -80px -192px; }
-.ui-icon-circle-triangle-n { background-position: -96px -192px; }
-.ui-icon-circle-arrow-e { background-position: -112px -192px; }
-.ui-icon-circle-arrow-s { background-position: -128px -192px; }
-.ui-icon-circle-arrow-w { background-position: -144px -192px; }
-.ui-icon-circle-arrow-n { background-position: -160px -192px; }
-.ui-icon-circle-zoomin { background-position: -176px -192px; }
-.ui-icon-circle-zoomout { background-position: -192px -192px; }
-.ui-icon-circle-check { background-position: -208px -192px; }
-.ui-icon-circlesmall-plus { background-position: 0 -208px; }
-.ui-icon-circlesmall-minus { background-position: -16px -208px; }
-.ui-icon-circlesmall-close { background-position: -32px -208px; }
-.ui-icon-squaresmall-plus { background-position: -48px -208px; }
-.ui-icon-squaresmall-minus { background-position: -64px -208px; }
-.ui-icon-squaresmall-close { background-position: -80px -208px; }
-.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
-.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
-.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
-.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
-.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
-.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Corner radius */
-.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 2px; -webkit-border-top-left-radius: 2px; -khtml-border-top-left-radius: 2px; border-top-left-radius: 2px; }
-.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 2px; -webkit-border-top-right-radius: 2px; -khtml-border-top-right-radius: 2px; border-top-right-radius: 2px; }
-.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 2px; -webkit-border-bottom-left-radius: 2px; -khtml-border-bottom-left-radius: 2px; border-bottom-left-radius: 2px; }
-.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 2px; -webkit-border-bottom-right-radius: 2px; -khtml-border-bottom-right-radius: 2px; border-bottom-right-radius: 2px; }
-
-/* Overlays */
-.ui-widget-overlay { background: #eeeeee url(images/ui-bg_flat_0_eeeeee_40x100.png) 50% 50% repeat-x; opacity: .80;filter:Alpha(Opacity=80); }
-.ui-widget-shadow { margin: -4px 0 0 -4px; padding: 4px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .60;filter:Alpha(Opacity=60); -moz-border-radius: 0px; -khtml-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; }/*!
- * jQuery UI Datepicker 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Datepicker#theming
- */
-.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
-.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
-.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
-.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
-.ui-datepicker .ui-datepicker-prev { left:2px; }
-.ui-datepicker .ui-datepicker-next { right:2px; }
-.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
-.ui-datepicker .ui-datepicker-next-hover { right:1px; }
-.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
-.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
-.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
-.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
-.ui-datepicker select.ui-datepicker-month, 
-.ui-datepicker select.ui-datepicker-year { width: 49%;}
-.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
-.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
-.ui-datepicker td { border: 0; padding: 1px; }
-.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
-.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
-.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
-.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
-
-/* with multiple calendars */
-.ui-datepicker.ui-datepicker-multi { width:auto; }
-.ui-datepicker-multi .ui-datepicker-group { float:left; }
-.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
-.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
-.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
-.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
-.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
-.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
-
-/* RTL support */
-.ui-datepicker-rtl { direction: rtl; }
-.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
-.ui-datepicker-rtl .ui-datepicker-group { float:right; }
-.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-
-/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
-.ui-datepicker-cover {
-    position: absolute; /*must have*/
-    z-index: -1; /*must have*/
-    filter: mask(); /*must have*/
-    top: -4px; /*must have*/
-    left: -4px; /*must have*/
-    width: 200px; /*must have*/
-    height: 200px; /*must have*/
-}

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 17 - 0
desktop/core/static/ext/js/bootstrap-datepicker.min.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 27 - 0
desktop/core/static/ext/js/bootstrap-timepicker.min.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
desktop/core/static/ext/js/jquery/plugins/jquery-timepicker.min.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 4
desktop/core/static/ext/js/jquery/plugins/jquery-ui-datepicker-1.8.23.min.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 7 - 0
desktop/core/static/ext/js/routie-0.3.0.min.js


+ 1 - 1
desktop/core/static/js/Source/jHue/jquery.notify.js

@@ -40,7 +40,7 @@
         el.find(".close").hide();
 
         if ($(".jHueNotify").last().position() != null) {
-            el.css("top", $(".jHueNotify").last().position().top + $(".jHueNotify").last().outerHeight() + MARGIN);
+            el.css("top", $(".jHueNotify").last().position().top + $(".jHueNotify").last().outerHeight() + MARGIN - $(window).scrollTop());
         }
 
         if (_this.options.level == TYPES.ERROR){

+ 2 - 1
desktop/core/static/js/Source/jHue/jquery.rowselector.js

@@ -28,7 +28,8 @@
                 return;
             }
             if (!$(e.target).is("a")) {
-                if ($.trim($(_this.element).attr("href")) != "" && $.trim($(_this.element).attr("href")) != "#") {
+                var href = $.trim($(_this.element).attr("href"));
+                if (href != "" && href != "#" && href.indexOf("void(0)") == -1) {
                     location.href = $(_this.element).attr("href");
                 }
                 else {

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно