workflow.mako 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. ## Licensed to Cloudera, Inc. under one
  2. ## or more contributor license agreements. See the NOTICE file
  3. ## distributed with this work for additional information
  4. ## regarding copyright ownership. Cloudera, Inc. licenses this file
  5. ## to you under the Apache License, Version 2.0 (the
  6. ## "License"); you may not use this file except in compliance
  7. ## with the License. You may obtain a copy of the License at
  8. ##
  9. ## http://www.apache.org/licenses/LICENSE-2.0
  10. ##
  11. ## Unless required by applicable law or agreed to in writing, software
  12. ## distributed under the License is distributed on an "AS IS" BASIS,
  13. ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ## See the License for the specific language governing permissions and
  15. ## limitations under the License.
  16. <%!
  17. import time
  18. from desktop.views import commonheader, commonfooter
  19. from hadoop.fs.hadoopfs import Hdfs
  20. from django.utils.translation import ugettext as _
  21. %>
  22. <%namespace name="layout" file="layout.mako" />
  23. ${ commonheader(_("Job Designer"), "jobsub", user, "100px") | n,unicode }
  24. ${layout.menubar(section='history')}
  25. <%def name="format_time(st_time)">
  26. % if st_time is None:
  27. -
  28. % else:
  29. ${time.strftime("%a, %d %b %Y %H:%M:%S", st_time)}
  30. % endif
  31. </%def>
  32. <%def name="hdfs_link(url)">
  33. <% path = Hdfs.urlsplit(url)[2] %>
  34. % if path:
  35. <a href="/filebrowser/view${path}" target="FileBrowser">${url}</a>
  36. % else:
  37. ${url}
  38. % endif
  39. </%def>
  40. <%def name="configModal(elementId, title, configs)">
  41. <div id="${elementId}" class="modal hide fade">
  42. <div class="modal-header">
  43. <a href="#" class="close" data-dismiss="modal">&times;</a>
  44. <h3>${title}</h3>
  45. </div>
  46. <div class="modal-body">
  47. <table class="table table-condensed table-striped">
  48. <thead>
  49. <tr>
  50. <th>${_('Name')}</th>
  51. <th>${_('Value')}</th>
  52. </tr>
  53. </thead>
  54. <tbody>
  55. % for name, value in sorted(configs.items()):
  56. <tr>
  57. <td>${name}</td>
  58. <td>
  59. ## Try to detect paths
  60. %if name.endswith('dir') or name.endswith('path'):
  61. ${hdfs_link(value)}
  62. %else:
  63. ${value}
  64. %endif
  65. </td>
  66. </tr>
  67. % endfor
  68. </tbody>
  69. </table>
  70. </div>
  71. </div>
  72. </%def>
  73. <div class="container-fluid">
  74. %if design_link is not None:
  75. <h1><a title="${_('Edit design')}" href="${design_link}">${workflow.appName}</a> (${workflow.id})</h1>
  76. %else:
  77. <h1>${workflow.appName} (${workflow.id})</h1>
  78. %endif
  79. ## Tab headers
  80. <ul class="nav nav-tabs">
  81. <li class="active"><a href="#actions" data-toggle="tab">${_('Actions')}</a></li>
  82. <li><a href="#details" data-toggle="tab">${_('Details')}</a></li>
  83. <li><a href="#definition" data-toggle="tab">${_('Definition')}</a></li>
  84. <li><a href="#log" data-toggle="tab">${_('Log')}</a></li>
  85. </ul>
  86. <div id="workflow-tab-content" class="tab-content">
  87. ## Tab: Actions
  88. <div class="tab-pane active" id="actions">
  89. <table data-filters="HtmlTable" class="table table-striped table-condensed selectable sortable" cellpadding="0" cellspacing="0">
  90. <thead>
  91. <tr>
  92. <th>${_('Name')}</th>
  93. <th>${_('Type')}</th>
  94. <th>${_('Status')}</th>
  95. <th>${_('External Id')}</th>
  96. <th>${_('Start Time')}</th>
  97. <th>${_('End Time')}</th>
  98. <th>${_('Retries')}</th>
  99. <th>${_('Error Message')}</th>
  100. <th>${_('Transition')}</th>
  101. <th>${_('Data')}</th>
  102. </tr>
  103. </thead>
  104. <tbody>
  105. % for i, action in enumerate(workflow.actions):
  106. <tr>
  107. <td>
  108. ## Include a modal for action configuration
  109. ${action.name}
  110. <% modal_id = "actionConfigModal" + str(i) %>
  111. <a href="#${modal_id}" data-toggle="modal"><img src="/static/art/led-icons/cog.png"
  112. alt="Show Configuration"></a>
  113. ${configModal(modal_id, "Action Configuration", action.conf_dict)}
  114. </td>
  115. <td>${action.type}</td>
  116. <td>${action.status}</td>
  117. <td>
  118. % if action.externalId:
  119. <a href="${ url('jobbrowser.views.single_job', job=action.externalId) }">${ "_".join(action.externalId.split("_")[-2:]) }</a>
  120. % endif
  121. </td>
  122. <td>${format_time(action.startTime)}</td>
  123. <td>${format_time(action.endTime)}</td>
  124. <td>${action.retries}</td>
  125. <td>${action.errorMessage}</td>
  126. <td>${action.transition}</td>
  127. <td>${action.data}</td>
  128. </tr>
  129. % endfor
  130. <tbody>
  131. </table>
  132. </div>
  133. ## Tab: Job details
  134. <div class="tab-pane" id="details">
  135. <table data-filters="HtmlTable" class="table table-striped table-condensed selectable sortable" cellpadding="0" cellspacing="0">
  136. <tbody>
  137. <tr>
  138. ## App name + configuration
  139. <td>${_('Application Name')}</td>
  140. <td>
  141. ${workflow.appName}
  142. <a href="#appConfigModal" data-toggle="modal"><img src="/static/art/led-icons/cog.png"
  143. alt="Show Configuration"/></a>
  144. </td>
  145. </tr>
  146. <tr>
  147. <td>${_('User')}</td>
  148. <td>${workflow.user}</td>
  149. </tr>
  150. <tr>
  151. <td>${_('Group')}</td>
  152. <td>${workflow.group}</td>
  153. </tr>
  154. <tr>
  155. <td>${_('Status')}</td>
  156. <td>${workflow.status}</td>
  157. </tr>
  158. <tr>
  159. <td>${_('External Id')}</td>
  160. <td>${workflow.externalId or "-"}</td>
  161. </tr>
  162. <tr>
  163. <td>${_('Start Time')}</td>
  164. <td>${format_time(workflow.startTime)}</td>
  165. </tr>
  166. <tr>
  167. <td>${_('Created Time')}</td>
  168. <td>${format_time(workflow.createdTime)}</td>
  169. </tr>
  170. <tr>
  171. <td>${_('End Time')}</td>
  172. <td>${format_time(workflow.endTime)}</td>
  173. </tr>
  174. <tr>
  175. <td>${_('Application Path')}</td>
  176. <td>${hdfs_link(workflow.appPath)}
  177. </td>
  178. </tr>
  179. </tbody>
  180. </table>
  181. </div>
  182. ## Tab: Definition
  183. <div class="tab-pane" id="definition">
  184. <textarea id="definitionEditor">${ definition }</textarea>
  185. </div>
  186. ## Tab: Log
  187. <div class="tab-pane" id="log">
  188. <pre>${log}</pre>
  189. </div>
  190. </ul>
  191. </div>
  192. </div>
  193. ${configModal("appConfigModal", "Application Configuration", workflow.conf_dict)}
  194. <script src="/static/ext/js/codemirror-3.0.js"></script>
  195. <link rel="stylesheet" href="/static/ext/css/codemirror.css">
  196. <script src="/static/ext/js/codemirror-xml.js"></script>
  197. <script type="text/javascript">
  198. $(document).ready(function() {
  199. var definitionEditor = $("#definitionEditor")[0];
  200. var codeMirror = CodeMirror(function (elt) {
  201. definitionEditor.parentNode.replaceChild(elt, definitionEditor);
  202. }, {
  203. value:definitionEditor.value,
  204. readOnly:true,
  205. lineNumbers:true
  206. });
  207. // force refresh on tab change
  208. $("a[data-toggle='tab']").on("shown", function (e) {
  209. if ($(e.target).attr("href") == "#definition") {
  210. codeMirror.refresh();
  211. }
  212. });
  213. });
  214. </script>
  215. ${ commonfooter(messages) | n,unicode }