designs.mako 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. ## or more contributor license agreements. See the NOTICE file
  2. ## distributed with this work for additional information
  3. ## regarding copyright ownership. Cloudera, Inc. licenses this file
  4. ## to you under the Apache License, Version 2.0 (the
  5. ## "License"); you may not use this file except in compliance
  6. ## with the License. You may obtain a copy of the License at
  7. ##
  8. ## http://www.apache.org/licenses/LICENSE-2.0
  9. ##
  10. ## Unless required by applicable law or agreed to in writing, software
  11. ## distributed under the License is distributed on an "AS IS" BASIS,
  12. ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. ## See the License for the specific language governing permissions and
  14. ## limitations under the License.
  15. <%!
  16. import cgi
  17. import urllib
  18. import time
  19. from desktop.views import commonheader, commonfooter
  20. from django.utils.translation import ugettext as _
  21. %>
  22. <%namespace name="actionbar" file="actionbar.mako" />
  23. ${ commonheader(None, "jobsub", user, "60px") | n,unicode }
  24. <link rel="stylesheet" href="/jobsub/static/css/jobsub.css">
  25. <script src="/static/ext/js/mustache.js" type="text/javascript" charset="utf-8"></script>
  26. <script src="/static/ext/js/routie-0.3.0.min.js" type="text/javascript" charset="utf-8"></script>
  27. <script src="/static/ext/js/datatables-paging-0.1.js" type="text/javascript" charset="utf-8"></script>
  28. <script src="/static/ext/js/knockout-2.1.0.js" type="text/javascript" charset="utf-8"></script>
  29. <script src="/static/ext/js/knockout.mapping-2.3.2.js" type="text/javascript" charset="utf-8"></script>
  30. <script src="/static/ext/js/moment.min.js" type="text/javascript" charset="utf-8"></script>
  31. <script src="/oozie/static/js/workflow.models.js" type="text/javascript" charset="utf-8"></script>
  32. <script src="/oozie/static/js/workflow.node-fields.js" type="text/javascript" charset="utf-8"></script>
  33. <script src="/jobsub/static/js/jobsub.templates.js" type="text/javascript" charset="utf-8"></script>
  34. <script src="/jobsub/static/js/jobsub.ko.js" type="text/javascript" charset="utf-8"></script>
  35. <script src="/jobsub/static/js/jobsub.js" type="text/javascript" charset="utf-8"></script>
  36. <div class="container-fluid">
  37. <h1>${_('Job Designs')}</h1>
  38. <%actionbar:render>
  39. <%def name="actions()">
  40. <div class="btn-toolbar" style="display: inline; vertical-align: middle">
  41. <button id="home" class="btn" title="${_('Home')}"><i class="icon-share"></i> ${_('Home')}</button>
  42. &nbsp;
  43. <!-- ko ifnot: inTrash -->
  44. <button id="submit-design" class="btn" title="${_('Submit')}" data-bind="enable: selectedDesignObjects().length == 1"><i class="icon-play"></i> ${_('Submit')}</button>
  45. <button id="edit-design" class="btn" title="${_('Edit')}" data-bind="enable: selectedDesignObjects().length == 1"><i class="icon-pencil"></i> ${_('Edit')}</button>
  46. <button id="copy-designs" class="btn" title="${_('Copy')}" data-bind="enable: selectedDesignObjects().length > 0"><i class="icon-retweet"></i> ${_('Copy')}</button>
  47. <div id="delete-dropdown" class="btn-group" style="vertical-align: middle">
  48. <button id="delete-btn" class="btn toolbarBtn dropdown-toggle" title="${_('Delete')}" data-toggle="dropdown" data-bind="enable: selectedDesignObjects().length > 0">
  49. <i class="icon-remove"></i> ${_('Delete')}
  50. <span class="caret"></span>
  51. </button>
  52. <ul class="dropdown-menu" style="top: auto">
  53. <li><a href="javascript:void(0);" id="trash-designs" title="${_('Move to trash')}"><i class="icon-trash"></i> ${_('Move to trash')}</a></li>
  54. <li><a href="javascript:void(0);" id="destroy-designs" title="${_('Delete forever')}"><i class="icon-bolt"></i> ${_('Delete forever')}</a></li>
  55. </ul>
  56. </div>
  57. <!-- /ko -->
  58. <!-- ko if: inTrash -->
  59. <button id="restore-designs" class="btn" title="${_('Restore')}" data-bind="enable: selectedDesignObjects().length > 0"><i class="icon-cloud-upload"></i> ${_('Restore')}</button>
  60. <button id="destroy-designs" class="btn" title="${_('Delete forever')}" data-bind="enable: selectedDesignObjects().length > 0"><i class="icon-bolt"></i> ${_('Delete forever')}</button>
  61. <!-- /ko -->
  62. </div>
  63. </%def>
  64. <%def name="creation()">
  65. <div class="btn-toolbar" style="display: inline; vertical-align: middle">
  66. <!-- ko ifnot: inTrash -->
  67. <div id="new-action-dropdown" class="btn-group" style="vertical-align: middle">
  68. <a href="#" class="btn new-action-link dropdown-toggle" title="${_('New action')}" data-toggle="dropdown">
  69. <i class="icon-plus-sign"></i> ${_('New action')}
  70. <span class="caret"></span>
  71. </a>
  72. <ul class="dropdown-menu" style="top: auto">
  73. <li>
  74. <a href="#new-design/mapreduce" class="new-node-link" title="${_('Create MapReduce design')}" rel="tooltip"><i class="icon-plus-sign"></i> MapReduce</a>
  75. </li>
  76. <li>
  77. <a href="#new-design/java" class="new-node-link" title="${_('Create Java design')}" rel="tooltip"><i class="icon-plus-sign"></i> Java</a>
  78. </li>
  79. <li>
  80. <a href="#new-design/streaming" class="new-node-link" title="${_('Create Streaming design')}" rel="tooltip"><i class="icon-plus-sign"></i> Streaming</a>
  81. </li>
  82. <li>
  83. <a href="#new-design/hive" class="new-node-link" title="${_('Create Hive design')}" rel="tooltip"><i class="icon-plus-sign"></i> Hive</a>
  84. </li>
  85. <li>
  86. <a href="#new-design/pig" class="new-node-link" title="${_('Create Pig design')}" rel="tooltip"><i class="icon-plus-sign"></i> Pig</a>
  87. </li>
  88. <li>
  89. <a href="#new-design/sqoop" class="new-node-link" title="${_('Create Sqoop design')}" rel="tooltip"><i class="icon-plus-sign"></i> Sqoop</a>
  90. </li>
  91. <li>
  92. <a href="#new-design/fs" class="new-node-link" title="${_('Create Fs design')}" rel="tooltip"><i class="icon-plus-sign"></i> Fs</a>
  93. </li>
  94. <li>
  95. <a href="#new-design/ssh" class="new-node-link" title="${_('Create Ssh design')}" rel="tooltip"><i class="icon-plus-sign"></i> Ssh</a>
  96. </li>
  97. <li>
  98. <a href="#new-design/shell" class="new-node-link" title="${_('Create Shell design')}" rel="tooltip"><i class="icon-plus-sign"></i> Shell</a>
  99. </li>
  100. <li>
  101. <a href="#new-design/email" class="new-node-link" title="${_('Create Email design')}" rel="tooltip"><i class="icon-plus-sign"></i> Email</a>
  102. </li>
  103. <li>
  104. <a href="#new-design/distcp" class="new-node-link" title="${_('Create DistCp design')}" rel="tooltip"><i class="icon-plus-sign"></i> DistCp</a>
  105. </li>
  106. </ul>
  107. </div>
  108. &nbsp;&nbsp;
  109. <a href="#trashed-designs" class="btn"><i class="icon-trash"></i> ${ _('Trash') }</a>
  110. <!-- /ko -->
  111. <!-- ko if: inTrash -->
  112. <button type="button" id="purge-trashed-designs" class="btn" title="${ _('Delete all the designs') }"><i class="icon-fire"></i> ${ _('Empty') }</button>
  113. <!-- /ko -->
  114. </div>
  115. </%def>
  116. </%actionbar:render>
  117. <div id="design" class="section" data-bind="template: {'name': temporary().template(), 'data': temporary().design(), 'if': temporary().design()}"></div>
  118. <div id="list-designs" class="section">
  119. <table id="designTable" class="table table-condensed datatables">
  120. <thead>
  121. <tr>
  122. <th width="1%">
  123. <div id="selectAll" data-bind="click: toggleSelectAll, css: {'hueCheckbox': true, 'icon-ok': allSelected}"></div>
  124. </th>
  125. <th>${_('Name')}</th>
  126. <th>${_('Description')}</th>
  127. <th>${_('Owner')}</th>
  128. <th>${_('Type')}</th>
  129. <th>${_('Status')}</th>
  130. <th>${_('Last modified')}</th>
  131. <th>${_('Trashed')}</th>
  132. </tr>
  133. </thead>
  134. <tbody id="designs" data-bind="template: {'name': 'designTemplate', 'foreach': designs}">
  135. </tbody>
  136. </table>
  137. </div>
  138. </div>
  139. <script id="designTemplate" type="text/html">
  140. <tr style="cursor: pointer" data-bind="with: design">
  141. <td data-row-selector-exclude="true" data-bind="click: function(data, event) {$root.toggleSelect.call($root, $index());}" class="center" style="cursor: default">
  142. <div class="hueCheckbox savedCheck" data-row-selector-exclude="true" data-bind="css: {'hueCheckbox': name != '..', 'icon-ok': $parent.selected()}"></div>
  143. </td>
  144. <td data-bind="click: function(data, event) { window.location = '#edit-design/' + $index() }, text: name"></td>
  145. <td data-bind="click: function(data, event) { window.location = '#edit-design/' + $index() }, text: description"></td>
  146. <td data-bind="click: function(data, event) { window.location = '#edit-design/' + $index() }, text: owner"></td>
  147. <td data-bind="click: function(data, event) { window.location = '#edit-design/' + $index() }, text: node_type"></td>
  148. <td data-bind="click: function(data, event) { window.location = '#edit-design/' + $index() }">
  149. <!-- ko if: is_shared -->
  150. <span class="label label-info">shared</span>
  151. <!-- /ko -->
  152. <!-- ko ifnot: is_shared -->
  153. <span class="label label-info">personal</span>
  154. <!-- /ko -->
  155. </td>
  156. <td data-bind="click: function(data, event) { window.location = '#edit-design/' + $index() }, text: new Date(last_modified() * 1000).format('%B %d, %Y %I:%M %p'), attr: { 'data-sort-value': last_modified() }"></td>
  157. <td data-bind="text: is_trashed"></td>
  158. </tr>
  159. </script>
  160. <div id="submitWf" class="modal hide fade"></div>
  161. <div id="trashWf" class="modal hide fade">
  162. <form id="trashWfForm" action="#" method="POST" style="margin:0">
  163. <div class="modal-header">
  164. <a href="#" class="close" data-dismiss="modal">&times;</a>
  165. <h3 id="trashWfMessage">${_('Move the selected designs to trash?')}</h3>
  166. </div>
  167. <div class="modal-footer">
  168. <a href="#" class="btn" data-dismiss="modal">${_('No')}</a>
  169. <input type="submit" class="btn btn-danger" value="${_('Yes')}" data-dismiss="modal" data-bind="click: trashDesigns" />
  170. </div>
  171. </form>
  172. </div>
  173. <div id="destroyWf" class="modal hide fade">
  174. <form id="destroyWfForm" action="#" method="POST" style="margin:0">
  175. <div class="modal-header">
  176. <a href="#" class="close" data-dismiss="modal">&times;</a>
  177. <h3 id="destroyWfMessage">${_('Delete the selected designs?')}</h3>
  178. </div>
  179. <div class="modal-footer">
  180. <a href="#" class="btn" data-dismiss="modal">${_('No')}</a>
  181. <input type="submit" class="btn btn-danger" value="${_('Yes')}" data-dismiss="modal" data-bind="click: destroyDesigns" />
  182. </div>
  183. </form>
  184. </div>
  185. <div id="purgeWf" class="modal hide fade">
  186. <form id="purgeWfForm" action="#" method="POST" style="margin:0">
  187. <div class="modal-header">
  188. <a href="#" class="close" data-dismiss="modal">&times;</a>
  189. <h3 id="purgeWfMessage">${_('Delete all trashed designs?')}</h3>
  190. </div>
  191. <div class="modal-footer">
  192. <a href="#" class="btn" data-dismiss="modal">${_('No')}</a>
  193. <input type="submit" class="btn btn-danger" value="${_('Yes')}" data-dismiss="modal" data-bind="click: destroyAllTrashedDesigns" />
  194. </div>
  195. </form>
  196. </div>
  197. <div id="restoreWf" class="modal hide fade">
  198. <form id="restoreWfForm" action="#" method="POST" style="margin:0">
  199. <div class="modal-header">
  200. <a href="#" class="close" data-dismiss="modal">&times;</a>
  201. <h3 id="restoreWfMessage">${_('Restore the selected designs?')}</h3>
  202. </div>
  203. <div class="modal-footer">
  204. <a href="#" class="btn" data-dismiss="modal">${_('No')}</a>
  205. <input type="submit" class="btn btn-danger" value="${_('Yes')}" data-dismiss="modal" data-bind="click: restoreDesigns" />
  206. </div>
  207. </form>
  208. </div>
  209. <div id="chooseFile" class="modal hide fade">
  210. <div class="modal-header">
  211. <a href="#" class="close" data-dismiss="modal">&times;</a>
  212. <h3>${_('Choose a file')}</h3>
  213. </div>
  214. <div class="modal-body">
  215. <div id="fileChooserModal">
  216. </div>
  217. </div>
  218. <div class="modal-footer">
  219. </div>
  220. </div>
  221. <script type="text/javascript" charset="utf-8">
  222. //// Contexts
  223. // Context matches up with jobsub.templates.js and various templates defined there.
  224. // If there is an update to any of the templates,
  225. // This global context may need to be updated.
  226. // Global context is extended to provide any uniqueness.
  227. var global_action_context = {
  228. 'alert': "${_('You can parameterize the values, using')} <code>$myVar</code> ${_('or')} <code>${"${"}myVar}</code>. ${_('When the design is submitted, you will be prompted for the actual value of ')}<code>myVar</code>.",
  229. 'paths_alert': "${_('All the paths are relative to the deployment directory. They can be absolute but this is not recommended.')}",
  230. 'smtp_alert': "${_('Requires some SMTP server configuration to be present (in oozie-site.xml).')}",
  231. 'ssh_alert': "${_('The ssh server requires passwordless login.')}",
  232. 'save': {
  233. 'name': "${_('Save')}",
  234. 'func': "function(data, event) {$root.saveDesign.call($root, data, event);}"
  235. },
  236. 'cancel': {
  237. 'name': "${_('Cancel')}",
  238. 'func': "function(data, event) {$root.closeDesign.call($parent, {}); reload();}"
  239. },
  240. 'name': {
  241. 'name': "${ _('Name') }",
  242. 'popover': "${ _('Name of the design.') }",
  243. 'js': {
  244. 'name': 'name'
  245. }
  246. },
  247. 'description': {
  248. 'name': "${ _('Description') }",
  249. 'popover': "${ _('Description of the design.') }",
  250. 'js': {
  251. 'name': 'description'
  252. }
  253. },
  254. 'is_shared': {
  255. 'name': "${ _('Is shared') }",
  256. 'popover': "${ _('Enable other users to have access to this job.') }",
  257. 'js': {
  258. 'name': 'is_shared'
  259. }
  260. },
  261. 'capture_output': {
  262. 'name': "${ _('Capture output') }",
  263. 'popover': "${ _('Capture the output of this job.') }",
  264. 'js': {
  265. 'name': 'capture_output'
  266. }
  267. },
  268. 'parameters': {
  269. 'title': "${ _('Oozie parameters') }",
  270. 'name': "${ _('Name') }",
  271. 'value': "${ _('Value') }",
  272. 'delete': {
  273. 'name': "${ _('Delete') }",
  274. 'func': 'function(data, event) { $parent.removeParameter.call($parent, data, event) }'
  275. },
  276. 'add': {
  277. 'name': "${ _('Add') }",
  278. 'func': 'addParameter'
  279. },
  280. 'ko': {
  281. 'items': "parameters",
  282. 'error_class': "parameters_error_class",
  283. 'condition': "parameters_condition"
  284. }
  285. },
  286. 'user': {
  287. 'name': "${ _('User') }",
  288. 'popover': "${ _('User to authenticate with.') }"
  289. },
  290. 'host': {
  291. 'name': "${ _('Host') }",
  292. 'popover': "${ _('Host to execute command on.') }"
  293. },
  294. 'command': {
  295. 'name': "${ _('Command') }",
  296. 'popover': "${ _('Command to execute.') }"
  297. },
  298. 'script_path': {
  299. 'name': "${ _('Script name') }",
  300. 'popover': "${ _('Path to the script to execute.') }"
  301. },
  302. 'jar_path': {
  303. 'name': "${ _('Jar path') }",
  304. 'popover': "${ _('Path to jar files on HDFS.') }"
  305. },
  306. 'main_class': {
  307. 'name': "${ _('Main class') }",
  308. 'popover': "${ _('Main class') }"
  309. },
  310. 'args': {
  311. 'name': "${ _('Args') }",
  312. 'popover': "${ _('Args') }"
  313. },
  314. 'java_opts': {
  315. 'name': "${ _('Java opts') }",
  316. 'popover': "${ _('Java opts') }"
  317. },
  318. 'mapper': {
  319. 'name': "${ _('Mapper') }",
  320. 'popover': "${ _('Mapper') }"
  321. },
  322. 'reducer': {
  323. 'name': "${ _('Reducer') }",
  324. 'popover': "${ _('Reducer') }"
  325. },
  326. 'to': {
  327. 'name': "${ _('TO addresses') }",
  328. 'popover': "${ _('TO addresses') }"
  329. },
  330. 'cc': {
  331. 'name': "${ _('CC addresses (optional)') }",
  332. 'popover': "${ _('CC addresses (optional)') }"
  333. },
  334. 'subject': {
  335. 'name': "${ _('Subject') }",
  336. 'popover': "${ _('Subject') }"
  337. },
  338. 'body': {
  339. 'name': "${ _('Body') }",
  340. 'popover': "${ _('Body') }"
  341. },
  342. 'job_properties': {
  343. 'title': "${ _('Job properties') }",
  344. 'name': "${ _('Property name') }",
  345. 'value': "${ _('Value') }",
  346. 'delete': {
  347. 'name': "${ _('Delete') }",
  348. 'func': 'function(data, event) { $parent.removeProperty.call($parent, data, event) }'
  349. },
  350. 'add': {
  351. 'name': "${ _('Add property') }",
  352. 'func': 'addProperty'
  353. },
  354. 'ko': {
  355. 'items': "job_properties",
  356. 'error_class': "job_properties_error_class",
  357. 'condition': "job_properties_condition"
  358. }
  359. },
  360. 'prepares': {
  361. 'title': "${ _('Prepare') }",
  362. 'name': "${ _('Type') }",
  363. 'value': "${ _('Value') }",
  364. 'delete': {
  365. 'name': "${ _('Delete') }",
  366. 'func': 'function(data, event) { $parent.removePrepare.call($parent, data, event) }'
  367. },
  368. 'add': {
  369. 'delete': {
  370. 'name': "${ _('Add delete') }",
  371. 'func': 'addPrepareDelete'
  372. },
  373. 'mkdir': {
  374. 'name': "${ _('Add mkdir') }",
  375. 'func': 'addPrepareMkdir'
  376. }
  377. },
  378. 'ko': {
  379. 'items': "prepares",
  380. 'error_class': "prepares_error_class",
  381. 'condition': "prepares_condition"
  382. }
  383. },
  384. 'params': {
  385. 'title': "${ _('Params') }",
  386. 'name': "${ _('Type') }",
  387. 'value': "${ _('Value') }",
  388. 'delete': {
  389. 'name': "${ _('Delete') }",
  390. 'func': 'function(data, event) { $parent.removeParam.call($parent, data, event) }'
  391. },
  392. 'add': [{
  393. 'name': "${ _('Add param') }",
  394. 'func': 'addParam'
  395. }],
  396. 'ko': {
  397. 'items': "params",
  398. 'error_class': "params_error_class",
  399. 'condition': "params_condition"
  400. }
  401. },
  402. 'files': {
  403. 'title': "${ _('Files') }",
  404. 'delete': {
  405. 'name': "${ _('Delete') }",
  406. 'func': 'function(data, event) { $parent.removeFile.call($parent, data, event) }'
  407. },
  408. 'add': {
  409. 'name': "${ _('Add file') }",
  410. 'func': 'addFile'
  411. },
  412. 'ko': {
  413. 'items': "files",
  414. 'error_class': "files_error_class",
  415. 'condition': "files_condition"
  416. }
  417. },
  418. 'archives': {
  419. 'title': "${ _('Archives') }",
  420. 'delete': {
  421. 'name': "${ _('Delete') }",
  422. 'func': 'function(data, event) { $parent.removeArchive.call($parent, data, event) }'
  423. },
  424. 'add': {
  425. 'name': "${ _('Add archive') }",
  426. 'func': 'addArchive'
  427. },
  428. 'ko': {
  429. 'items': "archives",
  430. 'error_class': "archives_error_class",
  431. 'condition': "archives_condition"
  432. }
  433. }
  434. };
  435. var contexts = {
  436. 'mapreduce': {
  437. 'title': "${ _('Job Design (mapreduce type)') }"
  438. },
  439. 'java': {
  440. 'title': "${ _('Job Design (java type)') }"
  441. },
  442. 'streaming': {
  443. 'title': "${ _('Job Design (streaming type)') }"
  444. },
  445. 'hive': {
  446. 'title': "${ _('Job Design (hive type)') }"
  447. },
  448. 'pig': {
  449. 'title': "${ _('Job Design (pig type)') }",
  450. 'params': {
  451. 'title': "${ _('Params') }",
  452. 'name': "${ _('Type') }",
  453. 'value': "${ _('Value') }",
  454. 'delete': {
  455. 'name': "${ _('Delete') }",
  456. 'func': 'function(data, event) { $parent.removeParam.call($parent, data, event) }'
  457. },
  458. 'add': [{
  459. 'name': "${ _('Add param') }",
  460. 'func': 'addParam'
  461. },{
  462. 'name': "${ _('Add argument') }",
  463. 'func': 'addArgument'
  464. }],
  465. 'ko': {
  466. 'items': "params",
  467. 'error_class': "params_error_class",
  468. 'condition': "params_condition"
  469. }
  470. },
  471. },
  472. 'sqoop': {
  473. 'title': "${ _('Job Design (sqoop type)') }",
  474. 'script_path': {
  475. 'name': "${ _('Command') }",
  476. 'popover': "${ _('Command to execute.') }"
  477. },
  478. 'params': {
  479. 'title': "${ _('Params') }",
  480. 'name': "${ _('Type') }",
  481. 'value': "${ _('Value') }",
  482. 'delete': {
  483. 'name': "${ _('Delete') }",
  484. 'func': 'function(data, event) { $parent.removeParam.call($parent, data, event) }'
  485. },
  486. 'add': [{
  487. 'name': "${ _('Add arg') }",
  488. 'func': 'addArg'
  489. }],
  490. 'ko': {
  491. 'items': "params",
  492. 'error_class': "params_error_class",
  493. 'condition': "params_condition"
  494. }
  495. }
  496. },
  497. 'fs': {
  498. 'title': "${ _('Job Design (fs type)') }",
  499. 'deletes': {
  500. 'title': "${ _('Delete path') }",
  501. 'delete': {
  502. 'name': "${ _('Delete') }",
  503. 'func': 'function(data, event) { $parent.removeDelete.call($parent, data, event) }'
  504. },
  505. 'add': {
  506. 'name': "${ _('Add path') }",
  507. 'func': 'addDelete'
  508. },
  509. 'ko': {
  510. 'items': "deletes",
  511. 'error_class': "deletes_error_class",
  512. 'condition': "deletes_condition"
  513. }
  514. },
  515. 'mkdirs': {
  516. 'title': "${ _('Create directory') }",
  517. 'delete': {
  518. 'name': "${ _('Delete') }",
  519. 'func': 'function(data, event) { $parent.removeMkdir.call($parent, data, event) }'
  520. },
  521. 'add': {
  522. 'name': "${ _('Add path') }",
  523. 'func': 'addMkdir'
  524. },
  525. 'ko': {
  526. 'items': "mkdirs",
  527. 'error_class': "mkdirs_error_class",
  528. 'condition': "mkdirs_condition"
  529. }
  530. },
  531. 'touchzs': {
  532. 'title': "${ _('Create or touch file') }",
  533. 'delete': {
  534. 'name': "${ _('Delete') }",
  535. 'func': 'function(data, event) { $parent.removeTouchz.call($parent, data, event) }'
  536. },
  537. 'add': {
  538. 'name': "${ _('Add path') }",
  539. 'func': 'addTouchz'
  540. },
  541. 'ko': {
  542. 'items': "touchzs",
  543. 'error_class': "touchzs_error_class",
  544. 'condition': "touchzs_condition"
  545. }
  546. },
  547. 'chmods': {
  548. 'title': "${ _('Change permissions') }",
  549. 'delete': {
  550. 'name': "${ _('Delete') }",
  551. 'func': 'function(data, event) { $parent.removeChmod.call($parent, data, event) }'
  552. },
  553. 'add': {
  554. 'name': "${ _('Add chmod') }",
  555. 'func': 'addChmod'
  556. },
  557. 'ko': {
  558. 'items': "chmods",
  559. 'error_class': "chmods_error_class",
  560. 'condition': "chmods_condition"
  561. }
  562. },
  563. 'moves': {
  564. 'title': "${ _('Move file') }",
  565. 'delete': {
  566. 'name': "${ _('Delete') }",
  567. 'func': 'function(data, event) { $parent.removeMove.call($parent, data, event) }'
  568. },
  569. 'add': {
  570. 'name': "${ _('Add move') }",
  571. 'func': 'addMove'
  572. },
  573. 'ko': {
  574. 'items': "moves",
  575. 'error_class': "moves_error_class",
  576. 'condition': "moves_condition"
  577. }
  578. }
  579. },
  580. 'ssh': {
  581. 'title': "${ _('Job Design (ssh type)') }",
  582. 'params': {
  583. 'title': "${ _('Params') }",
  584. 'name': "${ _('Type') }",
  585. 'value': "${ _('Value') }",
  586. 'delete': {
  587. 'name': "${ _('Delete') }",
  588. 'func': 'function(data, event) { $parent.removeParam.call($parent, data, event) }'
  589. },
  590. 'add': [{
  591. 'name': "${ _('Add arg') }",
  592. 'func': 'addArg'
  593. }],
  594. 'ko': {
  595. 'items': "params",
  596. 'error_class': "params_error_class",
  597. 'condition': "params_condition"
  598. }
  599. },
  600. },
  601. 'shell': {
  602. 'title': "${ _('Job Design (shell type)') }",
  603. 'params': {
  604. 'title': "${ _('Params') }",
  605. 'name': "${ _('Type') }",
  606. 'value': "${ _('Value') }",
  607. 'delete': {
  608. 'name': "${ _('Delete') }",
  609. 'func': 'function(data, event) { $parent.removeParam.call($parent, data, event) }'
  610. },
  611. 'add': [{
  612. 'name': "${ _('Add argument') }",
  613. 'func': 'addArgument'
  614. },{
  615. 'name': "${ _('Add env-var') }",
  616. 'func': 'addEnvVar'
  617. }],
  618. 'ko': {
  619. 'items': "params",
  620. 'error_class': "params_error_class",
  621. 'condition': "params_condition"
  622. }
  623. },
  624. },
  625. 'email': {
  626. 'title': "${ _('Job Design (email type)') }"
  627. },
  628. 'distcp': {
  629. 'title': "${ _('Job Design (distcp type)') }",
  630. 'params': {
  631. 'title': "${ _('Params') }",
  632. 'name': "${ _('Type') }",
  633. 'value': "${ _('Value') }",
  634. 'delete': {
  635. 'name': "${ _('Delete') }",
  636. 'func': 'function(data, event) { $parent.removeParam.call($parent, data, event) }'
  637. },
  638. 'add': [{
  639. 'name': "${ _('Add argument') }",
  640. 'func': 'addArgument'
  641. }],
  642. 'ko': {
  643. 'items': "params",
  644. 'error_class': "params_error_class",
  645. 'condition': "params_condition"
  646. }
  647. },
  648. }
  649. }
  650. //// Binding
  651. var designs = new Designs();
  652. ko.applyBindings(designs);
  653. // Design table and other variables.
  654. var designTableOptions = {
  655. "sPaginationType": "bootstrap",
  656. "bLengthChange": false,
  657. "sDom": "<'row'r>t<'row'<'span8'i><''p>>",
  658. "bDestroy": true,
  659. "aoColumnDefs": [
  660. { "bSortable": false, "aTargets": [ 0 ] },
  661. { "sSortDataType": "dom-sort-value", "sType": "numeric", "aTargets": [6] },
  662. { "bVisible": false, "aTargets": [7] }
  663. ],
  664. "aaSorting": [[ 6, "desc" ]],
  665. "fnPreDrawCallback": function( oSettings ) {
  666. if (designs.allSelected()) {
  667. designs.selectAll();
  668. }
  669. },
  670. "oLanguage": {
  671. "sEmptyTable": "${_('No data available')}",
  672. "sInfo": "${_('Showing _START_ to _END_ of _TOTAL_ entries')}",
  673. "sInfoEmpty": "${_('Showing 0 to 0 of 0 entries')}",
  674. "sInfoFiltered": "${_('(filtered from _MAX_ total entries)')}",
  675. "sZeroRecords": "${_('No matching records')}",
  676. "oPaginate": {
  677. "sFirst": "${_('First')}",
  678. "sLast": "${_('Last')}",
  679. "sNext": "${_('Next')}",
  680. "sPrevious": "${_('Previous')}"
  681. }
  682. }
  683. };
  684. var designTable = $('#designTable').dataTable( designTableOptions );
  685. /**
  686. * Redraw a table after the table has been dynamically updated.
  687. * This is necessary because KO and datatables don't play well together.
  688. */
  689. function redraw() {
  690. designTable.fnDestroy();
  691. designTable = $('#designTable').dataTable( designTableOptions );
  692. designTable.fnFilter(designs.inTrash().toString(), 7);
  693. }
  694. /**
  695. * Reload with datatables.
  696. * Remove datatables, reload, then reinitialize datatables.
  697. * Knockout doesn't work without this.
  698. */
  699. function reload() {
  700. $(document).one('load.designs', function() {
  701. designTable.fnDestroy();
  702. });
  703. designs.load();
  704. $(document).one('initialized.designs', function() {
  705. designTable = $('#designTable').dataTable( designTableOptions );
  706. designTable.fnFilter(designs.inTrash().toString(), 7);
  707. });
  708. }
  709. $(document).bind('loaded.designs', function() {
  710. // Filter should be added again after datatable has been recreated.
  711. $("#filterInput").keyup(function() {
  712. if (designTable != null){
  713. designTable.fnFilter($(this).val());
  714. }
  715. });
  716. });
  717. $(document).bind('saved.design', reload);
  718. $(document).bind('deleted.design', reload);
  719. $(document).bind('cloned.design', reload);
  720. $(document).bind('restored.design', reload);
  721. reload();
  722. /**
  723. * Using Mustache templating system: http://mustache.github.com/
  724. * Templates and partials are loaded in jobsub.templates.js
  725. * Context is matched up with templates and partials.
  726. * Routie is used to provide hash routing: http://projects.jga.me/routie/.
  727. */
  728. var setupRoutes = (function() {
  729. var eventCount = 0;
  730. return function(e) {
  731. if (++eventCount > 1) {
  732. //// Routes
  733. routie({
  734. 'new-design/:node_type': function(node_type) {
  735. /**
  736. * Update context with correct title.
  737. * Create empty design to fill.
  738. * Create template by calling `getActionTemplate`.
  739. */
  740. // Show section only after we've finished the new design process.
  741. $(document).one('created.design', function() {
  742. showSection('design');
  743. });
  744. designs.closeDesign();
  745. var context = $.extend(true, {}, global_action_context, contexts[node_type]);
  746. templates.getActionTemplate(node_type, context);
  747. designs.newDesign(node_type);
  748. },
  749. 'edit-design/:index': function(index) {
  750. /**
  751. * Update context with correct title.
  752. * Design is selected through 'list-designs'.
  753. */
  754. designs.closeDesign();
  755. var designObject = designs.designs()[index];
  756. if (!designObject) {
  757. routie('list-designs');
  758. return;
  759. }
  760. // Show section only after we've finished the edit design process.
  761. $(document).one('edited.design', function() {
  762. if (designObject.design().editable()) {
  763. $('#design input').removeAttr('disabled');
  764. $('#design textarea').removeAttr('disabled');
  765. $('#design button').removeAttr('disabled');
  766. } else {
  767. $('#design input').attr('disabled', 'disabled');
  768. $('#design textarea').attr('disabled', 'disabled');
  769. $('#design button').attr('disabled', 'disabled');
  770. }
  771. showSection('design');
  772. });
  773. var node_type = designObject.design().node_type();
  774. var context = $.extend(true, {}, global_action_context, contexts[node_type]);
  775. templates.getActionTemplate(node_type, context);
  776. designs.deselectAll();
  777. designs.select(index);
  778. designs.editDesign();
  779. },
  780. 'trashed-designs': function() {
  781. $('#home').removeAttr('disabled');
  782. designs.inTrash(true);
  783. showSection('list-designs');
  784. redraw();
  785. },
  786. 'list-designs': function() {
  787. $('#home').removeAttr('disabled');
  788. designs.inTrash(false);
  789. showSection('list-designs');
  790. redraw();
  791. }
  792. });
  793. }
  794. routie('list-designs');
  795. }
  796. })();
  797. $(document).ready(setupRoutes);
  798. $(document).one('loaded.designs', setupRoutes);
  799. $(document).ready(function(e) {
  800. //// Row selector, buttons, and various features.
  801. $(".btn[rel='tooltip']").tooltip({'placement':'bottom'});
  802. $("a[data-row-selector='true']").jHueRowSelector();
  803. $('#submit-design').click(function() {
  804. var url = '/oozie/submit_workflow/' + designs.selectedDesign().id();
  805. $.get(url, function (response) {
  806. $('#submitWf').html(response);
  807. $('#submitWf').modal('show');
  808. }
  809. );
  810. });
  811. $('body').on('click', '#edit-design', function() {
  812. routie('edit-design/' + designs.selectedIndex());
  813. });
  814. $('body').on('click', '#trash-designs', function() {
  815. $('#trashWf').modal('show');
  816. });
  817. $('body').on('click', '#destroy-designs', function() {
  818. $('#destroyWf').modal('show');
  819. });
  820. $('body').on('click', '#purge-trashed-designs', function() {
  821. $('#purgeWf').modal('show');
  822. });
  823. $('body').on('click', '#restore-designs', function() {
  824. $('#restoreWf').modal('show');
  825. });
  826. $('body').on('click', '#copy-designs', function() {
  827. designs.cloneDesigns();
  828. });
  829. $('#home').click(function() {
  830. routie('list-designs');
  831. });
  832. // load the autocomplete properties
  833. var AUTOCOMPLETE_PROPERTIES;
  834. $.getJSON("${ url('oozie:autocomplete_properties') }", function (properties) {
  835. AUTOCOMPLETE_PROPERTIES = properties;
  836. });
  837. });
  838. </script>
  839. ${ commonfooter(messages) | n,unicode }