瀏覽代碼

HUE-1812 [spark] Make it awesomer

Enrico Berti 12 年之前
父節點
當前提交
d076823

+ 5 - 10
apps/beeswax/src/beeswax/templates/layout.mako

@@ -38,21 +38,16 @@ def is_selected(section, matcher):
             <li class="currentApp">
               <a href="/spark">
                 <img src="/spark/static/art/icon_spark_24.png" />
-                ${ _('Spark Editor') }
+                ${ _('Spark Igniter') }
               </a>
             </li>
-            <li class="${is_selected(section, 'query')}"><a href="${ url('spark:editor') }">${_('Query Editor')}</a></li>
+            <li class="${is_selected(section, 'query')}"><a href="${ url('spark:editor') }">${_('App Runner')}</a></li>
             ##<li class="${is_selected(section, 'my queries')}"><a href="${ url(app_name + ':my_queries') }">${_('My Queries')}</a></li>
-            <li class="${is_selected(section, 'saved queries')}"><a href="${ url('spark:list_designs') }">${_('Queries')}</a></li>
+            <li class="${is_selected(section, 'saved queries')}"><a href="${ url('spark:list_designs') }">${_('App Configurations')}</a></li>
             ##<li class="${is_selected(section, 'history')}"><a href="${ url('spark:list_query_history') }">${_('History')}</a></li>
-            <li class="currentApp">
-              <a href="/spark">
-                ${ _('Dashboard') }
-              </a>
-            </li>
-            <li class="${is_selected(section, 'jobs')}"><a href="${ url('spark:list_jobs') }">${_('Jobs')}</a></li>
+            <li class="${is_selected(section, 'jobs')}"><a href="${ url('spark:list_jobs') }">${_('Dashboard')}</a></li>
             <li class="${is_selected(section, 'contexts')}"><a href="${ url('spark:list_contexts') }">${_('Contexts')}</a></li>
-            <li class="${is_selected(section, 'applications')}"><a href="${ url('spark:list_applications') }">${_('Applications')}</a></li>
+            <li class="${is_selected(section, 'applications')}"><a href="${ url('spark:list_applications') }">${_('Uploaded Apps')}</a></li>
           </ul>
         </div>
       </div>

+ 19 - 8
apps/beeswax/src/beeswax/templates/list_designs.mako

@@ -30,18 +30,29 @@ ${layout.menubar(section='saved queries')}
 
 <div class="container-fluid">
   <div class="card card-small">
-    <h1 class="card-heading simple">${_('Saved Queries')}</h1>
+    % if app_name == 'spark':
+      <h1 class="card-heading simple">${_('App Configurations')}</h1>
+    % else:
+      <h1 class="card-heading simple">${_('Saved Queries')}</h1>
+    % endif
 
+    <%
+      noun = "query"
+      pluralnoun = "queries"
+      if app_name == 'spark':
+        noun = "app"
+        pluralnoun = "apps"
+    %>
     <%actionbar:render>
       <%def name="search()">
-        <input id="filterInput" type="text" class="input-xlarge search-query" placeholder="${_('Search for query')}">
+        <input id="filterInput" type="text" class="input-xlarge search-query" placeholder="${_('Search for %s') % noun }">
       </%def>
 
       <%def name="actions()">
         <div class="btn-toolbar" style="display: inline; vertical-align: middle">
-          <button id="editBtn" class="btn toolbarBtn" title="${_('Edit the selected query')}" disabled="disabled"><i class="fa fa-edit"></i> ${_('Edit')}</button>
-          <button id="cloneBtn" class="btn toolbarBtn" title="${_('Copy the selected query')}" disabled="disabled"><i class="fa fa-files-o"></i> ${_('Copy')}</button>
-          <button id="historyBtn" class="btn toolbarBtn" title="${_('View the usage history of the selected query')}" disabled="disabled"><i class="fa fa-tasks"></i> ${_('Usage history')}</button>
+          <button id="editBtn" class="btn toolbarBtn" title="${_('Edit the selected %s' % noun)}" disabled="disabled"><i class="fa fa-edit"></i> ${_('Edit')}</button>
+          <button id="cloneBtn" class="btn toolbarBtn" title="${_('Copy the selected %s' % noun)}" disabled="disabled"><i class="fa fa-files-o"></i> ${_('Copy')}</button>
+          <button id="historyBtn" class="btn toolbarBtn" title="${_('View the usage history of the selected %s' % noun)}" disabled="disabled"><i class="fa fa-tasks"></i> ${_('Usage history')}</button>
 
           <div id="delete-dropdown" class="btn-group" style="vertical-align: middle">
             <button id="trashQueryBtn" class="btn toolbarBtn" disabled="disabled"><i class="fa fa-times"></i> ${_('Move to trash')}</button>
@@ -57,7 +68,7 @@ ${layout.menubar(section='saved queries')}
 
       <%def name="creation()">
         <div class="btn-toolbar" style="display: inline; vertical-align: middle">          
-          <a class="btn" href="${ url(app_name + ':execute_query') }" title="${_('Create new query')}"><i class="fa fa-plus-circle"></i> ${_('New query')}</a>
+          <a class="btn" href="${ url(app_name + ':execute_query') }" title="${_('Create new %s' % noun)}"><i class="fa fa-plus-circle"></i> ${_('New %s' % noun)}</a>
           <a class="btn" href="${ url(app_name + ':list_trashed_designs') }" title="${_('Go to the trash')}"><i class="fa fa-trash-o"></i> ${_('View trash')}</a>
         </div>
       </%def>
@@ -229,13 +240,13 @@ ${layout.menubar(section='saved queries')}
 
     $("#trashQueryBtn").click(function () {
       $("#skipTrash").val(false);
-      $("#deleteQueryMessage").text("${ _('Move the selected queries to the trash?') }");
+      $("#deleteQueryMessage").text("${ _('Move the selected %s to the trash?' % pluralnoun) }");
       deleteQueries();
     });
 
     $("#deleteQueryBtn").click(function () {
       $("#skipTrash").val(true);
-      $("#deleteQueryMessage").text("${ _('Delete the selected queries?') }");
+      $("#deleteQueryMessage").text("${ _('Delete the selected %s?' % pluralnoun) }");
       deleteQueries();
     });
 

+ 1 - 1
apps/beeswax/src/beeswax/templates/list_trashed_designs.mako

@@ -219,7 +219,7 @@ ${layout.menubar(section='saved queries')}
       $("#deleteQueryMessage").text("${ _('Empty the trash?') }");
 
       viewModel.chosenSavedQueries.removeAll();
-      $.each(viewModel.availableSavedQueries(), function(index, query) {
+      $.each(viewModel.availableSavedContexts(), function(index, query) {
         viewModel.chosenSavedQueries.push(query);
       });
 

+ 10 - 14
apps/spark/src/spark/templates/common.mako

@@ -35,21 +35,17 @@ def is_selected(section, matcher):
             <li class="currentApp">
               <a href="/spark">
                 <img src="/spark/static/art/icon_spark_24.png" />
-                ${ _('Spark Editor') }
+                ${ _('Spark Igniter') }
               </a>
             </li>
-            <li class="${is_selected(section, 'editor')}"><a href="${ url('spark:editor') }">${_('Query Editor')}</a></li>
+            <li class="${is_selected(section, 'editor')}"><a href="${ url('spark:editor') }">${_('App Runner')}</a></li>
             ##<li class="${is_selected(section, 'my queries')}"><a href="${ url(app_name + ':my_queries') }">${_('My Queries')}</a></li>
-            <li class="${is_selected(section, 'queries')}"><a href="${ url('spark:list_designs') }">${_('Queries')}</a></li>
+            <li class="${is_selected(section, 'queries')}"><a href="${ url('spark:list_designs') }">${_('App Configurations')}</a></li>
             ##<li class="${is_selected(section, 'history')}"><a href="${ url('spark:list_query_history') }">${_('History')}</a></li>
-            <li class="currentApp">
-              <a href="/spark">
-                ${ _('Dashboard') }
-              </a>
-            </li>
-            <li class="${is_selected(section, 'jobs')}"><a href="${ url('spark:list_jobs') }">${_('Jobs')}</a></li>
+
+            <li class="${is_selected(section, 'jobs')}"><a href="${ url('spark:list_jobs') }">${_('Dashboard')}</a></li>
             <li class="${is_selected(section, 'contexts')}"><a href="${ url('spark:list_contexts') }">${_('Contexts')}</a></li>
-            <li class="${is_selected(section, 'applications')}"><a href="${ url('spark:list_applications') }">${_('Applications')}</a></li>
+            <li class="${is_selected(section, 'applications')}"><a href="${ url('spark:list_applications') }">${_('Uploaded Apps')}</a></li>
           </ul>
         </div>
       </div>
@@ -68,26 +64,26 @@ def is_selected(section, matcher):
       <div class="control-group">
         <label class="control-label">${ _("Name") }</label>
         <div class="controls">
-          <input type="text" name="name">
+          <input type="text" name="name" data-default="">
         </div>
       </div>
       <div class="control-group">
         <label class="control-label">${ _("Num cpu cores") }</label>
         <div class="controls">
-          <input type="text" name="num-cpu-cores"value="1">
+          <input type="text" name="num-cpu-cores" value="1" data-default="1">
         </div>
       </div>
       <div class="control-group">
         <label class="control-label">${ _("Memory per node") }</label>
         <div class="controls">
-          <input type="text" name="mem-per-node" value="512m">
+          <input type="text" name="mem-per-node" value="512m" data-default="512m">
         </div>
       </div>
     </form>
   </div>
   <div class="modal-footer">
     <button class="btn" data-dismiss="modal">${_('Cancel')}</button>
-    <button data-bind="click: createContext" class="btn btn-primary">${_('Create')}</button>
+    <button id="createContextBtn" data-bind="click: createContext" class="btn btn-primary disable-feedback">${_('Create')}</button>
   </div>
 </div>
 </%def>

+ 147 - 160
apps/spark/src/spark/templates/editor.mako

@@ -25,194 +25,176 @@ ${ commonheader(_('Query'), app_name, user) | n,unicode }
 ${ common.navbar('editor') }
 
 <div class="container-fluid">
+
   <div class="row-fluid">
     <div class="card card-small">
-      <ul class="nav nav-pills hueBreadcrumbBar" id="breadcrumbs">
-        <li>
-          <div style="display: inline" class="dropdown">
-            ${_('App name')}&nbsp;
-            <!-- ko if: $root.appNames().length == 0 -->
-            <a class="uploadAppModalBtn" href="javascript:void(0);">
-              ${ _("Missing, add one?") }
-            </a>
-            <!-- /ko -->
-            <a data-bind="if: $root.appName" data-toggle="dropdown" href="javascript:void(0);">
-              <strong data-bind="text: $root.appName().nice_name"></strong>
-              <i class="fa fa-caret-down"></i>
-            </a>
-            <ul data-bind="foreach: $root.appNames" class="dropdown-menu">
-              <li data-bind="click: $root.chooseAppName, text: nice_name" class="selectable"></li>
-            </ul>
-          </div>
-        </li>
-        <li>&nbsp;&nbsp;&nbsp;&nbsp;</li>
-        <li>
-            ${_('Class path')}&nbsp;
-            <input type="text" data-bind="value: $root.classPath" class="input-xlarge" placeholder="spark.jobserver.WordCountExample"></input>
-        </li>
-        <li>&nbsp;&nbsp;&nbsp;&nbsp;</li>
-        <li>
-          <div style="display: inline" class="dropdown">
-            ${_('Context')}&nbsp;
-            <input type="checkbox" data-bind="checked: $root.autoContext" />
-            <span data-bind="visible: $root.autoContext">
-              ${ _('auto') }
-            </span>
-
-            <span data-bind="visible: ! $root.autoContext()">
-              <!-- ko if: $root.contexts().length == 0 -->
-              <a class="createContextModalBtn" href="javascript:void(0);">
-                ${ _("Create one?") }
-              </a>
-              <!-- /ko -->
-              <a data-bind="if: $root.context" data-toggle="dropdown" href="javascript:void(0);">
-                <strong data-bind="text: $root.context().nice_name"></strong>
-                <i class="fa fa-caret-down"></i>
-              </a>
-              <ul data-bind="foreach: $root.contexts" class="dropdown-menu">
-                <li data-bind="click: $root.chooseContext, text: nice_name" class="selectable"></li>
-              </ul>
-            </span>
-          </div>
-        </li>
-        % if can_edit_name:
-        <li style="padding-left:50px">
-          ${ _("Script") }
+      <div style="margin-bottom: 10px">
+        <h1 class="card-heading simple">
           <a href="javascript:void(0);"
              id="query-name"
              data-type="text"
              data-name="name"
              data-value="${design.name}"
-             data-original-title="${ _('Script name') }"
+             data-original-title="${ _('App name') }"
              data-placement="right">
           </a>
-          <a href="javascript:void(0);"
+        </h1>
+        % if can_edit_name:
+          <p style="margin-left: 20px">
+            <a href="javascript:void(0);"
              id="query-description"
              data-type="textarea"
              data-name="description"
              data-value="${design.desc}"
-             data-original-title="${ _('Script description') }"
+             data-original-title="${ _('App description') }"
              data-placement="right">
           </a>
-         </p>
-        </li>
-        %endif
-
-        <span class="pull-right">
-          <button type="button" class="btn btn-primary uploadAppModalBtn">${ _('Upload app') }</button>
-          <button type="button" class="btn btn-primary createContextModalBtn">${ _('Create context') }</button>
-        </span>
-      </ul>
-    </div>
-  </div>
+          </p>
+        % endif
+      </div>
+      <div class="card-body">
+        <p>
+          <span class="pull-right">
+            <button type="button" class="btn btn-primary uploadAppModalBtn">${ _('Upload app') }</button>
+            <button type="button" class="btn btn-primary createContextModalBtn">${ _('Create context') }</button>
+          </span>
+          <form class="form-inline">
+            <span class="dropdown">
+              ${_('App name')}&nbsp;
+              <!-- ko if: $root.appNames().length == 0 -->
+              <a class="uploadAppModalBtn" href="javascript:void(0);">
+                ${ _("Missing, add one?") }
+              </a>
+              <!-- /ko -->
+              <a data-bind="if: $root.appName" data-toggle="dropdown" href="javascript:void(0);"><strong data-bind="text: $root.appName().nice_name"></strong>
+                <i class="fa fa-caret-down"></i></a>
+              <ul data-bind="foreach: $root.appNames" class="dropdown-menu">
+                <li data-bind="click: $root.chooseAppName, text: nice_name" class="selectable"></li>
+              </ul>
+            </span>
 
-  <div class="row-fluid">
-    <div class="span12">
-    <div id="query">
-      <div class="card card-small">
-
-        <div class="card-body">
-          <div class="tab-content">
-            <div id="queryPane">
-
-              <div data-bind="css: {'hide': query.errors().length == 0}" class="hide alert alert-error">
-                <p><strong>${_('Your query has the following error(s):')}</strong></p>
-                <div data-bind="foreach: query.errors">
-                  <p data-bind="text: $data" class="queryErrorMessage"></p>
-                </div>
-              </div>
+            <label style="margin-left: 20px; margin-right: 20px">
+              ${_('Class path')}
+              <input type="text" data-bind="value: $root.classPath" class="input-xlarge" placeholder="spark.jobserver.WordCountExample" />
+            </label>
 
-      <div class="control-group">
-        <label class="control-label" style="padding-right:50px">${ _('Parameters') }</label>
-        <div class="controls">
-            <table class="table-condensed">
-              <thead data-bind="visible: query.params().length > 0">
-                <tr>
-                  <th>${ _('Name') }</th>
-                  <th>${ _('Value') }</th>
-                  <th/>
-                </tr>
-              </thead>
-              <tbody data-bind="foreach: query.params">
-                <tr>
-                  <td><input type="text" class="span6 required propKey" data-bind="value: name" /></td>
-                  <td><input type="text" class="span6 required pathChooserKo" data-bind="fileChooser: $data, value: value" /></td>
-                  <td>
-                    <a class="btn" href="#" data-bind="click: $root.removeParam">${ _('Delete') }</a>
-                  </td>
-                </tr>
-              </tbody>
-            </table>
-            <button class="btn" data-bind="click: $root.addParam">${ _('Add') }</button>
-          </div>
-         </div>
-        </div>
+            ${_('Context')}&nbsp;
+            <label class="radio" style="margin-left: 5px;margin-top:-2px">
+              ${ _('Automatic') }
+              <input type="radio" name="autoContext" value="true" data-bind="checked:$root.autoContext.forEditing" />
+            </label>
+            <label class="radio" style="margin-left: 5px;margin-top:-2px">
+              <span class="dropdown" style="padding-left: 5px">
+                <!-- ko if: $root.contexts().length == 0 -->
+                <a class="createContextModalBtn" href="javascript:void(0);">
+                  ${ _("Create one?") }
+                </a>
+                <!-- /ko -->
+                <a data-bind="if: $root.context" data-toggle="dropdown" href="javascript:void(0);">
+                  <strong data-bind="text: $root.context().nice_name"></strong>
+                  <i class="fa fa-caret-down"></i>
+                </a>
+                <ul data-bind="foreach: $root.contexts" class="dropdown-menu">
+                  <li data-bind="click: $root.chooseContext, text: nice_name" class="selectable"></li>
+                </ul>
+              </span>
+              <input type="radio" name="autoContext" value="false" data-bind="checked:$root.autoContext.forEditing"/>
+            </label>
+          </form>
+        </p>
       </div>
     </div>
   </div>
+
   <div class="row-fluid">
-    <div class="span12">
     <div class="card card-small">
-              <div class="actions">
-                <button data-bind="click: tryExecuteQuery, enable: $root.appNames().length > 0 && $root.classPath()"
-                    type="button" id="executeQuery" class="btn btn-primary disable-feedback"
-                    tabindex="2" data-loading-text="${ _("Executing...") }">
-                  ${_('Execute')}
-                </button>
-                <button data-bind="click: trySaveQuery, css: {'hide': !$root.query.id() || $root.query.id() == -1}" type="button" class="btn hide">${_('Save')}</button>
-                <button data-bind="click: trySaveAsQuery" type="button" class="btn">${_('Save as...')}</button>
-                &nbsp; ${_('or create a')} &nbsp;<a type="button" class="btn" href="${ url('spark:editor') }">${_('New query')}</a>
-                <span class="pull-right">
-                  <a type="button" class="btn" data-bind="visible: rows().length != 0, attr: {'href': '${ url('spark:download_result') }' + $root.query.jobId()}">${_('Download')}</a>
-                </span>
-              </div>
-             </div>
+      <h1 class="card-heading simple">${_('Parameters')}</h1>
+      <div class="card-body">
+        <p>
+          <div data-bind="css: {'hide': query.errors().length == 0}" class="hide alert alert-error">
+            <p><strong>${_('Your app configuration has the following error(s):')}</strong></p>
+            <div data-bind="foreach: query.errors">
+              <p data-bind="text: $data" class="queryErrorMessage"></p>
             </div>
           </div>
-        </div>
-      </div>
-    </div>
 
-    <div data-bind="css: {'hide': rows().length == 0}" class="hide">
-      <div class="card card-small scrollable">
-        <table class="table table-striped table-condensed resultTable" cellpadding="0" cellspacing="0" data-tablescroller-min-height-disable="true" data-tablescroller-enforce-height="true">
-          <thead>
-            <tr>
-              <th>${ _('Key') }</th>
-              <th>${ _('Value') }</th>
-            </tr>
-          </thead>
-        </table>
-      </div>
-    </div>
+          <div data-bind="visible: query.params().length == 0">${_('There currently no parameters defined.')}</div>
+
+          <table class="table-condensed">
+            <thead data-bind="visible: query.params().length > 0">
+              <tr>
+                <th>${ _('Name') }</th>
+                <th>${ _('Value') }</th>
+                <th/>
+              </tr>
+            </thead>
+            <tbody data-bind="foreach: query.params">
+              <tr>
+                <td><input type="text" class="span6 required propKey" data-bind="value: name" /></td>
+                <td><input type="text" class="span6 required pathChooserKo" data-bind="fileChooser: $data, value: value" /></td>
+                <td>
+                  <a class="btn" href="#" data-bind="click: $root.removeParam">${ _('Delete') }</a>
+                </td>
+              </tr>
+            </tbody>
+          </table>
+
+          <a class="btn" href="#" data-bind="click: $root.addParam">${ _('Add parameter') }</a>
+
+          <div class="actions">
+            <button data-bind="click: tryExecuteQuery, enable: $root.appNames().length > 0 && $root.classPath()"
+              type="button" id="executeQuery" class="btn btn-primary disable-feedback"
+              tabindex="2" data-loading-text="${ _("Executing...") }">
+              ${_('Execute')}
+            </button>
+            <button data-bind="click: trySaveQuery, css: {'hide': !$root.query.id() || $root.query.id() == -1}" type="button" class="btn hide">${_('Save')}</button>
+            <button data-bind="click: trySaveAsQuery" type="button" class="btn">${_('Save as...')}</button>
+            &nbsp; ${_('or create a')} &nbsp;<a type="button" class="btn" href="${ url('spark:editor') }">${_('New app configuration')}</a>
+            <span class="pull-right">
+              <a type="button" class="btn" data-bind="visible: rows().length != 0, attr: {'href': '${ url('spark:download_result') }' + $root.query.jobId()}">${_('Download')}</a>
+            </span>
+          </div>
 
-    <div data-bind="css: {'hide': !resultsEmpty()}" class="hide">
-      <div class="card card-small scrollable">
-        <div class="row-fluid">
-          <div class="span10 offset1 center empty-wrapper">
-            <i class="fa fa-frown-o"></i>
-            <h1>${_('The server returned no results.')}</h1>
-            <br/>
+          <div data-bind="css: {'hide': rows().length == 0}" class="hide">
+            <div class="card card-small scrollable">
+              <table class="table table-striped table-condensed resultTable" cellpadding="0" cellspacing="0" data-tablescroller-min-height-disable="true" data-tablescroller-enforce-height="true">
+                <thead>
+                  <tr>
+                    <th>${ _('Key') }</th>
+                    <th>${ _('Value') }</th>
+                  </tr>
+                </thead>
+              </table>
+            </div>
           </div>
-        </div>
-      </div>
-    </div>
 
-    <div id="wait-info" class="hide">
-      <div class="card card-small scrollable">
-        <div class="row-fluid">
-          <div class="span10 offset1 center" style="padding: 30px">
-            <!--[if !IE]><!--><i class="fa fa-spinner fa-spin" style="font-size: 60px; color: #DDD"></i><!--<![endif]-->
-            <!--[if IE]><img src="/static/art/spinner.gif" /><![endif]-->
+          <div data-bind="css: {'hide': !resultsEmpty()}" class="hide">
+            <div class="card card-small scrollable">
+              <div class="row-fluid">
+                <div class="span10 offset1 center empty-wrapper">
+                  <i class="fa fa-frown-o"></i>
+                  <h1>${_('The server returned no results.')}</h1>
+                  <br/>
+                </div>
+              </div>
+            </div>
           </div>
-        </div>
+
+          <div id="wait-info" class="hide">
+            <div class="card card-small scrollable">
+              <div class="row-fluid">
+                <div class="span10 offset1 center" style="padding: 30px">
+                  <!--[if !IE]><!--><i class="fa fa-spinner fa-spin" style="font-size: 60px; color: #DDD"></i><!--<![endif]-->
+                  <!--[if IE]><img src="/static/art/spinner.gif" /><![endif]-->
+                </div>
+              </div>
+            </div>
+          </div>
+        </p>
       </div>
     </div>
-
   </div>
 
-  </div>
-</div>
 
 
 <div id="saveAsQueryModal" class="modal hide fade">
@@ -451,7 +433,7 @@ ${ common.createContextModal() }
     success: function(response, newValue) {
       viewModel.query.name(newValue);
     },
-    emptytext: "${ _('Query name') }"
+    emptytext: "${ _('App configuration name') }"
   });
 
   $("#query-description").editable({
@@ -464,7 +446,7 @@ ${ common.createContextModal() }
 
   // Events and datatables
   $(document).on('saved.query', function() {
-    $.jHueNotify.info("${_('Query saved successfully!')}")
+    $.jHueNotify.info("${_('App saved successfully!')}")
   });
 
   var dataTable = null;
@@ -533,9 +515,14 @@ ${ common.createContextModal() }
     $("#executeQuery").button("reset");
     resultsTable();
   });
-  $(document).on('created.context', function() {
-    $('#createContextModal').modal('hide');
-  });
+
+  $(document).on("created.context", function() {
+      $("#createContextModal").modal("hide");
+      $("#createContextBtn").button("reset");
+      $("input[data-default]").each(function(){
+        $(this).val($(this).data("default"));
+      });
+    });
 
   // Server error handling.
   $(document).on('server.error', function(e, data) {

+ 15 - 32
apps/spark/src/spark/templates/list_applications.mako

@@ -17,7 +17,7 @@
   from desktop.views import commonheader, commonfooter
   from django.utils.translation import ugettext as _
 %>
-
+<%namespace name="actionbar" file="actionbar.mako" />
 <%namespace name="common" file="common.mako" />
 
 ${ commonheader(_('Applications'), app_name, user) | n,unicode }
@@ -28,9 +28,16 @@ ${ common.navbar('applications') }
   <div class="card card-small">
     <h1 class="card-heading simple">${_('Applications')}</h1>
 
-    <button type="button" class="btn uploadAppModalBtn">
-      <i class="fa fa-plus-circle"> ${ _('Upload app') }</i>
-    </button>
+    <%actionbar:render>
+      <%def name="search()">
+          <input id="filterInput" type="text" class="input-xlarge search-query" placeholder="${_('Search for name')}">
+      </%def>
+      <%def name="creation()">
+         <button type="button" class="btn uploadAppModalBtn"><i class="fa fa-plus-circle"></i> ${ _('Upload app') }</button>
+      </%def>
+    </%actionbar:render>
+
+
 
     <table class="table table-condensed datatables">
     <thead>
@@ -57,23 +64,6 @@ ${ common.navbar('applications') }
   </div>
 </div>
 
-<div id="deleteQuery" class="modal hide fade">
-  <form id="deleteQueryForm" action="${ url(app_name + ':delete_design') }" method="POST">
-    <input type="hidden" name="skipTrash" id="skipTrash" value="false"/>
-    <div class="modal-header">
-      <a href="#" class="close" data-dismiss="modal">&times;</a>
-      <h3 id="deleteQueryMessage">${_('Confirm action')}</h3>
-    </div>
-    <div class="modal-footer">
-      <input type="button" class="btn" data-dismiss="modal" value="${_('Cancel')}" />
-      <input type="submit" class="btn btn-danger" value="${_('Yes')}"/>
-    </div>
-    <div class="hide">
-      <select name="designs_selection" data-bind="options: availableSavedQueries, selectedOptions: chosenSavedQueries" multiple="true"></select>
-    </div>
-  </form>
-</div>
-
 
 ${ common.uploadAppModal() }
 
@@ -82,14 +72,8 @@ ${ common.uploadAppModal() }
 
 <script type="text/javascript" charset="utf-8">
   $(document).ready(function () {
-    var viewModel = {
-        availableSavedQueries : ko.observableArray(${ applications_json | n,unicode }),
-        chosenSavedQueries : ko.observableArray([])
-    };
-
-    ko.applyBindings(viewModel);
 
-    var savedQueries = $(".datatables").dataTable({
+    var apps = $(".datatables").dataTable({
       "sDom":"<'row'r>t<'row'<'span8'i><''p>>",
       "bPaginate": false,
       "bLengthChange": false,
@@ -109,14 +93,13 @@ ${ common.uploadAppModal() }
     });
 
     $("#filterInput").keyup(function () {
-      savedQueries.fnFilter($(this).val());
+      apps.fnFilter($(this).val());
     });
 
-    $('.uploadAppModalBtn').click(function(){
-      $('#uploadAppModal').modal('show');
+    $(".uploadAppModalBtn").on("click", function(){
+      $("#uploadAppModal").modal("show");
     });
 
-    $("a[data-row-selector='true']").jHueRowSelector();
   });
 </script>
 

+ 95 - 44
apps/spark/src/spark/templates/list_contexts.mako

@@ -17,7 +17,7 @@
   from desktop.views import commonheader, commonfooter
   from django.utils.translation import ugettext as _
 %>
-
+<%namespace name="actionbar" file="actionbar.mako" />
 <%namespace name="common" file="common.mako" />
 
 ${ commonheader(_('Context'), app_name, user) | n,unicode }
@@ -28,12 +28,19 @@ ${ common.navbar('contexts') }
   <div class="card card-small">
     <h1 class="card-heading simple">${_('Contexts')}</h1>
 
-    <button type="button" class="btn createContextModalBtn">
-      <i class="fa fa-plus-circle"> ${ _('Create context') }</i>
-    </button>
-    <a href="#" id="deleteContextBtn" title="${_('Delete forever')}" class="btn">
-      <i class="fa fa-bolt"></i> ${ _('Delete') }
-    </a>
+    <%actionbar:render>
+      <%def name="search()">
+          <input id="filterInput" type="text" class="input-xlarge search-query" placeholder="${_('Search for name')}">
+      </%def>
+      <%def name="actions()">
+        <button type="button" id="deleteContextBtn" title="${_('Delete forever')}" class="btn" disabled="disabled">
+          <i class="fa fa-bolt"></i> ${ _('Delete selected') }
+        </button>
+      </%def>
+      <%def name="creation()">
+         <button type="button" class="btn createContextModalBtn"><i class="fa fa-plus-circle"></i> ${ _('Create context') }</button>
+      </%def>
+    </%actionbar:render>
 
     <table class="table table-condensed datatables" id="contextTable">
     <thead>
@@ -49,8 +56,15 @@ ${ common.navbar('contexts') }
         <td data-name="${ contextz }">${ contextz }</td>
       </tr>
       % endfor
-
     </tbody>
+    <tfoot>
+      <tr class="hide">
+        <td colspan="2" style="text-align: center">
+          <!--[if !IE]><!--><i class="fa fa-spinner fa-spin" style="font-size: 20px; color: #DDD"></i><!--<![endif]-->
+          <!--[if IE]><img src="/static/art/spinner.gif"/><![endif]-->
+        </td>
+      </tr>
+    </tfoot>
   </table>
     <div class="card-body">
       <p>
@@ -72,7 +86,7 @@ ${ common.navbar('contexts') }
       <input type="submit" class="btn btn-danger" value="${_('Yes')}"/>
     </div>
     <div class="hide">
-      <select name="contexts_selection" data-bind="options: availableSavedQueries, selectedOptions: chosenSavedQueries" multiple="true"></select>
+      <select name="contexts_selection" data-bind="options: availableSavedContexts, selectedOptions: chosenSavedContexts" multiple="true"></select>
     </div>
   </form>
 </div>
@@ -90,41 +104,46 @@ ${ common.createContextModal() }
 
   $(document).ready(function() {
     var viewModel = {
-        availableSavedQueries : ko.observableArray(${ contexts_json | n,unicode }),
-        chosenSavedQueries : ko.observableArray([])
+        availableSavedContexts : ko.observableArray(${ contexts_json | n,unicode }),
+        chosenSavedContexts : ko.observableArray([])
     };
 
     ko.applyBindings(viewModel, $('#deleteContext')[0]);
 
-    //var sparkViewModel = new sparkViewModel();
-    //ko.applyBindings(sparkViewModel, $('#createContextModal')[0]);
-
-    var savedQueries = $(".datatables").dataTable({
-      "sDom":"<'row'r>t<'row'<'span8'i><''p>>",
-      "bPaginate":false,
-      "bLengthChange":false,
-      "bInfo":false,
-      "aaSorting":[
-        [2, 'desc']
-      ],
-      "aoColumns":[
-        null,
-        null
-      ],
-      "oLanguage":{
-        "sEmptyTable":"${_('No data available')}",
-        "sZeroRecords":"${_('No matching records')}",
-      },
-      "bStateSave": true
-    });
+    var sViewModel = new sparkViewModel();
+    ko.applyBindings(sViewModel, $('#createContextModal')[0]);
+
+    var savedContexts;
+    function createDataTable () {
+      savedContexts = $(".datatables").dataTable({
+        "sDom":"<'row'r>t<'row'<'span8'i><''p>>",
+        "bPaginate":false,
+        "bLengthChange":false,
+        "bInfo":false,
+        "aaSorting":[
+          [1, "desc"]
+        ],
+        "aoColumns":[
+          {"bSortable": false},
+          null
+        ],
+        "oLanguage":{
+          "sEmptyTable":"${_('No data available')}",
+          "sZeroRecords":"${_('No matching records')}",
+        },
+        "bDestroy": true
+      });
+    }
+
+    createDataTable();
 
-    $("#filterInput").keyup(function () {
-      savedQueries.fnFilter($(this).val());
+    $("#filterInput").on("keyup", function () {
+      savedContexts.fnFilter($(this).val());
     });
 
     $("a[data-row-selector='true']").jHueRowSelector();
 
-    $(".selectAll").click(function () {
+    $(".selectAll").on("click", function () {
       if ($(this).attr("checked")) {
         $(this).removeAttr("checked").removeClass("fa-check");
         $("." + $(this).data("selectables")).removeClass("fa-check").removeAttr("checked");
@@ -136,7 +155,7 @@ ${ common.createContextModal() }
       toggleActions();
     });
 
-    $(".savedCheck").click(function () {
+    $(document).on("click", ".savedCheck", function () {
       if ($(this).attr("checked")) {
         $(this).removeClass("fa-check").removeAttr("checked");
       }
@@ -171,29 +190,61 @@ ${ common.createContextModal() }
       if (selector.length >= 1) {
         $("#trashContextBtn").removeAttr("disabled");
         $("#trashContextCaretBtn").removeAttr("disabled");
+        $("#deleteContextBtn").removeAttr("disabled");
       }
     }
 
-    function deleteQueries() {
-      viewModel.chosenSavedQueries.removeAll();
+    function deleteContexts() {
+      viewModel.chosenSavedContexts.removeAll();
       $(".hueCheckbox[checked='checked']").each(function( index ) {
-        viewModel.chosenSavedQueries.push($(this).data("delete-name"));
+        viewModel.chosenSavedContexts.push($(this).data("delete-name"));
       });
 
       $("#deleteContext").modal("show");
     }
 
-    $("#deleteContextBtn").click(function () {
+    $("#deleteContextBtn").on("click", function () {
       $("#skipTrash").val(true);
-      $("#deleteContextMessage").text("${ _('Delete the selected queries?') }");
-      deleteQueries();
+      $("#deleteContextMessage").text("${ _('Delete the selected contexts?') }");
+      deleteContexts();
     });
 
-    $('.createContextModalBtn').click(function(){
-      $('#createContextModal').modal('show');
+    $(".createContextModalBtn").on("click", function(){
+      $("#createContextModal").modal("show");
     });
 
     $("a[data-row-selector='true']").jHueRowSelector();
+
+    $(document).on("created.context", function() {
+      $(".datatables tfoot tr").removeClass("hide");
+      $(".datatables tbody").empty();
+      savedContexts.fnClearTable();
+      $.getJSON("${ url('spark:list_contexts')}", function(data){
+        viewModel.availableSavedContexts(data.contexts);
+        var _h  = "";
+        $(data.contexts).each(function(cnt, ctx){
+          _h += getContextRow(ctx);
+        });
+        $(".datatables").find("tbody").html(_h);
+        createDataTable();
+      });
+      $("#createContextModal").modal("hide");
+      $("#createContextBtn").button("reset");
+      $("input[data-default]").each(function(){
+        $(this).val($(this).data("default"));
+      });
+      $(".datatables tfoot tr").addClass("hide");
+    });
+
+    function getContextRow(context) {
+      return '<tr>' +
+        '<td data-row-selector-exclude="true">' +
+        '<div class="hueCheckbox savedCheck fa" data-delete-name="'+context+'" data-row-selector-exclude="true"></div>' +
+        '</td>' +
+        '<td data-name="'+context+'">'+context+'</td>' +
+      '</tr>';
+    }
+
   });
 </script>
 

+ 3 - 26
apps/spark/src/spark/templates/list_jobs.mako

@@ -71,41 +71,18 @@ ${ common.navbar('jobs') }
   </div>
 </div>
 
-<div id="deleteQuery" class="modal hide fade">
-  <form id="deleteQueryForm" action="${ url(app_name + ':delete_design') }" method="POST">
-    <input type="hidden" name="skipTrash" id="skipTrash" value="false"/>
-    <div class="modal-header">
-      <a href="#" class="close" data-dismiss="modal">&times;</a>
-      <h3 id="deleteQueryMessage">${_('Confirm action')}</h3>
-    </div>
-    <div class="modal-footer">
-      <input type="button" class="btn" data-dismiss="modal" value="${_('Cancel')}" />
-      <input type="submit" class="btn btn-danger" value="${_('Yes')}"/>
-    </div>
-    <div class="hide">
-      <select name="designs_selection" data-bind="options: availableSavedQueries, selectedOptions: chosenSavedQueries" multiple="true"></select>
-    </div>
-  </form>
-</div>
-
 <script src="/static/ext/js/knockout-min.js" type="text/javascript" charset="utf-8"></script>
 
 <script type="text/javascript" charset="utf-8">
   $(document).ready(function () {
-    var viewModel = {
-      availableSavedQueries : ko.observableArray(${ jobs_json | n,unicode }),
-      chosenSavedQueries : ko.observableArray([])
-    };
-
-    ko.applyBindings(viewModel);
 
-    var savedQueries = $(".datatables").dataTable({
+    var jobs = $(".datatables").dataTable({
       "sDom":"<'row'r>t<'row'<'span8'i><''p>>",
       "bPaginate":false,
       "bLengthChange":false,
       "bInfo":false,
       "aaSorting":[
-        [4, 'desc']
+        [4, "desc"]
       ],
       "aoColumns":[
         null,
@@ -123,7 +100,7 @@ ${ common.navbar('jobs') }
     });
 
     $("#filterInput").keyup(function () {
-      savedQueries.fnFilter($(this).val());
+      jobs.fnFilter($(this).val());
     });
 
     $("a[data-row-selector='true']").jHueRowSelector();

+ 12 - 0
apps/spark/static/js/spark.vm.js

@@ -25,6 +25,16 @@ function sparkViewModel() {
   self.selectedContext = ko.observable(0);
   self.classPath = ko.observable('');
 
+  self.autoContext.forEditing = ko.computed({
+    read: function() {
+        return this.autoContext().toString();
+    },
+    write: function(newValue) {
+         this.autoContext(newValue === "true");
+    },
+    owner: this
+  });
+
   self.query = ko.mapping.fromJS({
     'id': -1,
     'jobId': null,
@@ -299,6 +309,8 @@ function sparkViewModel() {
 
   self.createContext = function() {
     var data = $("#createContextForm").serialize(); // Not koified
+    $("#createContextBtn").attr("data-loading-text", $("#createContextBtn").text() + " ...");
+    $("#createContextBtn").button("loading");
     var request = {
       url: '/spark/api/create_context',
       dataType: 'json',