|
|
@@ -17,9 +17,6 @@
|
|
|
<%!
|
|
|
import cgi
|
|
|
import urllib
|
|
|
-import time as py_time
|
|
|
-from django.template.defaultfilters import date, time
|
|
|
-from desktop.lib.django_util import extract_field_data
|
|
|
from desktop.views import commonheader, commonfooter
|
|
|
from django.utils.translation import ugettext as _
|
|
|
%>
|
|
|
@@ -30,17 +27,28 @@ ${commonheader(_('Job Designer'), "jobsub", user, "100px")}
|
|
|
${layout.menubar(section='designs')}
|
|
|
|
|
|
<script src="/static/ext/js/datatables-paging-0.1.js" type="text/javascript" charset="utf-8"></script>
|
|
|
+<script src="/static/ext/js/knockout-2.0.0.js" type="text/javascript" charset="utf-8"></script>
|
|
|
+<script src="/static/ext/js/moment.min.js" type="text/javascript" charset="utf-8"></script>
|
|
|
+<script src="static/js/jobsub.ko.js" type="text/javascript" charset="utf-8"></script>
|
|
|
|
|
|
<div class="container-fluid">
|
|
|
<h1>${_('Job Designs')}</h1>
|
|
|
|
|
|
<%actionbar:render>
|
|
|
+ <%def name="actions()">
|
|
|
+ <button class="btn" title="${_('Submit')}" data-bind="click: submitDesign, enable: selectedDesigns().length == 1 && selectedDesigns()[0].canSubmit"><i class="icon-play"></i> ${_('Submit')}</button>
|
|
|
+ <button class="btn" title="${_('Edit')}" data-bind="click: editDesign, enable: selectedDesigns().length == 1 && selectedDesigns()[0].canSubmit"><i class="icon-pencil"></i> ${_('Edit')}</button>
|
|
|
+ <button class="btn" title="${_('Delete')}" data-bind="click: deleteDesign, enable: selectedDesigns().length == 1 && selectedDesigns()[0].canDelete"><i class="icon-trash"></i> ${_('Delete')}</button>
|
|
|
+ <button class="btn" title="${_('Clone')}" data-bind="click: cloneDesign, enable: selectedDesigns().length == 1"><i class="icon-share"></i> ${_('Clone')}</button>
|
|
|
+ </%def>
|
|
|
<%def name="creation()">
|
|
|
- <a href="${ url('jobsub.views.new_design', action_type='mapreduce') }" class="btn">${_('Create Mapreduce Design')}</a>
|
|
|
- <a href="${ url('jobsub.views.new_design', action_type='streaming') }" class="btn">${_('Create Streaming Design')}</a>
|
|
|
- <a href="${ url('jobsub.views.new_design', action_type='java') }" class="btn">${_('Create Java Design')}</a>
|
|
|
+ <span class="btn-group">
|
|
|
+ <a href="${ url('jobsub.views.new_design', action_type='mapreduce') }" class="btn" title="${_('Create Mapreduce Design')}" rel="tooltip"><i class="icon-plus-sign"></i> ${_('Mapreduce')}</a>
|
|
|
+ <a href="${ url('jobsub.views.new_design', action_type='streaming') }" class="btn" title="${_('Create Streaming Design')}" rel="tooltip"><i class="icon-plus-sign"></i> ${_('Streaming')}</a>
|
|
|
+ <a href="${ url('jobsub.views.new_design', action_type='java') }" class="btn"title="${_('Create Java Design')}" rel="tooltip"><i class="icon-plus-sign"></i> ${_('Java')}</a>
|
|
|
+ </span>
|
|
|
%if show_install_examples:
|
|
|
- <a id="installSamplesLink" href="javascript:void(0)" data-confirmation-url="${url('jobsub.views.setup')}" class="btn" >${_('Install Samples')}</a>
|
|
|
+ <a id="installSamplesLink" href="javascript:void(0)" data-confirmation-url="${url('jobsub.views.setup')}" class="btn"><i class="icon-download-alt"></i> ${_('Install Samples')}</a>
|
|
|
%endif
|
|
|
</%def>
|
|
|
</%actionbar:render>
|
|
|
@@ -48,50 +56,37 @@ ${layout.menubar(section='designs')}
|
|
|
<table id="designTable" class="table table-condensed datatables">
|
|
|
<thead>
|
|
|
<tr>
|
|
|
+ <th width="1%"><div data-bind="click: selectAll, css: {hueCheckbox: true, 'icon-ok': allSelected}"></div></th>
|
|
|
<th>${_('Owner')}</th>
|
|
|
<th>${_('Name')}</th>
|
|
|
<th>${_('Type')}</th>
|
|
|
<th>${_('Description')}</th>
|
|
|
<th>${_('Last Modified')}</th>
|
|
|
- <th nowrap="nowrap"> </th>
|
|
|
</tr>
|
|
|
</thead>
|
|
|
- <tbody>
|
|
|
- %for design in designs:
|
|
|
- <tr>
|
|
|
- <td>${design.owner.username}</td>
|
|
|
- <td>${design.name}</td>
|
|
|
- <td>${design.root_action.action_type}</td>
|
|
|
- <td>${design.description}</td>
|
|
|
- <td nowrap="nowrap" data-sort-value="${py_time.mktime(design.last_modified.timetuple())}">${date(design.last_modified)} ${time(design.last_modified).replace("p.m.","PM").replace("a.m.","AM")}</td>
|
|
|
- <td nowrap="nowrap" class="right">
|
|
|
- %if currentuser.username == design.owner.username:
|
|
|
- <a title="${_('Submit %(name)s to the cluster') % dict(name=design.name)}" class="btn small submitConfirmation"
|
|
|
- alt="${_('Submit %(name)s to the cluster') % dict(name=design.name)}"
|
|
|
- href="javascript:void(0)"
|
|
|
- data-param-url="${ url('jobsub.views.get_design_params', design_id=design.id) }"
|
|
|
- data-submit-url="${ url('jobsub.views.submit_design', design_id=design.id) }">${_('Submit')}</a>
|
|
|
- <a title="${_('Edit %(name)s') % dict(name=design.name)}" class="btn small"
|
|
|
- href="${ url('jobsub.views.edit_design', design_id=design.id) }" data-row-selector="true">${_('Edit')}</a>
|
|
|
- %endif
|
|
|
- %if currentuser.is_superuser or currentuser.username == design.owner.username:
|
|
|
- <a title="${_('Delete %(name)s') % dict(name=design.name)}" class="btn small deleteConfirmation"
|
|
|
- alt="${_('Are you sure you want to delete %(name)s?') % dict(name=design.name)}"
|
|
|
- href="javascript:void(0)"
|
|
|
- data-confirmation-url="${ url('jobsub.views.delete_design', design_id=design.id) }">${_('Delete')}</a>
|
|
|
- %endif
|
|
|
- <a title="${_('Clone %(name)s') % dict(name=design.name)}" class="btn small" href="${ url('jobsub.views.clone_design', design_id=design.id) }">${_('Clone')}</a>
|
|
|
- </td>
|
|
|
- </tr>
|
|
|
- %endfor
|
|
|
+ <tbody id="designs" data-bind="template: {name: 'designTemplate', foreach: designs}">
|
|
|
+
|
|
|
</tbody>
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
+<script id="designTemplate" type="text/html">
|
|
|
+ <tr style="cursor: pointer">
|
|
|
+ <td class="center" data-bind="click: handleSelect" style="cursor: default">
|
|
|
+ <div data-bind="visible: name != '..', css: {hueCheckbox: name != '..', 'icon-ok': selected}"></div>
|
|
|
+ </td>
|
|
|
+ <td data-bind="click: $root.editDesign, text: owner"></td>
|
|
|
+ <td data-bind="click: $root.editDesign, text: name"></td>
|
|
|
+ <td data-bind="click: $root.editDesign, text: type"></td>
|
|
|
+ <td data-bind="click: $root.editDesign, text: description"></td>
|
|
|
+ <td data-bind="click: $root.editDesign, text: lastModified, attr: { 'data-sort-value': lastModifiedMillis }" style="white-space: nowrap;"></td>
|
|
|
+ </tr>
|
|
|
+</script>
|
|
|
+
|
|
|
|
|
|
<div id="submitWf" class="modal hide fade">
|
|
|
- <form id="submitWfForm" action="" method="POST">
|
|
|
+ <form id="submitWfForm" action="" method="POST" style="margin:0">
|
|
|
<div class="modal-header">
|
|
|
<a href="#" class="close" data-dismiss="modal">×</a>
|
|
|
<h3 id="submitWfMessage">${_('Submit this design?')}</h3>
|
|
|
@@ -104,26 +99,26 @@ ${layout.menubar(section='designs')}
|
|
|
</div>
|
|
|
<div class="modal-footer">
|
|
|
<input id="submitBtn" type="submit" class="btn primary" value="${_('Submit')}"/>
|
|
|
- <a href="#" class="btn secondary hideModal">${_('Cancel')}</a>
|
|
|
+ <a href="#" class="btn secondary" data-dismiss="modal">${_('Cancel')}</a>
|
|
|
</div>
|
|
|
</form>
|
|
|
</div>
|
|
|
|
|
|
<div id="deleteWf" class="modal hide fade">
|
|
|
- <form id="deleteWfForm" action="" method="POST">
|
|
|
+ <form id="deleteWfForm" action="" method="POST" style="margin:0">
|
|
|
<div class="modal-header">
|
|
|
<a href="#" class="close" data-dismiss="modal">×</a>
|
|
|
<h3 id="deleteWfMessage">${_('Delete this design?')}</h3>
|
|
|
</div>
|
|
|
<div class="modal-footer">
|
|
|
<input type="submit" class="btn primary" value="${_('Yes')}"/>
|
|
|
- <a href="#" class="btn secondary hideModal">${_('No')}</a>
|
|
|
+ <a href="#" class="btn secondary" data-dismiss="modal">${_('No')}</a>
|
|
|
</div>
|
|
|
</form>
|
|
|
</div>
|
|
|
|
|
|
<div id="installSamples" class="modal hide fade">
|
|
|
- <form id="installSamplesForm" action="${url('jobsub.views.setup')}" method="POST">
|
|
|
+ <form id="installSamplesForm" action="${url('jobsub.views.setup')}" method="POST" style="margin:0">
|
|
|
<div class="modal-header">
|
|
|
<a href="#" class="close" data-dismiss="modal">×</a>
|
|
|
<h3>${_('Install sample job designs?')}</h3>
|
|
|
@@ -140,67 +135,44 @@ ${layout.menubar(section='designs')}
|
|
|
|
|
|
|
|
|
<script type="text/javascript" charset="utf-8">
|
|
|
+
|
|
|
+ var deleteMessage = "${_('Are you sure you want to delete %(name)s?') % dict(name='##PLACEHOLDER##')}";
|
|
|
+ var submitMessage = "${_('Submit %(name)s to the cluster') % dict(name='##PLACEHOLDER##')}";
|
|
|
+
|
|
|
$(document).ready(function() {
|
|
|
|
|
|
- $(".deleteConfirmation").click(function(){
|
|
|
- var _this = $(this);
|
|
|
- var _action = _this.attr("data-confirmation-url");
|
|
|
- $("#deleteWfForm").attr("action", _action);
|
|
|
- $("#deleteWfMessage").text(_this.attr("alt"));
|
|
|
- $("#deleteWf").modal("show");
|
|
|
- });
|
|
|
- $("#deleteWf .hideModal").click(function(){
|
|
|
- $("#deleteWf").modal("hide");
|
|
|
- });
|
|
|
+ var designTable, viewModel;
|
|
|
|
|
|
- $(".submitConfirmation").click(function(){
|
|
|
- var _this = $(this);
|
|
|
- var _action = _this.attr("data-submit-url");
|
|
|
- $("#submitWfForm").attr("action", _action);
|
|
|
- $("#submitWfMessage").text(_this.attr("alt"));
|
|
|
- // We will show the model form, but disable the submit button
|
|
|
- // until we've finish loading the parameters via ajax.
|
|
|
- $("#submitBtn").attr("disabled", "disabled");
|
|
|
- $("#submitWf").modal("show");
|
|
|
-
|
|
|
- $.get(_this.attr("data-param-url"), function(data) {
|
|
|
- var params = data["params"]
|
|
|
- var container = $("#param-container");
|
|
|
- container.empty();
|
|
|
- for (key in params) {
|
|
|
- if (!params.hasOwnProperty(key)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- container.append(
|
|
|
- $("<div/>").addClass("clearfix")
|
|
|
- .append($("<label/>").text(params[key]))
|
|
|
- .append(
|
|
|
- $("<div/>").addClass("input")
|
|
|
- .append($("<input/>").attr("name", key).attr("type", "text"))
|
|
|
- )
|
|
|
- )
|
|
|
- }
|
|
|
- // Good. We can submit now.
|
|
|
- $("#submitBtn").removeAttr("disabled");
|
|
|
- }, "json");
|
|
|
+ $("#filterInput").keyup(function() {
|
|
|
+ if (designTable != null){
|
|
|
+ designTable.fnFilter($(this).val());
|
|
|
+ }
|
|
|
});
|
|
|
- $("#submitWf .hideModal").click(function(){
|
|
|
- $("#submitWf").modal("hide");
|
|
|
+
|
|
|
+ $("#installSamplesLink").click(function(){
|
|
|
+ $("#installSamples").modal("show");
|
|
|
});
|
|
|
|
|
|
- var oTable = $('#designTable').dataTable( {
|
|
|
+ viewModel = new JobSubModel(${designs});
|
|
|
+ ko.applyBindings(viewModel);
|
|
|
+ designTable = $('#designTable').dataTable( {
|
|
|
"sPaginationType": "bootstrap",
|
|
|
"bLengthChange": false,
|
|
|
"sDom": "<'row'r>t<'row'<'span8'i><''p>>",
|
|
|
"aoColumns": [
|
|
|
+ { "bSortable": false },
|
|
|
null,
|
|
|
null,
|
|
|
null,
|
|
|
null,
|
|
|
- { "sSortDataType": "dom-sort-value", "sType": "numeric" },
|
|
|
- { "bSortable": false }
|
|
|
+ { "sSortDataType": "dom-sort-value", "sType": "numeric" }
|
|
|
],
|
|
|
- "aaSorting": [[ 4, "desc" ]],
|
|
|
+ "aaSorting": [[ 5, "desc" ]],
|
|
|
+ "fnPreDrawCallback": function( oSettings ) {
|
|
|
+ if (viewModel.allSelected()){
|
|
|
+ viewModel.selectAll();
|
|
|
+ }
|
|
|
+ },
|
|
|
"oLanguage": {
|
|
|
"sEmptyTable": "${_('No data available in table')}",
|
|
|
"sInfo": "${_('Showing _START_ to _END_ of _TOTAL_ entries')}",
|
|
|
@@ -216,14 +188,7 @@ ${layout.menubar(section='designs')}
|
|
|
}
|
|
|
});
|
|
|
|
|
|
- $("#filterInput").keyup(function() {
|
|
|
- oTable.fnFilter($(this).val());
|
|
|
- });
|
|
|
-
|
|
|
- $("#installSamplesLink").click(function(){
|
|
|
- $("#installSamples").modal("show");
|
|
|
- });
|
|
|
-
|
|
|
+ $(".btn[rel='tooltip']").tooltip({placement:'bottom'});
|
|
|
$("a[data-row-selector='true']").jHueRowSelector();
|
|
|
});
|
|
|
</script>
|