job_browser.mako 132 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013
  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. from django.utils.translation import ugettext as _
  18. from desktop import conf
  19. from desktop.models import ANALYTIC_DB
  20. from desktop.views import commonheader, commonfooter, _ko
  21. from jobbrowser.conf import DISABLE_KILLING_JOBS, MAX_JOB_FETCH, ENABLE_QUERY_BROWSER
  22. %>
  23. <%
  24. SUFFIX = is_mini and "-mini" or ""
  25. %>
  26. % if not is_embeddable:
  27. ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
  28. <%namespace name="assist" file="/assist.mako" />
  29. % endif
  30. <span class="notebook">
  31. <link rel="stylesheet" href="${ static('desktop/ext/css/basictable.css') }">
  32. % if not is_embeddable:
  33. <link rel="stylesheet" href="${ static('notebook/css/notebook.css') }">
  34. <link rel="stylesheet" href="${ static('notebook/css/notebook-layout.css') }">
  35. <style type="text/css">
  36. % if conf.CUSTOM.BANNER_TOP_HTML.get():
  37. .show-assist {
  38. top: 110px!important;
  39. }
  40. .main-content {
  41. top: 112px!important;
  42. }
  43. % endif
  44. </style>
  45. % endif
  46. <link rel="stylesheet" href="${ static('jobbrowser/css/jobbrowser-embeddable.css') }">
  47. <script src="${ static('oozie/js/dashboard-utils.js') }" type="text/javascript" charset="utf-8"></script>
  48. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.basictable.min.js') }"></script>
  49. <script src="${ static('desktop/ext/js/jquery/plugins/jquery-ui-1.10.4.custom.min.js') }"></script>
  50. <script src="${ static('desktop/ext/js/knockout-sortable.min.js') }"></script>
  51. <script src="${ static('desktop/js/ko.editable.js') }"></script>
  52. % if ENABLE_QUERY_BROWSER.get():
  53. <script src="${ static('desktop/ext/js/d3.v3.js') }"></script>
  54. <script src="${ static('desktop/ext/js/dagre-d3-min.js') }"></script>
  55. <script src="${ static('jobbrowser/js/impala_dagre.js') }"></script>
  56. % endif
  57. % if not is_mini:
  58. <div id="jobbrowserComponents" class="jobbrowser-components jobbrowser-full jb-panel">
  59. % else:
  60. <div id="jobbrowserMiniComponents" class="jobbrowser-components jobbrowser-mini jb-panel">
  61. % endif
  62. % if not is_embeddable:
  63. ${ assist.assistJSModels() }
  64. ${ assist.assistPanel() }
  65. <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
  66. <i class="fa fa-chevron-right"></i>
  67. </a>
  68. % endif
  69. % if not is_mini:
  70. <div class="navbar hue-title-bar">
  71. <div class="navbar-inner">
  72. <div class="container-fluid">
  73. <div class="nav-collapse">
  74. <ul class="nav">
  75. <li class="app-header">
  76. <a href="/${app_name}">
  77. <img src="${ static('jobbrowser/art/icon_jobbrowser_48.png') }" class="app-icon" alt="${ _('Job browser icon') }"/>
  78. ${ _('Job Browser') }
  79. </a>
  80. </li>
  81. <!-- ko foreach: availableInterfaces -->
  82. <li data-bind="css: {'active': $parent.interface() === interface}, visible: condition()">
  83. <a class="pointer" data-bind="click: function(){ $parent.selectInterface(interface); }, text: label"></a>
  84. </li>
  85. <!-- /ko -->
  86. </ul>
  87. <span class="pull-right">
  88. <!-- ko if: availableComputes().length > 1 -->
  89. <div data-bind="component: { name: 'hue-drop-down', params: { value: compute, entries: availableComputes, labelAttribute: 'name', searchable: true, linkTitle: '${ _ko('Active clusters') }' } }"></div>
  90. <!-- /ko -->
  91. </span>
  92. % if not hiveserver2_impersonation_enabled:
  93. <div class="pull-right label label-warning" style="margin-top: 16px">${ _("Hive jobs are running as the 'hive' user") }</div>
  94. % endif
  95. </div>
  96. </div>
  97. </div>
  98. </div>
  99. % endif
  100. <script type="text/html" id="apps-list${ SUFFIX }">
  101. <table data-bind="attr: {id: tableId}" class="datatables table table-condensed status-border-container">
  102. <thead>
  103. <tr>
  104. <th width="1%" class="vertical-align-middle">
  105. <div class="select-all hue-checkbox fa" data-bind="hueCheckAll: { allValues: apps, selectedValues: selectedJobs }"></div>
  106. </th>
  107. <th width="20%">${_('Name')}</th>
  108. <th width="6%">${_('User')}</th>
  109. <th width="6%">${_('Type')}</th>
  110. <th width="5%">${_('Status')}</th>
  111. <th width="3%">${_('Progress')}</th>
  112. <th width="5%">${_('Group')}</th>
  113. <th width="10%" data-bind="text: $root.interface() != 'schedules' ? '${_('Started')}' : '${_('Modified')}'"></th>
  114. <th width="6%">${_('Duration')}</th>
  115. <th width="15%">${_('Id')}</th>
  116. </tr>
  117. </thead>
  118. <tbody data-bind="foreach: apps">
  119. <tr class="status-border pointer" data-bind="css: {'completed': apiStatus() == 'SUCCEEDED', 'info': apiStatus() == 'PAUSED', 'running': apiStatus() == 'RUNNING', 'failed': apiStatus() == 'FAILED'}, click: fetchJob">
  120. <td data-bind="click: function() {}, clickBubble: false">
  121. <div class="hue-checkbox fa" data-bind="click: function() {}, clickBubble: false, multiCheck: '#' + $parent.tableId, value: $data, hueChecked: $parent.selectedJobs"></div>
  122. </td>
  123. <td data-bind="text: name"></td>
  124. <td data-bind="text: user"></td>
  125. <td data-bind="text: type"></td>
  126. <td data-bind="text: status"></td>
  127. <td data-bind="text: $root.formatProgress(progress)"></td>
  128. <td data-bind="text: queue"></td>
  129. <td data-bind="moment: {data: submitted, format: 'LLL'}"></td>
  130. <td data-bind="text: duration().toHHMMSS()"></td>
  131. <td data-bind="text: id"></td>
  132. </tr>
  133. </tbody>
  134. </table>
  135. </script>
  136. <div class="main-content">
  137. <div class="vertical-full container-fluid" data-bind="style: { 'padding-left' : $root.isLeftPanelVisible() ? '0' : '20px' }">
  138. <div class="vertical-full">
  139. <div class="vertical-full row-fluid panel-container">
  140. % if not is_embeddable:
  141. <div class="assist-container left-panel" data-bind="visible: $root.isLeftPanelVisible() && $root.assistAvailable()">
  142. <a title="${_('Toggle Assist')}" class="pointer hide-assist" data-bind="click: function() { $root.isLeftPanelVisible(false) }">
  143. <i class="fa fa-chevron-left"></i>
  144. </a>
  145. <div class="assist" data-bind="component: {
  146. name: 'assist-panel',
  147. params: {
  148. user: '${user.username}',
  149. sql: {
  150. navigationSettings: {
  151. openItem: false,
  152. showStats: true
  153. }
  154. },
  155. visibleAssistPanels: ['sql']
  156. }
  157. }"></div>
  158. </div>
  159. <div class="resizer" data-bind="visible: $root.isLeftPanelVisible() && $root.assistAvailable(), splitDraggable : { appName: 'notebook', leftPanelVisible: $root.isLeftPanelVisible }"><div class="resize-bar">&nbsp;</div></div>
  160. % endif
  161. <div class="content-panel">
  162. <div class="content-panel-inner">
  163. <!-- ko if: $root.job() -->
  164. <div data-bind="template: { name: 'breadcrumbs${ SUFFIX }' }"></div>
  165. <!-- /ko -->
  166. <!-- ko if: interface() !== 'slas' && interface() !== 'oozie-info' -->
  167. <!-- ko if: !$root.job() -->
  168. <form class="form-inline">
  169. <!-- ko if: !$root.isMini() && interface() == 'queries' -->
  170. ${ _('Impala queries from') }
  171. <!-- /ko -->
  172. <input type="text" class="input-large" data-bind="clearable: jobs.textFilter, valueUpdate: 'afterkeydown'" placeholder="${_('Filter by id, name, user...')}" />
  173. <!-- ko if: jobs.statesValuesFilter -->
  174. <span data-bind="foreach: jobs.statesValuesFilter">
  175. <label class="checkbox">
  176. <div class="pull-left margin-left-5 status-border status-content" data-bind="css: value, hueCheckbox: checked"></div>
  177. <div class="inline-block" data-bind="text: name, toggle: checked"></div>
  178. </label>
  179. </span>
  180. <!-- /ko -->
  181. <!-- ko ifnot: $root.isMini -->
  182. <!-- ko if: $root.interface() !== 'schedules' && $root.interface() !== 'bundles' -->
  183. ${_('in the last')} <input class="input-mini no-margin" type="number" min="1" max="3650" data-bind="value: jobs.timeValueFilter">
  184. <select class="input-small no-margin" data-bind="value: jobs.timeUnitFilter, options: jobs.timeUnitFilterUnits, optionsText: 'name', optionsValue: 'value'">
  185. <option value="days">${_('days')}</option>
  186. <option value="hours">${_('hours')}</option>
  187. <option value="minutes">${_('minutes')}</option>
  188. </select>
  189. <a class="btn" title="${ _('Refresh') }" data-bind="click: jobs.updateJobs">
  190. <i class="fa fa-refresh"></i>
  191. </a>
  192. <a class="btn" title="${ _('Create cluster') }" data-bind="visible: $root.compute() && $root.compute()['type'].indexOf('altus') >= 0, click: jobs.createCluster">
  193. <i class="fa fa-plus"></i>
  194. </a>
  195. <!-- /ko -->
  196. <div data-bind="template: { name: 'job-actions${ SUFFIX }', 'data': jobs }" class="pull-right"></div>
  197. <!-- /ko -->
  198. </form>
  199. <div data-bind="visible: jobs.showJobCountBanner" class="pull-center alert alert-warning">${ _("Showing oldest %s jobs. Use days filter to get the recent ones.") % MAX_JOB_FETCH.get() }</div>
  200. <div class="card card-small">
  201. <!-- ko hueSpinner: { spin: jobs.loadingJobs(), center: true, size: 'xlarge' } --><!-- /ko -->
  202. <!-- ko ifnot: jobs.loadingJobs() -->
  203. <!-- ko if: $root.isMini -->
  204. <ul class="unstyled status-border-container" id="jobsTable" data-bind="foreach: jobs.apps">
  205. <li class="status-border pointer" data-bind="css: {'completed': apiStatus() == 'SUCCEEDED', 'info': apiStatus() === 'PAUSED', 'running': apiStatus() === 'RUNNING', 'failed': apiStatus() == 'FAILED'}, click: fetchJob">
  206. <span class="muted pull-left" data-bind="momentFromNow: {data: submitted, interval: 10000, titleFormat: 'LLL'}"></span><span class="muted">&nbsp;-&nbsp;</span><span class="muted" data-bind="text: status"></span></td>
  207. <span class="muted pull-right" data-bind="text: duration().toHHMMSS()"></span>
  208. <div class="clearfix"></div>
  209. <strong class="pull-left" data-bind="text: type"></strong>
  210. <div class="inline-block pull-right"><i class="fa fa-user muted"></i> <span data-bind="text: user"></span></div>
  211. <div class="clearfix"></div>
  212. <div class="pull-left" data-bind="ellipsis: {data: name(), length: 40 }"></div>
  213. <div class="pull-right muted" data-bind="text: id"></div>
  214. <div class="clearfix"></div>
  215. </li>
  216. <div class="status-bar status-background" data-bind="css: {'running': isRunning()}, style: {'width': progress() + '%'}"></div>
  217. </ul>
  218. <!-- /ko -->
  219. <!-- ko ifnot: $root.isMini -->
  220. ${ _('Running') }
  221. <div data-bind="template: { name: 'apps-list${ SUFFIX }', data: {apps: jobs.runningApps, tableId: 'runningJobsTable', selectedJobs: jobs.selectedJobs} }"></div>
  222. ${ _('Completed') }
  223. <div data-bind="template: { name: 'apps-list${ SUFFIX }', data: {apps: jobs.finishedApps, tableId: 'completedJobsTable', selectedJobs: jobs.selectedJobs} }"></div>
  224. <!-- /ko -->
  225. <!-- /ko -->
  226. </div>
  227. <!-- /ko -->
  228. <!-- ko if: $root.job() -->
  229. <!-- ko with: $root.job() -->
  230. <!-- ko if: mainType() == 'jobs' -->
  231. <div class="jb-panel" data-bind="template: { name: 'job-page${ SUFFIX }' }"></div>
  232. <!-- /ko -->
  233. <!-- ko if: mainType() == 'queries' -->
  234. <div class="jb-panel" data-bind="template: { name: 'queries-page${ SUFFIX }' }"></div>
  235. <!-- /ko -->
  236. <!-- ko if: mainType() == 'workflows' -->
  237. <!-- ko if: type() == 'workflow' -->
  238. <div class="jb-panel" data-bind="template: { name: 'workflow-page${ SUFFIX }' }"></div>
  239. <!-- /ko -->
  240. <!-- ko if: type() == 'workflow-action' -->
  241. <div class="jb-panel" data-bind="template: { name: 'workflow-action-page${ SUFFIX }' }"></div>
  242. <!-- /ko -->
  243. <!-- /ko -->
  244. <!-- ko if: mainType() == 'schedules' -->
  245. <div class="jb-panel" data-bind="template: { name: 'schedule-page${ SUFFIX }' }"></div>
  246. <!-- /ko -->
  247. <!-- ko if: mainType() == 'bundles' -->
  248. <div class="jb-panel" data-bind="template: { name: 'bundle-page${ SUFFIX }' }"></div>
  249. <!-- /ko -->
  250. <!-- ko if: mainType().startsWith('dataeng-job') -->
  251. <div data-bind="template: { name: 'dataeng-job-page${ SUFFIX }' }"></div>
  252. <!-- /ko -->
  253. <!-- ko if: mainType() == 'livy-sessions' -->
  254. <div class="jb-panel" data-bind="template: { name: 'livy-session-page${ SUFFIX }' }"></div>
  255. <!-- /ko -->
  256. <!-- /ko -->
  257. <!-- /ko -->
  258. <div data-bind="template: { name: 'pagination${ SUFFIX }', data: $root.jobs }, visible: !$root.job() && !jobs.loadingJobs()"></div>
  259. <!-- /ko -->
  260. % if not is_mini:
  261. <!-- ko if: interface() === 'slas' -->
  262. <!-- ko hueSpinner: { spin: slasLoading(), center: true, size: 'xlarge' } --><!-- /ko -->
  263. <!-- /ko -->
  264. <div id="slas" data-bind="visible: interface() === 'slas'"></div>
  265. <!-- ko if: interface() === 'oozie-info' -->
  266. <!-- ko hueSpinner: { spin: oozieInfoLoading(), center: true, size: 'xlarge' } --><!-- /ko -->
  267. <!-- /ko -->
  268. <div id="oozieInfo" data-bind="visible: interface() === 'oozie-info'"></div>
  269. %endif
  270. </div>
  271. </div>
  272. </div>
  273. </div>
  274. </div>
  275. </div>
  276. <!-- ko if: $root.job() -->
  277. <div id="rerun-modal${ SUFFIX }" class="modal hide" data-bind="htmlUnsecure: $root.job().rerunModalContent"></div>
  278. <!-- /ko -->
  279. <!-- ko if: ($root.job() && $root.job().hasKill()) || (!$root.job() && $root.jobs.hasKill()) -->
  280. <div id="killModal${ SUFFIX }" class="modal hide">
  281. <div class="modal-header">
  282. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  283. <h2 class="modal-title">${_('Confirm Kill')}</h2>
  284. </div>
  285. <div class="modal-body">
  286. <p>${_('Are you sure you want to kill the selected job(s)?')}</p>
  287. </div>
  288. <div class="modal-footer">
  289. <a class="btn" data-dismiss="modal">${_('No')}</a>
  290. <a id="killJobBtn" class="btn btn-danger disable-feedback" data-dismiss="modal" data-bind="click: function(){ if (job()) { job().control('kill'); } else { jobs.control('kill'); } }">${_('Yes')}</a>
  291. </div>
  292. </div>
  293. <!-- /ko -->
  294. </div>
  295. <script type="text/html" id="breadcrumbs-icons${ SUFFIX }">
  296. <!-- ko switch: type -->
  297. <!-- ko case: 'workflow' -->
  298. <img src="${ static('oozie/art/icon_oozie_workflow_48.png') }" class="app-icon" alt="${ _('Oozie workflow icon') }"/>
  299. <!-- /ko -->
  300. <!-- ko case: 'workflow-action' -->
  301. <i class="fa fa-fw fa-code-fork"></i>
  302. <!-- /ko -->
  303. <!-- ko case: 'schedule' -->
  304. <img src="${ static('oozie/art/icon_oozie_coordinator_48.png') }" class="app-icon" alt="${ _('Oozie coordinator icon') }"/>
  305. <!-- /ko -->
  306. <!-- ko case: 'bundle' -->
  307. <img src="${ static('oozie/art/icon_oozie_bundle_48.png') }" class="app-icon" alt="${ _('Oozie bundle icon') }"/>
  308. <!-- /ko -->
  309. <!-- /ko -->
  310. </script>
  311. <script type="text/html" id="breadcrumbs${ SUFFIX }">
  312. <h3 class="jb-breadcrumbs">
  313. <ul class="inline hue-breadcrumbs-bar">
  314. <!-- ko foreach: breadcrumbs -->
  315. <li>
  316. <!-- ko if: $index() > 1 -->
  317. <span class="divider">&gt;</span>
  318. <!-- /ko -->
  319. <!-- ko if: $index() != 0 -->
  320. <!-- ko if: $index() != $parent.breadcrumbs().length - 1 -->
  321. <a href="javascript:void(0)" data-bind="click: function() { $parent.breadcrumbs.splice($index()); $root.job().id(id); $root.job().fetchJob(); }">
  322. <span data-bind="template: 'breadcrumbs-icons${ SUFFIX }'"></span>
  323. <span data-bind="text: name"></span></a>
  324. <!-- /ko -->
  325. <!-- ko if: $index() == $parent.breadcrumbs().length - 1 -->
  326. <span data-bind="template: 'breadcrumbs-icons${ SUFFIX }'"></span>
  327. <span data-bind="text: name, attr: { title: id }"></span>
  328. <!-- /ko -->
  329. <!-- /ko -->
  330. </li>
  331. <!-- /ko -->
  332. <!-- ko if: !$root.isMini() -->
  333. <!-- ko if: ['workflows', 'schedules', 'bundles', 'slas'].indexOf(interface()) > -1 -->
  334. <li class="pull-right">
  335. <a href="javascript:void(0)" data-bind="click: function() { $root.selectInterface('oozie-info') }">${ _('Configuration') }</a>
  336. </li>
  337. <!-- /ko -->
  338. <!-- /ko -->
  339. </ul>
  340. </h3>
  341. </script>
  342. <script type="text/html" id="pagination${ SUFFIX }">
  343. <!-- ko ifnot: hasPagination -->
  344. <div class="inline">
  345. <span data-bind="text: totalApps()"></span>
  346. ${ _('jobs') }
  347. </div>
  348. <!-- /ko -->
  349. <!-- ko if: hasPagination -->
  350. <div class="inline">
  351. <div class="inline">
  352. ${ _('Showing') }
  353. <span data-bind="text: Math.min(paginationOffset(), totalApps())"></span>
  354. ${ _('to')}
  355. <span data-bind="text: Math.min(paginationOffset() - 1 + paginationResultPage(), totalApps())"></span>
  356. ${ _('of') }
  357. <span data-bind="text: totalApps"></span>
  358. ##${ _('Show')}
  359. ##<span data-bind="text: paginationResultPage"></span>
  360. ##${ _('results by page.') }
  361. </div>
  362. <ul class="inline">
  363. <li class="previous-page" data-bind="visible: showPreviousPage">
  364. <a href="javascript:void(0);" data-bind="click: previousPage" title="${_('Previous page')}"><i class="fa fa-backward"></i></a>
  365. </li>
  366. <li class="next-page" data-bind="visible: showNextPage">
  367. <a href="javascript:void(0);" data-bind="click: nextPage" title="${_('Next page')}"><i class="fa fa-forward"></i></a>
  368. </li>
  369. </ul>
  370. </div>
  371. <!-- /ko -->
  372. </script>
  373. <script type="text/html" id="job-page${ SUFFIX }">
  374. <!-- ko if: type() == 'MAPREDUCE' -->
  375. <div data-bind="template: { name: 'job-mapreduce-page${ SUFFIX }', data: $root.job() }"></div>
  376. <!-- /ko -->
  377. <!-- ko if: type() == 'MAP' || type() == 'REDUCE' -->
  378. <div data-bind="template: { name: 'job-mapreduce-task-page${ SUFFIX }', data: $root.job() }"></div>
  379. <!-- /ko -->
  380. <!-- ko if: type() == 'MAP_ATTEMPT' || type() == 'REDUCE_ATTEMPT' -->
  381. <div data-bind="template: { name: 'job-mapreduce-task-attempt-page${ SUFFIX }', data: $root.job() }"></div>
  382. <!-- /ko -->
  383. <!-- ko if: type() == 'YARN' -->
  384. <div data-bind="template: { name: 'job-yarn-page${ SUFFIX }', data: $root.job() }"></div>
  385. <!-- /ko -->
  386. <!-- ko if: type() == 'Oozie Launcher' -->
  387. <div data-bind="template: { name: 'job-oozie-page${ SUFFIX }', data: $root.job() }"></div>
  388. <!-- /ko -->
  389. <!-- ko if: type() == 'Oozie Launcher_ATTEMPT' -->
  390. <div data-bind="template: { name: 'job-oozie-attempt-page${ SUFFIX }', data: $root.job() }"></div>
  391. <!-- /ko -->
  392. <!-- ko if: type() == 'SPARK' -->
  393. <div data-bind="template: { name: 'job-spark-page${ SUFFIX }', data: $root.job() }"></div>
  394. <!-- /ko -->
  395. <!-- ko if: type() == 'SPARK_EXECUTOR' -->
  396. <div data-bind="template: { name: 'job-spark-executor-page${ SUFFIX }', data: $root.job() }"></div>
  397. <!-- /ko -->
  398. </script>
  399. <script type="text/html" id="job-yarn-page${ SUFFIX }">
  400. <div class="row-fluid">
  401. <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
  402. <div class="sidebar-nav">
  403. <ul class="nav nav-list">
  404. <li class="nav-header">${ _('Id') }</li>
  405. <li><span data-bind="text: id"></span></li>
  406. <li class="nav-header">${ _('Name') }</li>
  407. <li><span data-bind="text: name"></span></li>
  408. <li class="nav-header">${ _('Type') }</li>
  409. <li><span data-bind="text: type"></span></li>
  410. <li class="nav-header">${ _('Status') }</li>
  411. <li><span data-bind="text: status"></span></li>
  412. <li class="nav-header">${ _('User') }</li>
  413. <li><span data-bind="text: user"></span></li>
  414. <li class="nav-header">${ _('Progress') }</li>
  415. <li><span data-bind="text: progress"></span>%</li>
  416. <li>
  417. <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': apiStatus() !== 'FAILED' && progress() < 100, 'progress-success': apiStatus() !== 'FAILED' && progress() === 100, 'progress-danger': apiStatus() === 'FAILED'}">
  418. <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
  419. </div>
  420. </li>
  421. <li class="nav-header">${ _('Duration') }</li>
  422. <li><span data-bind="text: duration().toHHMMSS()"></span></li>
  423. <li class="nav-header">${ _('Submitted') }</li>
  424. <li><span data-bind="text: submitted"></span></li>
  425. </ul>
  426. </div>
  427. </div>
  428. <div data-bind="css:{'span10': !$root.isMini(), 'span12 no-margin': $root.isMini() }">
  429. <div class="pull-right" data-bind="template: { name: 'job-actions${ SUFFIX }' }"></div>
  430. </div>
  431. </div>
  432. </script>
  433. <script type="text/html" id="job-mapreduce-page${ SUFFIX }">
  434. <div class="row-fluid">
  435. <div data-bind="css: {'span2': !$root.isMini(), 'span12': $root.isMini()}">
  436. <div class="sidebar-nav">
  437. <ul class="nav nav-list">
  438. <li class="nav-header">${ _('Id') }</li>
  439. <li><span data-bind="text: id"></span></li>
  440. <li data-bind="visible: id() != name() && ! $root.isMini()" class="nav-header">${ _('Name') }</li>
  441. <li data-bind="visible: id() != name() && ! $root.isMini(), attr: {title: name}"><span data-bind="text: name"></span></li>
  442. <li class="nav-header">${ _('Type') }</li>
  443. <li><span data-bind="text: type"></span></li>
  444. <li data-bind="visible: ! $root.isMini()" class="nav-header">${ _('Status') }</li>
  445. <li data-bind="visible: ! $root.isMini()"><span data-bind="text: status"></span></li>
  446. <li class="nav-header">${ _('User') }</li>
  447. <li><span data-bind="text: user"></span></li>
  448. <li class="nav-header">${ _('Progress') }</li>
  449. <li><span data-bind="text: progress"></span>%</li>
  450. <li>
  451. <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': apiStatus() !== 'FAILED' && progress() < 100, 'progress-success': apiStatus() !== 'FAILED' && progress() === 100, 'progress-danger': apiStatus() === 'FAILED'}, attr: {title: status}">
  452. <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
  453. </div>
  454. </li>
  455. <!-- ko if: !$root.isMini() -->
  456. <!-- ko with: properties -->
  457. <li class="nav-header">${ _('Map') }</li>
  458. <li><span data-bind="text: maps_percent_complete"></span>% <span data-bind="text: finishedMaps"></span> /<span data-bind="text: desiredMaps"></span></li>
  459. <li class="nav-header">${ _('Reduce') }</li>
  460. <li><span data-bind="text: reduces_percent_complete"></span>% <span data-bind="text: finishedReduces"></span> / <span data-bind="text: desiredReduces"></span></li>
  461. <li class="nav-header">${ _('Duration') }</li>
  462. <li><span data-bind="text: durationFormatted"></span></li>
  463. <li class="nav-header">${ _('Submitted') }</li>
  464. <li><span data-bind="text: startTimeFormatted"></span></li>
  465. <!-- /ko -->
  466. <!-- /ko -->
  467. </ul>
  468. </div>
  469. </div>
  470. <div data-bind="css:{'span10': !$root.isMini(), 'span12 no-margin': $root.isMini() }">
  471. <ul class="nav nav-pills margin-top-20">
  472. <li class="active"><a class="jb-logs-link" href="#job-mapreduce-page-logs${ SUFFIX }" data-toggle="tab">${ _('Logs') }</a></li>
  473. <li><a href="#job-mapreduce-page-tasks${ SUFFIX }" data-bind="click: function(){ fetchProfile('tasks'); $('a[href=\'#job-mapreduce-page-tasks${ SUFFIX }\']').tab('show'); }">${ _('Tasks') }</a></li>
  474. <li><a href="#job-mapreduce-page-metadata${ SUFFIX }" data-bind="click: function(){ fetchProfile('metadata'); $('a[href=\'#job-mapreduce-page-metadata${ SUFFIX }\']').tab('show'); }">${ _('Metadata') }</a></li>
  475. <li><a href="#job-mapreduce-page-counters${ SUFFIX }" data-bind="click: function(){ fetchProfile('counters'); $('a[href=\'#job-mapreduce-page-counters${ SUFFIX }\']').tab('show'); }">${ _('Counters') }</a></li>
  476. <li class="pull-right" data-bind="template: { name: 'job-actions${ SUFFIX }' }"></li>
  477. </ul>
  478. <div class="clearfix"></div>
  479. <div class="tab-content">
  480. <div class="tab-pane active" id="job-mapreduce-page-logs${ SUFFIX }">
  481. <ul class="nav nav-tabs">
  482. % for name in ['default', 'stdout', 'stderr', 'syslog']:
  483. <li class="${ name == 'default' and 'active' or '' }"><a href="javascript:void(0)" data-bind="click: function(data, e) { $(e.currentTarget).parent().siblings().removeClass('active'); $(e.currentTarget).parent().addClass('active'); fetchLogs('${ name }'); logActive('${ name }'); }, text: '${ name }'"></a></li>
  484. % endfor
  485. </ul>
  486. <!-- ko if: properties.diagnostics() -->
  487. <pre data-bind="text: properties.diagnostics"></pre>
  488. <!-- /ko -->
  489. <pre data-bind="html: logs, logScroller: logs"></pre>
  490. </div>
  491. <div class="tab-pane" id="job-mapreduce-page-tasks${ SUFFIX }">
  492. <form class="form-inline">
  493. <input data-bind="textFilter: textFilter, clearable: {value: textFilter}, valueUpdate: 'afterkeydown'" type="text" class="input-xlarge search-query" placeholder="${_('Filter by name')}">
  494. <span data-bind="foreach: statesValuesFilter">
  495. <label class="checkbox">
  496. <div class="pull-left margin-left-5 status-border status-content" data-bind="css: value, hueCheckbox: checked"></div>
  497. <div class="inline-block" data-bind="text: name, toggle: checked"></div>
  498. </label>
  499. </span>
  500. <span data-bind="foreach: typesValuesFilter" class="margin-left-30">
  501. <label class="checkbox">
  502. <div class="pull-left margin-left-5" data-bind="css: value, hueCheckbox: checked"></div>
  503. <div class="inline-block" data-bind="text: name, toggle: checked"></div>
  504. </label>
  505. </span>
  506. </form>
  507. <table class="table table-condensed">
  508. <thead>
  509. <tr>
  510. <th>${_('Type')}</th>
  511. <th>${_('Id')}</th>
  512. <th>${_('Elapsed Time')}</th>
  513. <th>${_('Progress')}</th>
  514. <th>${_('State')}</th>
  515. <th>${_('Start Time')}</th>
  516. <th>${_('Successful Attempt')}</th>
  517. <th>${_('Finish Time')}</th>
  518. </tr>
  519. </thead>
  520. <tbody data-bind="foreach: properties['tasks']()['task_list']">
  521. <tr data-bind="click: function() { $root.job().id(id); $root.job().fetchJob(); }, css: {'completed': apiStatus == 'SUCCEEDED', 'running': apiStatus == 'RUNNING', 'failed': apiStatus == 'FAILED'}" class="status-border pointer">
  522. <td data-bind="text: type"></td>
  523. <td data-bind="text: id"></td>
  524. <td data-bind="text: elapsedTime.toHHMMSS()"></td>
  525. <td data-bind="text: progress"></td>
  526. <td data-bind="text: state"></td>
  527. <td data-bind="moment: {data: startTime, format: 'LLL'}"></td>
  528. <td data-bind="text: successfulAttempt"></td>
  529. <td data-bind="moment: {data: finishTime, format: 'LLL'}"></td>
  530. </tr>
  531. </tbody>
  532. </table>
  533. </div>
  534. <div class="tab-pane" id="job-mapreduce-page-metadata${ SUFFIX }">
  535. <div data-bind="template: { name: 'render-metadata${ SUFFIX }', data: properties['metadata'] }"></div>
  536. </div>
  537. <div class="tab-pane" id="job-mapreduce-page-counters${ SUFFIX }">
  538. <div data-bind="template: { name: 'render-page-counters${ SUFFIX }', data: properties['counters'] }"></div>
  539. </div>
  540. </div>
  541. </div>
  542. </div>
  543. </script>
  544. <script type="text/html" id="job-mapreduce-task-page${ SUFFIX }">
  545. <div class="row-fluid">
  546. <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
  547. <div class="sidebar-nav">
  548. <ul class="nav nav-list">
  549. <li class="nav-header">${ _('Id') }</li>
  550. <li class="break-word"><span data-bind="text: id"></span></li>
  551. <li class="nav-header">${ _('Type') }</li>
  552. <li><span data-bind="text: type"></span></li>
  553. <li class="nav-header">${ _('Progress') }</li>
  554. <li><span data-bind="text: progress"></span>%</li>
  555. <li>
  556. <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': apiStatus() !== 'FAILED' && progress() < 100, 'progress-success': apiStatus() !== 'FAILED' && progress() === 100, 'progress-danger': apiStatus() === 'FAILED'}, attr: {title: status}">
  557. <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
  558. </div>
  559. </li>
  560. <!-- ko if: !$root.isMini() -->
  561. <!-- ko with: properties -->
  562. <li data-bind="visible: ! $root.isMini()" class="nav-header">${ _('State') }</li>
  563. <li data-bind="visible: ! $root.isMini()"><span data-bind="text: state"></span></li>
  564. <li class="nav-header">${ _('Start time') }</li>
  565. <li><span data-bind="moment: {data: startTime, format: 'LLL'}"></span></li>
  566. <li class="nav-header">${ _('Successful attempt') }</li>
  567. <li><span data-bind="text: successfulAttempt"></span></li>
  568. <li class="nav-header">${ _('Finish time') }</li>
  569. <li><span data-bind="moment: {data: finishTime, format: 'LLL'}"></span></li>
  570. <li class="nav-header">${ _('Elapsed time') }</li>
  571. <li><span data-bind="text: elapsedTime().toHHMMSS()"></span></li>
  572. <!-- /ko -->
  573. <!-- /ko -->
  574. </ul>
  575. </div>
  576. </div>
  577. <div data-bind="css:{'span10': !$root.isMini(), 'span12 no-margin': $root.isMini() }">
  578. <ul class="nav nav-pills margin-top-20">
  579. <li class="active"><a class="jb-logs-link" href="#job-mapreduce-task-page-logs${ SUFFIX }" data-toggle="tab">${ _('Logs') }</a></li>
  580. <li><a href="#job-mapreduce-task-page-attempts${ SUFFIX }" data-bind="click: function(){ fetchProfile('attempts'); $('a[href=\'#job-mapreduce-task-page-attempts${ SUFFIX }\']').tab('show'); }">${ _('Attempts') }</a></li>
  581. <li><a href="#job-mapreduce-task-page-counters${ SUFFIX }" data-bind="click: function(){ fetchProfile('counters'); $('a[href=\'#job-mapreduce-task-page-counters${ SUFFIX }\']').tab('show'); }">${ _('Counters') }</a></li>
  582. </ul>
  583. <div class="tab-content">
  584. <div class="tab-pane active" id="job-mapreduce-task-page-logs${ SUFFIX }">
  585. <ul class="nav nav-tabs">
  586. % for name in ['stdout', 'stderr', 'syslog']:
  587. <li class="${ name == 'stdout' and 'active' or '' }"><a href="javascript:void(0)" data-bind="click: function(data, e) { $(e.currentTarget).parent().siblings().removeClass('active'); $(e.currentTarget).parent().addClass('active'); fetchLogs('${ name }'); logActive('${ name }'); }, text: '${ name }'"></a></li>
  588. % endfor
  589. </ul>
  590. <pre data-bind="html: logs, logScroller: logs"></pre>
  591. </div>
  592. <div class="tab-pane" id="job-mapreduce-task-page-attempts${ SUFFIX }">
  593. <table class="table table-condensed">
  594. <thead>
  595. <tr>
  596. <th>${_('Assigned Container Id')}</th>
  597. <th>${_('Progress')}</th>
  598. <th>${_('Elapsed Time')}</th>
  599. <th>${_('State')}</th>
  600. <th>${_('Rack')}</th>
  601. <th>${_('Node Http Address')}</th>
  602. <th>${_('Type')}</th>
  603. <th>${_('Start Time')}</th>
  604. <th>${_('Id')}</th>
  605. <th>${_('Finish Time')}</th>
  606. </tr>
  607. </thead>
  608. <tbody data-bind="foreach: properties['attempts']()['task_list']">
  609. <tr class="pointer" data-bind="click: function() { $root.job().id(id); $root.job().fetchJob(); }">
  610. <td data-bind="text: assignedContainerId"></td>
  611. <td data-bind="text: progress"></td>
  612. <td data-bind="text: elapsedTime.toHHMMSS()"></td>
  613. <td data-bind="text: state"></td>
  614. <td data-bind="text: rack"></td>
  615. <td data-bind="text: nodeHttpAddress"></td>
  616. <td data-bind="text: type"></td>
  617. <td data-bind="moment: {data: startTime, format: 'LLL'}"></td>
  618. <td data-bind="text: id"></td>
  619. <td data-bind="moment: {data: finishTime, format: 'LLL'}"></td>
  620. </tr>
  621. </tbody>
  622. </table>
  623. </div>
  624. <div class="tab-pane" id="job-mapreduce-task-page-counters${ SUFFIX }">
  625. <div data-bind="template: { name: 'render-task-counters${ SUFFIX }', data: properties['counters'] }"></div>
  626. </div>
  627. </div>
  628. </div>
  629. </div>
  630. </script>
  631. <script type="text/html" id="job-oozie-page${ SUFFIX }">
  632. <div class="row-fluid">
  633. <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
  634. <div class="sidebar-nav">
  635. <ul class="nav nav-list">
  636. <li class="nav-header">${ _('Id') }</li>
  637. <li class="break-word"><span data-bind="text: id"></span></li>
  638. <li class="nav-header">${ _('Type') }</li>
  639. <li><span data-bind="text: type"></span></li>
  640. <li class="nav-header">${ _('Progress') }</li>
  641. <li><span data-bind="text: progress"></span>%</li>
  642. <li>
  643. <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': apiStatus() == 'RUNNING', 'progress-success': apiStatus() == 'SUCCEEDED', 'progress-danger': apiStatus() == 'FAILED'}, attr: {title: status}">
  644. <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
  645. </div>
  646. </li>
  647. <!-- ko if: !$root.isMini() -->
  648. <li class="nav-header">${ _('State') }</li>
  649. <li><span data-bind="text: status"></span></li>
  650. <!-- ko with: properties -->
  651. <li class="nav-header">${ _('Start time') }</li>
  652. <li><span data-bind="moment: {data: startTime, format: 'LLL'}"></span></li>
  653. <li class="nav-header">${ _('Finish time') }</li>
  654. <li><span data-bind="moment: {data: finishTime, format: 'LLL'}"></span></li>
  655. <li class="nav-header">${ _('Elapsed time') }</li>
  656. <li><span data-bind="text: elapsedTime().toHHMMSS()"></span></li>
  657. <!-- /ko -->
  658. <!-- /ko -->
  659. </ul>
  660. </div>
  661. </div>
  662. <div data-bind="css: {'span10': !$root.isMini(), 'span12': $root.isMini() }">
  663. <ul class="nav nav-pills margin-top-20">
  664. <li class="active"><a class="jb-logs-link" href="#job-oozie-page-logs${ SUFFIX }" data-toggle="tab">${ _('Logs') }</a></li>
  665. <li><a href="#job-oozie-page-attempts${ SUFFIX }" data-bind="click: function(){ fetchProfile('attempts'); $('a[href=\'#job-oozie-page-attempts${ SUFFIX }\']').tab('show'); }">${ _('Attempts') }</a></li>
  666. </ul>
  667. <div class="tab-content">
  668. <div class="tab-pane active" id="job-oozie-page-logs${ SUFFIX }">
  669. <ul class="nav nav-tabs">
  670. % for name in ['stdout', 'stderr']:
  671. <li class="${ name == 'stdout' and 'active' or '' }"><a href="javascript:void(0)" data-bind="click: function(data, e) { $(e.currentTarget).parent().siblings().removeClass('active'); $(e.currentTarget).parent().addClass('active'); fetchLogs('${ name }'); logActive('${ name }'); }, text: '${ name }'"></a></li>
  672. % endfor
  673. </ul>
  674. <pre data-bind="html: logs, logScroller: logs"></pre>
  675. </div>
  676. <div class="tab-pane" id="job-oozie-page-attempts${ SUFFIX }">
  677. <table class="table table-condensed">
  678. <thead>
  679. <tr>
  680. <th>${_('Assigned Container Id')}</th>
  681. <th>${_('Node Id')}</th>
  682. <th>${_('appAttemptId')}</th>
  683. <th>${_('Start Time')}</th>
  684. <th>${_('Finish Time')}</th>
  685. <th>${_('Node Http Address')}</th>
  686. <th>${_('Blacklisted Nodes')}</th>
  687. <th>${_('Nodes Blacklisted By System')}</th>
  688. </tr>
  689. </thead>
  690. <tbody data-bind="foreach: properties['attempts']()['task_list']">
  691. <tr class="pointer" data-bind="click: function() { $root.job().id(id); $root.job().fetchJob(); }">
  692. <td data-bind="text: containerId"></td>
  693. <td data-bind="text: nodeId"></td>
  694. <td data-bind="text: appAttemptId"></td>
  695. <td data-bind="moment: {data: startTime, format: 'LLL'}"></td>
  696. <td data-bind="moment: {data: finishedTime, format: 'LLL'}"></td>
  697. <td data-bind="text: nodeHttpAddress"></td>
  698. <td data-bind="text: blacklistedNodes"></td>
  699. <td data-bind="text: nodesBlacklistedBySystem"></td>
  700. </tr>
  701. </tbody>
  702. </table>
  703. </div>
  704. </div>
  705. </div>
  706. </div>
  707. </script>
  708. <script type="text/html" id="job-oozie-attempt-page${ SUFFIX }">
  709. <div class="row-fluid">
  710. <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
  711. <div class="sidebar-nav">
  712. <ul class="nav nav-list">
  713. <li class="nav-header">${ _('Id') }</li>
  714. <li class="break-word"><span data-bind="text: id"></span></li>
  715. <li class="nav-header">${ _('Type') }</li>
  716. <li><span data-bind="text: type"></span></li>
  717. <!-- ko with: properties -->
  718. <li class="nav-header">${ _('State') }</li>
  719. <li><span data-bind="text: state"></span></li>
  720. <!-- ko if: !$root.isMini() -->
  721. <li class="nav-header">${ _('Finish time') }</li>
  722. <li><span data-bind="moment: {data: finishTime, format: 'LLL'}"></span></li>
  723. <li class="nav-header">${ _('Assigned Container ID') }</li>
  724. <li><span data-bind="text: assignedContainerId"></span></li>
  725. <li class="nav-header">${ _('Host') }</li>
  726. <li><span data-bind="text: host"></span></li>
  727. <li class="nav-header">${ _('RPC Port') }</li>
  728. <li><span data-bind="text: rpcPort"></span></li>
  729. <li class="nav-header">${ _('Diagnostics Info') }</li>
  730. <li><span data-bind="text: diagnosticsInfo"></span></li>
  731. <!-- /ko -->
  732. <!-- /ko -->
  733. </ul>
  734. </div>
  735. </div>
  736. <div data-bind="css: {'span10': !$root.isMini(), 'span12': $root.isMini() }">
  737. </div>
  738. </div>
  739. </script>
  740. <script type="text/html" id="job-mapreduce-task-attempt-page${ SUFFIX }">
  741. <div class="row-fluid">
  742. <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
  743. <div class="sidebar-nav">
  744. <ul class="nav nav-list">
  745. <li class="nav-header">${ _('Id') }</li>
  746. <li class="break-word"><span data-bind="text: id"></span></li>
  747. <li class="nav-header">${ _('Type') }</li>
  748. <li><span data-bind="text: type"></span></li>
  749. <li class="nav-header">${ _('Progress') }</li>
  750. <li><span data-bind="text: progress"></span>%</li>
  751. <li>
  752. <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': apiStatus() == 'RUNNING', 'progress-success': apiStatus() == 'SUCCEEDED', 'progress-danger': apiStatus() == 'FAILED'}, attr: {title: status}">
  753. <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
  754. </div>
  755. </li>
  756. <!-- ko if: !$root.isMini() -->
  757. <!-- ko with: properties -->
  758. <li class="nav-header">${ _('State') }</li>
  759. <li><span data-bind="text: state"></span></li>
  760. <li class="nav-header">${ _('Assigned Container ID') }</li>
  761. <li><span data-bind="text: assignedContainerId"></span></li>
  762. <li class="nav-header">${ _('Rack') }</li>
  763. <li><span data-bind="text: rack"></span></li>
  764. <li class="nav-header">${ _('Node HTTP address') }</li>
  765. <li><span data-bind="text: nodeHttpAddress"></span></li>
  766. <li class="nav-header">${ _('Start time') }</li>
  767. <li><span data-bind="moment: {data: startTime, format: 'LLL'}"></span></li>
  768. <li class="nav-header">${ _('Finish time') }</li>
  769. <li><span data-bind="moment: {data: finishTime, format: 'LLL'}"></span></li>
  770. <li class="nav-header">${ _('Elapsed time') }</li>
  771. <li><span data-bind="text: elapsedTime().toHHMMSS()"></span></li>
  772. <!-- /ko -->
  773. <!-- /ko -->
  774. </ul>
  775. </div>
  776. </div>
  777. <div data-bind="css: {'span10': !$root.isMini(), 'span12': $root.isMini() }">
  778. <ul class="nav nav-pills margin-top-20">
  779. <li class="active"><a class="jb-logs-link" href="#job-mapreduce-task-attempt-page-logs${ SUFFIX }" data-toggle="tab">${ _('Logs') }</a></li>
  780. <li><a href="#job-mapreduce-task-attempt-page-counters${ SUFFIX }" data-bind="click: function(){ fetchProfile('counters'); $('a[href=\'#job-mapreduce-task-attempt-page-counters${ SUFFIX }\']').tab('show'); }">${ _('Counters') }</a></li>
  781. </ul>
  782. <div class="tab-content">
  783. <div class="tab-pane active" id="job-mapreduce-task-attempt-page-logs${ SUFFIX }">
  784. <ul class="nav nav-tabs">
  785. % for name in ['stdout', 'stderr', 'syslog']:
  786. <li class="${ name == 'stdout' and 'active' or '' }"><a href="javascript:void(0)" data-bind="click: function(data, e) { $(e.currentTarget).parent().siblings().removeClass('active'); $(e.currentTarget).parent().addClass('active'); fetchLogs('${ name }'); logActive('${ name }'); }, text: '${ name }'"></a></li>
  787. % endfor
  788. </ul>
  789. <pre data-bind="html: logs, logScroller: logs"></pre>
  790. </div>
  791. <div class="tab-pane" id="job-mapreduce-task-attempt-page-counters${ SUFFIX }">
  792. <div data-bind="template: { name: 'render-attempt-counters${ SUFFIX }', data: properties['counters'] }"></div>
  793. </div>
  794. </div>
  795. </div>
  796. </div>
  797. </script>
  798. <script type="text/html" id="job-spark-page${ SUFFIX }">
  799. <div class="row-fluid">
  800. <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
  801. <div class="sidebar-nav">
  802. <ul class="nav nav-list">
  803. <li class="nav-header">${ _('Id') }</li>
  804. <li class="break-word"><span data-bind="text: id"></span></li>
  805. <li class="nav-header">${ _('Name') }</li>
  806. <li><span data-bind="text: name"></span></li>
  807. <li class="nav-header">${ _('Type') }</li>
  808. <li><span data-bind="text: type"></span></li>
  809. <li class="nav-header">${ _('Status') }</li>
  810. <li><span data-bind="text: status"></span></li>
  811. <li class="nav-header">${ _('User') }</li>
  812. <li><span data-bind="text: user"></span></li>
  813. <li class="nav-header">${ _('Progress') }</li>
  814. <li><span data-bind="text: progress"></span>%</li>
  815. <li>
  816. <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': apiStatus() !== 'FAILED' && progress() < 100, 'progress-success': apiStatus() !== 'FAILED' && progress() === 100, 'progress-danger': apiStatus() === 'FAILED'}">
  817. <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
  818. </div>
  819. </li>
  820. <!-- ko if: !$root.isMini() -->
  821. <li class="nav-header">${ _('Duration') }</li>
  822. <li><span data-bind="text: duration().toHHMMSS()"></span></li>
  823. <li class="nav-header">${ _('Submitted') }</li>
  824. <li><span data-bind="text: submitted"></span></li>
  825. <!-- /ko -->
  826. </ul>
  827. </div>
  828. </div>
  829. <div data-bind="css:{'span10': !$root.isMini(), 'span12 no-margin': $root.isMini() }">
  830. <ul class="nav nav-pills margin-top-20">
  831. <li class="active"><a class="job-spark-logs-link" href="#job-spark-page-logs${ SUFFIX }" data-toggle="tab">${ _('Logs') }</a></li>
  832. <li><a href="#job-spark-page-executors${ SUFFIX }" data-bind="click: function(){ fetchProfile('executors'); $('a[href=\'#job-spark-page-executors${ SUFFIX }\']').tab('show'); }">${ _('Executors') }</a></li>
  833. <li><a href="#job-spark-page-properties${ SUFFIX }" data-toggle="tab">${ _('Properties') }</a></li>
  834. <li class="pull-right" data-bind="template: { name: 'job-actions${ SUFFIX }' }"></li>
  835. </ul>
  836. <div class="clearfix"></div>
  837. <div class="tab-content">
  838. <div class="tab-pane active" id="job-spark-page-logs${ SUFFIX }">
  839. <ul class="nav nav-tabs">
  840. % for name in ['stdout', 'stderr']:
  841. <li class="${ name == 'stdout' and 'active' or '' }"><a href="javascript:void(0)" data-bind="click: function(data, e) { $(e.currentTarget).parent().siblings().removeClass('active'); $(e.currentTarget).parent().addClass('active'); fetchLogs('${ name }'); logActive('${ name }'); }, text: '${ name }'"></a></li>
  842. % endfor
  843. </ul>
  844. <pre data-bind="html: logs, logScroller: logs"></pre>
  845. </div>
  846. <div class="tab-pane" id="job-spark-page-executors${ SUFFIX }">
  847. <form class="form-inline">
  848. <input data-bind="textFilter: textFilter, clearable: {value: textFilter}, valueUpdate: 'afterkeydown'" type="text" class="input-xlarge search-query" placeholder="${_('Filter by name')}">
  849. </form>
  850. <table class="table table-condensed">
  851. <thead>
  852. <tr>
  853. <th>${_('Executor Id')}</th>
  854. <th>${_('Address')}</th>
  855. <th>${_('RDD Blocks')}</th>
  856. <th>${_('Storage Memory')}</th>
  857. <th>${_('Disk Used')}</th>
  858. <th>${_('Active Tasks')}</th>
  859. <th>${_('Failed Tasks')}</th>
  860. <th>${_('Complete Tasks')}</th>
  861. <th>${_('Task Time')}</th>
  862. <th>${_('Input')}</th>
  863. <th>${_('Shuffle Read')}</th>
  864. <th>${_('Shuffle Write')}</th>
  865. </tr>
  866. </thead>
  867. <tbody data-bind="foreach: properties['executors']()['executor_list']">
  868. <tr data-bind="click: function() { $root.job().id(id); $root.job().fetchJob(); }" class="status-border pointer">
  869. <td data-bind="text: executor_id"></td>
  870. <td data-bind="text: address"></td>
  871. <td data-bind="text: rdd_blocks"></td>
  872. <td data-bind="text: storage_memory"></td>
  873. <td data-bind="text: disk_used"></td>
  874. <td data-bind="text: active_tasks"></td>
  875. <td data-bind="text: failed_tasks"></td>
  876. <td data-bind="text: complete_tasks"></td>
  877. <td data-bind="text: task_time"></td>
  878. <td data-bind="text: input"></td>
  879. <td data-bind="text: shuffle_read"></td>
  880. <td data-bind="text: shuffle_write"></td>
  881. </tr>
  882. </tbody>
  883. </table>
  884. </div>
  885. <div class="tab-pane" id="job-spark-page-properties${ SUFFIX }">
  886. <table class="datatables table table-condensed">
  887. <thead>
  888. <tr>
  889. <th>${_('Name')}</th>
  890. <th>${_('Value')}</th>
  891. </tr>
  892. </thead>
  893. <tbody data-bind="foreach: properties['metadata']">
  894. <tr>
  895. <td data-bind="text: name"></td>
  896. <td><!-- ko template: { name: 'link-or-text', data: { name: name(), value: value() } } --><!-- /ko --></td>
  897. </tr>
  898. </tbody>
  899. </table>
  900. </div>
  901. </div>
  902. </div>
  903. </div>
  904. </script>
  905. <script type="text/html" id="job-spark-executor-page${ SUFFIX }">
  906. <div class="row-fluid">
  907. <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
  908. <div class="sidebar-nav">
  909. <ul class="nav nav-list">
  910. <!-- ko with: properties -->
  911. <li class="nav-header">${ _('Id') }</li>
  912. <li class="break-word"><span data-bind="text: executor_id"></span></li>
  913. <!-- /ko -->
  914. <li class="nav-header">${ _('Type') }</li>
  915. <li><span data-bind="text: type"></span></li>
  916. <!-- ko if: !$root.isMini() -->
  917. <!-- ko with: properties -->
  918. <li class="nav-header">${ _('Address') }</li>
  919. <li><span data-bind="text: address"></span></li>
  920. <li class="nav-header">${ _('RDD Blocks') }</li>
  921. <li><span data-bind="text: rdd_blocks"></span></li>
  922. <li class="nav-header">${ _('Storage Memory') }</li>
  923. <li><span data-bind="text: storage_memory"></span></li>
  924. <li class="nav-header">${ _('Disk Used') }</li>
  925. <li><span data-bind="text: disk_used"></span></li>
  926. <li class="nav-header">${ _('Active Tasks') }</li>
  927. <li><span data-bind="text: active_tasks"></span></li>
  928. <li class="nav-header">${ _('Failed Tasks') }</li>
  929. <li><span data-bind="text: failed_tasks"></span></li>
  930. <li class="nav-header">${ _('Complet Tasks') }</li>
  931. <li><span data-bind="text: complete_tasks"></span></li>
  932. <li class="nav-header">${ _('Input') }</li>
  933. <li><span data-bind="text: input"></span></li>
  934. <li class="nav-header">${ _('Shuffle Read') }</li>
  935. <li><span data-bind="text: shuffle_read"></span></li>
  936. <li class="nav-header">${ _('Shuffle Write') }</li>
  937. <li><span data-bind="text: shuffle_write"></span></li>
  938. <!-- /ko -->
  939. <!-- /ko -->
  940. </ul>
  941. </div>
  942. </div>
  943. <div data-bind="css: {'span10': !$root.isMini(), 'span12': $root.isMini() }">
  944. <ul class="nav nav-pills margin-top-20">
  945. <li class="active"><a class="jb-logs-link" href="#job-spark-executor-page-logs${ SUFFIX }" data-toggle="tab">${ _('Logs') }</a></li>
  946. </ul>
  947. <div class="tab-content">
  948. <div class="tab-pane active" id="job-spark-executor-page-logs${ SUFFIX }">
  949. <ul class="nav nav-tabs">
  950. % for name in ['stdout', 'stderr']:
  951. <li class="${ name == 'stdout' and 'active' or '' }"><a href="javascript:void(0)" data-bind="click: function(data, e) { $(e.currentTarget).parent().siblings().removeClass('active'); $(e.currentTarget).parent().addClass('active'); fetchLogs('${ name }'); logActive('${ name }'); }, text: '${ name }'"></a></li>
  952. % endfor
  953. </ul>
  954. <pre data-bind="html: logs, logScroller: logs"></pre>
  955. </div>
  956. </div>
  957. </div>
  958. </div>
  959. </script>
  960. <script type="text/html" id="dataeng-job-page${ SUFFIX }">
  961. <button class="btn" title="${ _('Troubleshoot') }" data-bind="click: troubleshoot">
  962. <i class="fa fa-tachometer"></i> ${ _('Troubleshoot') }
  963. </button>
  964. <!-- ko if: type() == 'dataeng-job-HIVE' -->
  965. <div data-bind="template: { name: 'dataeng-job-hive-page${ SUFFIX }', data: $root.job() }"></div>
  966. <!-- /ko -->
  967. </script>
  968. <script type="text/html" id="dataeng-job-hive-page${ SUFFIX }">
  969. ${ _('Id') } <span data-bind="text: id"></span>
  970. ${ _('Name') } <span data-bind="text: name"></span>
  971. ${ _('Type') } <span data-bind="text: type"></span>
  972. ${ _('Status') } <span data-bind="text: status"></span>
  973. ${ _('User') } <span data-bind="text: user"></span>
  974. ${ _('Progress') } <span data-bind="text: progress"></span>
  975. ${ _('Duration') } <span data-bind="text: duration().toHHMMSS()"></span>
  976. ${ _('Submitted') } <span data-bind="text: submitted"></span>
  977. <br>
  978. <span data-bind="text: ko.mapping.toJSON(properties['properties'])"></span>
  979. ##<div data-bind="template: { name: 'render-properties${ SUFFIX }', data: properties['properties'] }"></div>
  980. </script>
  981. <script type="text/html" id="queries-page${ SUFFIX }">
  982. <div class="row-fluid" data-jobType="queries">
  983. <!-- ko if: id() -->
  984. <div data-bind="css: {'span2': !$root.isMini(), 'span12': $root.isMini() }">
  985. <div class="sidebar-nav">
  986. <ul class="nav nav-list">
  987. <!-- ko if: doc_url -->
  988. <li class="nav-header">${ _('Id') }</li>
  989. <li>
  990. <a data-bind="attr: {href: doc_url}" target="_blank" title="${ _('Open in impalad') }">
  991. <span data-bind="text: id"></span>
  992. </a>
  993. </li>
  994. <!-- /ko -->
  995. <!-- ko ifnot: doc_url -->
  996. <li class="nav-header">${ _('Id') }</li>
  997. <li class="break-word"><span data-bind="text: id"></span></li>
  998. <!-- /ko -->
  999. <li class="nav-header">${ _('User') }</li>
  1000. <li><span data-bind="text: user"></span></li>
  1001. <li class="nav-header">${ _('Progress') }</li>
  1002. <li>
  1003. <span data-bind="text: progress"></span>%
  1004. </li>
  1005. <li>
  1006. <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-danger': apiStatus() === 'FAILED', 'progress-warning': apiStatus() === 'RUNNING', 'progress-success': apiStatus() === 'SUCCEEDED' }">
  1007. <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
  1008. </div>
  1009. </li>
  1010. <li class="nav-header">${ _('Status') }</li>
  1011. <li><span data-bind="text: status"></span></li>
  1012. <!-- ko if: properties.plan && properties.plan().status && properties.plan().status.length > 2 -->
  1013. <li class="nav-header">${ _('Status Text') }</li>
  1014. <li><span data-bind="text: properties.plan().status"></span></li>
  1015. <!-- /ko -->
  1016. <!-- ko if: !$root.isMini() -->
  1017. <li class="nav-header">${ _('Open Duration') }</li>
  1018. <li><span data-bind="text: duration() && duration().toHHMMSS()"></span></li>
  1019. <li class="nav-header">${ _('Submitted') }</li>
  1020. <li><span data-bind="moment: {data: submitted, format: 'LLL'}"></span></li>
  1021. <!-- /ko -->
  1022. </ul>
  1023. </div>
  1024. </div>
  1025. <div data-bind="css:{'span10': !$root.isMini(), 'span12 no-margin': $root.isMini() }">
  1026. <ul class="nav nav-pills margin-top-20">
  1027. <li>
  1028. <a href="#queries-page-plan${ SUFFIX }" data-bind="click: function(){ $('a[href=\'#queries-page-plan${ SUFFIX }\']').tab('show'); }, event: {'shown': function () { if (!properties.plan || !properties.plan().plan_json) { fetchProfile('plan'); } } }">
  1029. ${ _('Plan') }</a>
  1030. </li>
  1031. <li>
  1032. <a href="#queries-page-stmt${ SUFFIX }" data-bind="click: function(){ $('a[href=\'#queries-page-stmt${ SUFFIX }\']').tab('show'); }">
  1033. ${ _('Query') }</a>
  1034. </li>
  1035. <li>
  1036. <a href="#queries-page-plan-text${ SUFFIX }" data-bind="click: function(){ $('a[href=\'#queries-page-plan-text${ SUFFIX }\']').tab('show'); }">
  1037. ${ _('Text Plan') }</a>
  1038. </li>
  1039. <li>
  1040. <a href="#queries-page-summary${ SUFFIX }" data-bind="click: function(){ $('a[href=\'#queries-page-summary${ SUFFIX }\']').tab('show'); }">
  1041. ${ _('Summary') }</a>
  1042. </li>
  1043. <li>
  1044. <a href="#queries-page-profile${ SUFFIX }" data-bind="click: function(){ $('a[href=\'#queries-page-profile${ SUFFIX }\']').tab('show'); }, event: {'shown': function () { if (!properties.profile || !properties.profile().profile) { fetchProfile('profile'); } } }">
  1045. ${ _('Profile') }</a>
  1046. </li>
  1047. <li>
  1048. <a href="#queries-page-memory${ SUFFIX }" data-bind="click: function(){ $('a[href=\'#queries-page-memory${ SUFFIX }\']').tab('show'); }, event: {'shown': function () { if (!properties.memory || !properties.memory().mem_usage) { fetchProfile('memory'); } } }">
  1049. ${ _('Memory') }</a>
  1050. </li>
  1051. </ul>
  1052. <div class="clearfix"></div>
  1053. <div class="tab-content">
  1054. <div class="tab-pane" id="queries-page-plan${ SUFFIX }" data-profile="plan">
  1055. <div data-bind="visible:properties.plan && properties.plan().plan_json && properties.plan().plan_json.plan_nodes.length">
  1056. <div id="queries-page-plan-graph${ SUFFIX }" data-bind="impalaDagre: {value: properties.plan && properties.plan().plan_json, height:$root.isMini() ? 250 : 600 }">
  1057. <svg class="query-plan" style="width:100%;height:100%;" id="queries-page-plan-svg${ SUFFIX }">
  1058. <g/>
  1059. </svg>
  1060. </div>
  1061. </div>
  1062. <pre data-bind="visible:!properties.plan || !properties.plan().plan_json || !properties.plan().plan_json.plan_nodes.length" >${ _('The selected tab has no data') }</pre>
  1063. </div>
  1064. <div class="tab-pane" id="queries-page-stmt${ SUFFIX }" data-profile="plan">
  1065. <pre data-bind="text: (properties.plan && properties.plan().stmt) || _('The selected tab has no data')"/>
  1066. </div>
  1067. <div class="tab-pane" id="queries-page-plan-text${ SUFFIX }" data-profile="plan">
  1068. <pre data-bind="text: (properties.plan && properties.plan().plan) || _('The selected tab has no data')"/>
  1069. </div>
  1070. <div class="tab-pane" id="queries-page-summary${ SUFFIX }" data-profile="plan">
  1071. <pre data-bind="text: (properties.plan && properties.plan().summary) || _('The selected tab has no data')"/>
  1072. </div>
  1073. <div class="tab-pane" id="queries-page-profile${ SUFFIX }" data-profile="profile">
  1074. <pre data-bind="text: (properties.profile && properties.profile().profile) || _('The selected tab has no data')"/>
  1075. </div>
  1076. <div class="tab-pane" id="queries-page-memory${ SUFFIX }" data-profile="mem_usage">
  1077. <pre data-bind="text: (properties.memory && properties.memory().mem_usage) || _('The selected tab has no data')"/>
  1078. </div>
  1079. </div>
  1080. </div>
  1081. <!-- /ko -->
  1082. </div>
  1083. </script>
  1084. <script type="text/html" id="livy-session-page${ SUFFIX }">
  1085. <div class="row-fluid">
  1086. <div data-bind="css: {'span2': !$root.isMini(), 'span12': $root.isMini() }">
  1087. <div class="sidebar-nav">
  1088. <ul class="nav nav-list">
  1089. <li class="nav-header">${ _('Id') }</li>
  1090. <li class="break-word"><span data-bind="text: id"></span></li>
  1091. <!-- ko if: doc_url -->
  1092. <li class="nav-header">${ _('Document') }</li>
  1093. <li>
  1094. <a data-bind="hueLink: doc_url" href="javascript: void(0);" title="${ _('Open in editor') }">
  1095. <span data-bind="text: name"></span>
  1096. </a>
  1097. </li>
  1098. <!-- /ko -->
  1099. <!-- ko ifnot: doc_url -->
  1100. <li class="nav-header">${ _('Name') }</li>
  1101. <li><span data-bind="text: name"></span></li>
  1102. <!-- /ko -->
  1103. <li class="nav-header">${ _('Status') }</li>
  1104. <li><span data-bind="text: status"></span></li>
  1105. <li class="nav-header">${ _('User') }</li>
  1106. <li><span data-bind="text: user"></span></li>
  1107. <li class="nav-header">${ _('Progress') }</li>
  1108. <li><span data-bind="text: progress"></span>%</li>
  1109. <li>
  1110. <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-danger': apiStatus() === 'FAILED', 'progress-warning': apiStatus() === 'RUNNING', 'progress-success': apiStatus() === 'SUCCEEDED' }">
  1111. <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
  1112. </div>
  1113. </li>
  1114. <li class="nav-header">${ _('Duration') }</li>
  1115. <li><span data-bind="text: duration().toHHMMSS()"></span></li>
  1116. <li class="nav-header">${ _('Submitted') }</li>
  1117. <li><span data-bind="moment: {data: submitted, format: 'LLL'}"></span></li>
  1118. </ul>
  1119. </div>
  1120. </div>
  1121. <div data-bind="css:{'span10': !$root.isMini(), 'span12 no-margin': $root.isMini() }">
  1122. <ul class="nav nav-pills margin-top-20">
  1123. <li>
  1124. <a href="#livy-session-page-statements${ SUFFIX }" data-bind="click: function(){ fetchProfile('properties'); $('a[href=\'#livy-session-page-statements${ SUFFIX }\']').tab('show'); }">
  1125. ${ _('Properties') }</a>
  1126. </li>
  1127. </ul>
  1128. <div class="clearfix"></div>
  1129. <div class="tab-content">
  1130. <div class="tab-pane active" id="livy-session-page-statements${ SUFFIX }">
  1131. <table id="actionsTable" class="datatables table table-condensed">
  1132. <thead>
  1133. <tr>
  1134. <th>${_('Id')}</th>
  1135. <th>${_('State')}</th>
  1136. <th>${_('Output')}</th>
  1137. </tr>
  1138. </thead>
  1139. <tbody data-bind="foreach: properties['statements']">
  1140. <tr data-bind="click: function() { $root.job().id(id); $root.job().fetchJob(); }" class="pointer">
  1141. <td>
  1142. <a data-bind="hueLink: '/jobbrowser/jobs/' + id(), clickBubble: false">
  1143. <i class="fa fa-tasks"></i>
  1144. </a>
  1145. </td>
  1146. <td data-bind="text: state"></td>
  1147. <td data-bind="text: output"></td>
  1148. </tr>
  1149. </tbody>
  1150. </table>
  1151. </div>
  1152. </div>
  1153. </div>
  1154. </div>
  1155. </script>
  1156. <script type="text/html" id="job-actions${ SUFFIX }">
  1157. <div class="btn-group">
  1158. <!-- ko if: hasResume -->
  1159. <button class="btn" title="${ _('Resume selected') }" data-bind="click: function() { control('resume'); }, enable: resumeEnabled">
  1160. <i class="fa fa-play"></i> <!-- ko ifnot: $root.isMini -->${ _('Resume') }<!-- /ko -->
  1161. </button>
  1162. <!-- /ko -->
  1163. <!-- ko if: hasPause -->
  1164. <button class="btn" title="${ _('Suspend selected') }" data-bind="click: function() { control('suspend'); }, enable: pauseEnabled">
  1165. <i class="fa fa-pause"></i> <!-- ko ifnot: $root.isMini -->${ _('Suspend') }<!-- /ko -->
  1166. </button>
  1167. <!-- /ko -->
  1168. <!-- ko if: hasRerun -->
  1169. <button class="btn" title="${ _('Rerun selected') }" data-bind="click: function() { control('rerun'); }, enable: rerunEnabled">
  1170. <i class="fa fa-repeat"></i> <!-- ko ifnot: $root.isMini -->${ _('Rerun') }<!-- /ko -->
  1171. </button>
  1172. <!-- /ko -->
  1173. % if not DISABLE_KILLING_JOBS.get():
  1174. <!-- ko if: hasKill -->
  1175. <button class="btn btn-danger disable-feedback" title="${_('Stop selected')}" data-bind="click: function() { $('#killModal${ SUFFIX }').modal('show'); }, enable: killEnabled">
  1176. <i class="fa fa-times"></i> <!-- ko ifnot: $root.isMini -->${_('Kill')}<!-- /ko -->
  1177. </button>
  1178. <!-- /ko -->
  1179. % endif
  1180. <!-- ko if: hasIgnore -->
  1181. <button class="btn btn-danger disable-feedback" title="${_('Ignore selected')}" data-bind="click: function() { control('ignore'); }, enable: ignoreEnabled">
  1182. ## TODO confirmation
  1183. <i class="fa fa-eraser"></i> <!-- ko ifnot: $root.isMini -->${_('Ignore')}<!-- /ko -->
  1184. </button>
  1185. <!-- /ko -->
  1186. </div>
  1187. </script>
  1188. <script type="text/html" id="workflow-page${ SUFFIX }">
  1189. <div class="row-fluid">
  1190. <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
  1191. <div class="sidebar-nav">
  1192. <ul class="nav nav-list">
  1193. <li class="nav-header" data-bind="visible: ! $root.isMini()">${ _('Id') }</li>
  1194. <li class="break-word" data-bind="visible: ! $root.isMini()"><span data-bind="text: id"></span></li>
  1195. <!-- ko if: doc_url -->
  1196. <li class="nav-header">${ _('Document') }</li>
  1197. <li>
  1198. <a data-bind="documentContextPopover: { uuid: doc_url().split('=')[1], orientation: 'bottom', offset: { top: 5 } }" href="javascript: void(0);" title="${ _('Preview document') }">
  1199. <span data-bind="text: name"></span> <i class="fa fa-info"></i>
  1200. </a>
  1201. </li>
  1202. <!-- /ko -->
  1203. <!-- ko ifnot: doc_url -->
  1204. <li class="nav-header">${ _('Name') }</li>
  1205. <li><span data-bind="text: name"></span></li>
  1206. <!-- /ko -->
  1207. <li class="nav-header" data-bind="visible: ! $root.isMini()">${ _('Status') }</li>
  1208. <li><span data-bind="text: status, visible: ! $root.isMini()"></span></li>
  1209. <li class="nav-header">${ _('User') }</li>
  1210. <li><span data-bind="text: user"></span></li>
  1211. <li class="nav-header">${ _('Progress') }</li>
  1212. <li><span data-bind="text: progress"></span>%</li>
  1213. <li>
  1214. <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-danger': apiStatus() === 'FAILED', 'progress-warning': apiStatus() === 'RUNNING', 'progress-success': apiStatus() === 'SUCCEEDED' }, attr: {title: status}">
  1215. <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
  1216. </div>
  1217. </li>
  1218. <li data-bind="visible: ! $root.isMini()" class="nav-header">${ _('Duration') }</li>
  1219. <li data-bind="visible: ! $root.isMini()"><span data-bind="text: duration().toHHMMSS()"></span></li>
  1220. <li class="nav-header" data-bind="visible: ! $root.isMini()">${ _('Submitted') }</li>
  1221. <li data-bind="visible: ! $root.isMini()"><span data-bind="moment: {data: submitted, format: 'LLL'}"></span></li>
  1222. <!-- ko if: properties['parameters'].length > 0 -->
  1223. <li class="nav-header">${ _('Variables') }</li>
  1224. <li>
  1225. <ul class="unstyled" data-bind="foreach: properties['parameters']">
  1226. <li class="margin-top-5">
  1227. <span data-bind="text: name, attr: { title: value }" class="muted"></span><br>
  1228. &nbsp;
  1229. <!-- ko if: link -->
  1230. <a data-bind="hueLink: link, text: value, attr: { title: value }" href="javascript: void(0);">
  1231. </a>
  1232. <!-- /ko -->
  1233. <!-- ko ifnot: link -->
  1234. <span data-bind="text: value, attr: { title: value }"></span>
  1235. <!-- /ko -->
  1236. </li>
  1237. </ul>
  1238. </li>
  1239. <!-- /ko -->
  1240. </ul>
  1241. </div>
  1242. </div>
  1243. <div data-bind="css: { 'span10': !$root.isMini(), 'span12 no-margin': $root.isMini() }">
  1244. <ul class="nav nav-pills margin-top-20">
  1245. %if not is_mini:
  1246. <li class="active"><a href="#workflow-page-graph${ SUFFIX }" data-toggle="tab">${ _('Graph') }</a></li>
  1247. %endif
  1248. <li><a href="#workflow-page-metadata${ SUFFIX }" data-bind="click: function(){ fetchProfile('properties'); $('a[href=\'#workflow-page-metadata${ SUFFIX }\']').tab('show'); }">${ _('Properties') }</a></li>
  1249. <li><a class="jb-logs-link" href="#workflow-page-logs${ SUFFIX }" data-toggle="tab">${ _('Logs') }</a></li>
  1250. <li class="${ 'active' if is_mini else ''}"><a href="#workflow-page-tasks${ SUFFIX }" data-toggle="tab">${ _('Tasks') }</a></li>
  1251. <li><a href="#workflow-page-xml${ SUFFIX }" data-bind="click: function(){ fetchProfile('xml'); $('a[href=\'#workflow-page-xml${ SUFFIX }\']').tab('show'); }">${ _('XML') }</a></li>
  1252. <li class="pull-right" data-bind="template: { name: 'job-actions${ SUFFIX }' }"></li>
  1253. </ul>
  1254. <div class="clearfix"></div>
  1255. <div class="tab-content">
  1256. %if not is_mini:
  1257. <div class="tab-pane active dashboard-container" id="workflow-page-graph${ SUFFIX }"></div>
  1258. %endif
  1259. <div class="tab-pane" id="workflow-page-logs${ SUFFIX }">
  1260. <pre data-bind="html: logs, logScroller: logs"></pre>
  1261. </div>
  1262. <div class="tab-pane ${ 'active' if is_mini else ''}" id="workflow-page-tasks${ SUFFIX }">
  1263. <table id="actionsTable" class="datatables table table-condensed">
  1264. <thead>
  1265. <tr>
  1266. <th>${_('Log')}</th>
  1267. <th>${_('Status')}</th>
  1268. <th>${_('Error message')}</th>
  1269. <th>${_('Error code')}</th>
  1270. <th>${_('External id')}</th>
  1271. <th>${_('Id')}</th>
  1272. <th>${_('Start time')}</th>
  1273. <th>${_('End time')}</th>
  1274. </tr>
  1275. </thead>
  1276. <tbody data-bind="foreach: properties['actions']">
  1277. <tr data-bind="click: function() { $root.job().id(id); $root.job().fetchJob(); }" class="pointer">
  1278. <td>
  1279. <a data-bind="hueLink: '/jobbrowser/jobs/' + externalId(), clickBubble: false">
  1280. <i class="fa fa-tasks"></i>
  1281. </a>
  1282. </td>
  1283. <td data-bind="text: status"></td>
  1284. <td data-bind="text: errorMessage"></td>
  1285. <td data-bind="text: errorCode"></td>
  1286. <td data-bind="text: externalId"></td>
  1287. <td data-bind="text: id"></td>
  1288. <td data-bind="moment: {data: startTime, format: 'LLL'}"></td>
  1289. <td data-bind="moment: {data: endTime, format: 'LLL'}"></td>
  1290. </tr>
  1291. </tbody>
  1292. </table>
  1293. </div>
  1294. <div class="tab-pane" id="workflow-page-metadata${ SUFFIX }">
  1295. <div data-bind="template: { name: 'render-properties${ SUFFIX }', data: properties['properties'] }"></div>
  1296. </div>
  1297. <div class="tab-pane" id="workflow-page-xml${ SUFFIX }">
  1298. <div data-bind="readOnlyAce: properties['xml'], path: 'xml', type: 'xml'"></div>
  1299. </div>
  1300. </div>
  1301. </div>
  1302. </div>
  1303. </script>
  1304. <script type="text/html" id="workflow-action-page${ SUFFIX }">
  1305. <div class="row-fluid">
  1306. <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
  1307. <div class="sidebar-nav">
  1308. <ul class="nav nav-list">
  1309. <li class="nav-header">${ _('Id') }</li>
  1310. <li class="break-word"><span data-bind="text: id"></span></li>
  1311. <li class="nav-header">${ _('Name') }</li>
  1312. <li><span data-bind="text: name"></span></li>
  1313. <li class="nav-header">${ _('Type') }</li>
  1314. <li><span data-bind="text: type"></span></li>
  1315. <li class="nav-header">${ _('Job') }</li>
  1316. <li>
  1317. <a data-bind="hueLink: '/jobbrowser/jobs/' + properties['externalId']()" href="javascript: void(0);">
  1318. <span data-bind="text: properties['externalId']"></span>
  1319. </a>
  1320. </li>
  1321. <li class="nav-header">${ _('Status') }</li>
  1322. <li><span data-bind="text: status"></span></li>
  1323. </ul>
  1324. </div>
  1325. </div>
  1326. <div data-bind="css:{'span10': !$root.isMini(), 'span12 no-margin': $root.isMini() }">
  1327. <ul class="nav nav-pills margin-top-20">
  1328. <li class="active"><a href="#workflow-action-page-metadata${ SUFFIX }" data-toggle="tab">${ _('Properties') }</a></li>
  1329. <li><a href="#workflow-action-page-tasks${ SUFFIX }" data-toggle="tab">${ _('Child jobs') }</a></li>
  1330. <li><a href="#workflow-action-page-xml${ SUFFIX }" data-toggle="tab">${ _('XML') }</a></li>
  1331. </ul>
  1332. <div class="tab-content">
  1333. <div class="tab-pane active" id="workflow-action-page-metadata${ SUFFIX }">
  1334. <table class="datatables table table-condensed">
  1335. <thead>
  1336. <tr>
  1337. <th>${_('Name')}</th>
  1338. <th>${_('Value')}</th>
  1339. </tr>
  1340. </thead>
  1341. <tbody data-bind="foreach: properties['properties']">
  1342. <tr>
  1343. <td data-bind="text: name"></td>
  1344. <td data-bind="text: value"></td>
  1345. </tr>
  1346. </tbody>
  1347. </table>
  1348. </div>
  1349. <div class="tab-pane" id="workflow-action-page-tasks${ SUFFIX }">
  1350. <!-- ko if: properties['externalChildIDs'].length > 0 -->
  1351. <table class="table table-condensed datatables">
  1352. <thead>
  1353. <tr>
  1354. <th>${ _('Ids') }</th>
  1355. </tr>
  1356. </thead>
  1357. <tbody data-bind="foreach: properties['externalChildIDs']">
  1358. <tr>
  1359. <td>
  1360. <a data-bind="hueLink: '/jobbrowser/jobs/' + $data, text: $data" href="javascript: void(0);">
  1361. </a>
  1362. </td>
  1363. </tr>
  1364. </tbody>
  1365. </table>
  1366. <!-- /ko -->
  1367. <!-- ko if: properties['externalChildIDs'].length == 0 -->
  1368. ${ _('No external jobs') }
  1369. <!-- /ko -->
  1370. </div>
  1371. <div class="tab-pane" id="workflow-action-page-xml${ SUFFIX }">
  1372. <div data-bind="readOnlyAce: properties['conf'], type: 'xml'"></div>
  1373. </div>
  1374. </div>
  1375. </div>
  1376. </div>
  1377. </script>
  1378. <script type="text/html" id="schedule-page${ SUFFIX }">
  1379. <div class="row-fluid">
  1380. <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
  1381. <div class="sidebar-nav">
  1382. <ul class="nav nav-list">
  1383. <li class="nav-header" data-bind="visible: ! $root.isMini()">${ _('Id') }</li>
  1384. <li class="break-word" data-bind="visible: ! $root.isMini()"><span data-bind="text: id"></span></li>
  1385. <!-- ko if: doc_url -->
  1386. <li class="nav-header">${ _('Document') }</li>
  1387. <li>
  1388. <a data-bind="documentContextPopover: { uuid: doc_url().split('=')[1], orientation: 'bottom', offset: { top: 5 } }" href="javascript: void(0);" title="${ _('Preview document') }">
  1389. <span data-bind="text: name"></span> <i class="fa fa-info"></i>
  1390. </a>
  1391. </li>
  1392. <!-- /ko -->
  1393. <!-- ko ifnot: doc_url -->
  1394. <li class="nav-header">${ _('Name') }</li>
  1395. <li><span data-bind="text: name"></span></li>
  1396. <!-- /ko -->
  1397. <li class="nav-header" data-bind="visible: ! $root.isMini()">${ _('Type') }</li>
  1398. <li data-bind="visible: ! $root.isMini()"><span data-bind="text: type"></span></li>
  1399. <li class="nav-header" data-bind="visible: ! $root.isMini()">${ _('Status') }</li>
  1400. <li data-bind="visible: ! $root.isMini()"><span data-bind="text: status"></span></li>
  1401. <li class="nav-header">${ _('User') }</li>
  1402. <li><span data-bind="text: user"></span></li>
  1403. <li class="nav-header">${ _('Progress') }</li>
  1404. <li><span data-bind="text: progress"></span>%</li>
  1405. <li>
  1406. <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': apiStatus() !== 'FAILED' && progress() < 100, 'progress-success': apiStatus() !== 'FAILED' && progress() === 100, 'progress-danger': apiStatus() === 'FAILED'}, attr: {title: status}">
  1407. <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
  1408. </div>
  1409. </li>
  1410. <!-- ko if: !$root.isMini() -->
  1411. <li class="nav-header">${ _('Submitted') }</li>
  1412. <li><span data-bind="text: submitted"></span></li>
  1413. <li class="nav-header">${ _('Next Run') }</li>
  1414. <li><span data-bind="text: properties['nextTime']"></span></li>
  1415. <li class="nav-header">${ _('Total Actions') }</li>
  1416. <li><span data-bind="text: properties['total_actions']"></span></li>
  1417. <li class="nav-header">${ _('End time') }</li>
  1418. <li><span data-bind="text: properties['endTime']"></span></li>
  1419. <!-- /ko -->
  1420. </ul>
  1421. </div>
  1422. </div>
  1423. <div data-bind="css:{'span10': !$root.isMini(), 'span12 no-margin': $root.isMini() }">
  1424. <ul class="nav nav-pills margin-top-20">
  1425. <li class="active"><a href="#schedule-page-calendar${ SUFFIX }" data-toggle="tab">${ _('Tasks') }</a></li>
  1426. <li><a class="jb-logs-link" href="#schedule-page-logs${ SUFFIX }" data-toggle="tab">${ _('Logs') }</a></li>
  1427. <li><a href="#schedule-page-metadata${ SUFFIX }" data-bind="click: function(){ fetchProfile('properties'); $('a[href=\'#schedule-page-metadata${ SUFFIX }\']').tab('show'); }">${ _('Properties') }</a></li>
  1428. <li><a href="#schedule-page-xml${ SUFFIX }" data-bind="click: function(){ fetchProfile('xml'); $('a[href=\'#schedule-page-xml${ SUFFIX }\']').tab('show'); }">${ _('XML') }</a></li>
  1429. <li class="pull-right" data-bind="template: { name: 'job-actions${ SUFFIX }' }"></li>
  1430. </ul>
  1431. <div class="clearfix"></div>
  1432. <div class="tab-content">
  1433. <div class="tab-pane active" id="schedule-page-calendar${ SUFFIX }">
  1434. <!-- ko with: coordinatorActions() -->
  1435. <form class="form-inline">
  1436. ##<input data-bind="value: textFilter" type="text" class="input-xlarge search-query" placeholder="${_('Filter by name')}">
  1437. ##<span data-bind="foreach: statesValuesFilter">
  1438. ## <label class="checkbox">
  1439. ## <div class="pull-left margin-left-5 status-border status-content" data-bind="css: value, hueCheckbox: checked"></div>
  1440. ## <div class="inline-block" data-bind="text: name, toggle: checked"></div>
  1441. ## </label>
  1442. ##</span>
  1443. <div data-bind="template: { name: 'job-actions${ SUFFIX }' }" class="pull-right"></div>
  1444. </form>
  1445. <table id="schedulesTable" class="datatables table table-condensed status-border-container">
  1446. <thead>
  1447. <tr>
  1448. <th width="1%"><div class="select-all hue-checkbox fa"></div></th>
  1449. <th>${_('Status')}</th>
  1450. <th>${_('Title')}</th>
  1451. <th>${_('type')}</th>
  1452. <th>${_('errorMessage')}</th>
  1453. <th>${_('missingDependencies')}</th>
  1454. <th>${_('number')}</th>
  1455. <th>${_('errorCode')}</th>
  1456. <th>${_('externalId')}</th>
  1457. <th>${_('id')}</th>
  1458. <th>${_('lastModifiedTime')}</th>
  1459. </tr>
  1460. </thead>
  1461. <tbody data-bind="foreach: apps">
  1462. <tr class="status-border pointer" data-bind="css: {'completed': properties.status() == 'SUCCEEDED', 'running': ['RUNNING', 'FAILED', 'KILLED'].indexOf(properties.status()) != -1, 'failed': properties.status() == 'FAILED' || properties.status() == 'KILLED'}, click: function() { if (properties.externalId() && properties.externalId() != '-') { $root.job().id(properties.externalId()); $root.job().fetchJob(); } }">
  1463. <td data-bind="click: function() {}, clickBubble: false">
  1464. <div class="hue-checkbox fa" data-bind="click: function() {}, clickBubble: false, multiCheck: '#schedulesTable', value: $data, hueChecked: $parent.selectedJobs"></div>
  1465. </td>
  1466. <td data-bind="text: properties.status"></td>
  1467. <td data-bind="text: properties.title"></td>
  1468. <td data-bind="text: properties.type"></td>
  1469. <td data-bind="text: properties.errorMessage"></td>
  1470. <td data-bind="text: properties.missingDependencies"></td>
  1471. <td data-bind="text: properties.number"></td>
  1472. <td data-bind="text: properties.errorCode"></td>
  1473. <td data-bind="text: properties.externalId"></td>
  1474. <td data-bind="text: properties.id"></td>
  1475. <td data-bind="text: properties.lastModifiedTime"></td>
  1476. </tr>
  1477. </tbody>
  1478. </table>
  1479. <!-- /ko -->
  1480. </div>
  1481. <div class="tab-pane" id="schedule-page-logs${ SUFFIX }">
  1482. <pre data-bind="html: logs, logScroller: logs"></pre>
  1483. </div>
  1484. <div class="tab-pane" id="schedule-page-metadata${ SUFFIX }">
  1485. <div data-bind="template: { name: 'render-properties${ SUFFIX }', data: properties['properties'] }"></div>
  1486. </div>
  1487. <div class="tab-pane" id="schedule-page-xml${ SUFFIX }">
  1488. <div data-bind="readOnlyAce: properties['xml'], path: 'xml', type: 'xml'"></div>
  1489. </div>
  1490. </div>
  1491. </div>
  1492. </div>
  1493. </script>
  1494. <script type="text/html" id="bundle-page${ SUFFIX }">
  1495. <div class="row-fluid">
  1496. <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
  1497. <div class="sidebar-nav">
  1498. <ul class="nav nav-list">
  1499. <li class="nav-header">${ _('Id') }</li>
  1500. <li class="break-word"><span data-bind="text: id"></span></li>
  1501. <!-- ko if: doc_url -->
  1502. <li class="nav-header">${ _('Document') }</li>
  1503. <li>
  1504. <a data-bind="documentContextPopover: { uuid: doc_url().split('=')[1], orientation: 'bottom', offset: { top: 5 } }" href="javascript: void(0);" title="${ _('Preview document') }">
  1505. <span data-bind="text: name"></span> <i class="fa fa-info"></i>
  1506. </a>
  1507. </li>
  1508. <!-- /ko -->
  1509. <!-- ko ifnot: doc_url -->
  1510. <li class="nav-header">${ _('Name') }</li>
  1511. <li><span data-bind="text: name"></span></li>
  1512. <!-- /ko -->
  1513. <li class="nav-header">${ _('Type') }</li>
  1514. <li><span data-bind="text: type"></span></li>
  1515. <li class="nav-header">${ _('Status') }</li>
  1516. <li><span data-bind="text: status"></span></li>
  1517. <li class="nav-header">${ _('User') }</li>
  1518. <li><span data-bind="text: user"></span></li>
  1519. <li class="nav-header">${ _('Progress') }</li>
  1520. <li><span data-bind="text: progress"></span>%</li>
  1521. <li>
  1522. <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-danger': apiStatus() === 'FAILED', 'progress-warning': apiStatus() !== 'FAILED' && progress() < 100, 'progress-success': apiStatus() !== 'FAILED' && progress() === 100}">
  1523. <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
  1524. </div>
  1525. </li>
  1526. ##<li class="nav-header">${ _('Duration') }</li>
  1527. ##<li><span data-bind="text: duration"></span></li>
  1528. <li class="nav-header">${ _('Submitted') }</li>
  1529. <li><span data-bind="text: submitted"></span></li>
  1530. ##<li class="nav-header">${ _('Next Run') }</li>
  1531. ##<li><span data-bind="text: properties['nextTime']"></span></li>
  1532. ##<li class="nav-header">${ _('Total Actions') }</li>
  1533. ##<li><span data-bind="text: properties['total_actions']"></span></li>
  1534. ##<li class="nav-header">${ _('End time') }</li>
  1535. ##<li><span data-bind="text: properties['endTime']"></span></li>
  1536. </ul>
  1537. </div>
  1538. </div>
  1539. <div data-bind="css:{'span10': !$root.isMini(), 'span12 no-margin': $root.isMini() }">
  1540. <ul class="nav nav-pills margin-top-20">
  1541. <li class="active"><a href="#bundle-page-coordinators${ SUFFIX }" data-toggle="tab">${ _('Tasks') }</a></li>
  1542. <li><a class="jb-logs-link" href="#bundle-page-logs${ SUFFIX }" data-toggle="tab">${ _('Logs') }</a></li>
  1543. <li><a href="#bundle-page-metadata${ SUFFIX }" data-bind="click: function(){ fetchProfile('properties'); $('a[href=\'#bundle-page-metadata${ SUFFIX }\']').tab('show'); }">${ _('Properties') }</a></li>
  1544. <li><a href="#bundle-page-xml${ SUFFIX }" data-bind="click: function(){ fetchProfile('xml'); $('a[href=\'#bundle-page-xml${ SUFFIX }\']').tab('show'); }">${ _('XML') }</a></li>
  1545. <li class="pull-right" data-bind="template: { name: 'job-actions${ SUFFIX }' }"></li>
  1546. </ul>
  1547. <div class="clearfix"></div>
  1548. <div class="tab-content">
  1549. <div class="tab-pane active" id="bundle-page-coordinators${ SUFFIX }">
  1550. <table id="coordsTable" class="datatables table table-condensed status-border-container">
  1551. <thead>
  1552. <tr>
  1553. <th>${_('Status')}</th>
  1554. <th>${_('Name')}</th>
  1555. <th>${_('Type')}</th>
  1556. <th>${_('nextMaterializedTime')}</th>
  1557. <th>${_('lastAction')}</th>
  1558. <th>${_('frequency')}</th>
  1559. <th>${_('timeUnit')}</th>
  1560. <th>${_('externalId')}</th>
  1561. <th>${_('id')}</th>
  1562. <th>${_('pauseTime')}</th>
  1563. </tr>
  1564. </thead>
  1565. <tbody data-bind="foreach: properties['actions']">
  1566. <tr class="status-border pointer" data-bind="css: {'completed': status() == 'SUCCEEDED', 'running': ['SUCCEEDED', 'FAILED', 'KILLED'].indexOf(status()) != -1, 'failed': status() == 'FAILED' || status() == 'KILLED'}, click: function() { if (id()) { $root.job().id(id()); $root.job().fetchJob();} }">
  1567. <td data-bind="text: status"></td>
  1568. <td data-bind="text: name"></td>
  1569. <td data-bind="text: type"></td>
  1570. <td data-bind="text: nextMaterializedTime"></td>
  1571. <td data-bind="text: lastAction"></td>
  1572. <td data-bind="text: frequency"></td>
  1573. <td data-bind="text: timeUnit"></td>
  1574. <td data-bind="text: externalId"></td>
  1575. <td data-bind="text: id"></td>
  1576. <td data-bind="text: pauseTime"></td>
  1577. </tr>
  1578. </tbody>
  1579. </table>
  1580. </div>
  1581. <div class="tab-pane" id="bundle-page-logs${ SUFFIX }">
  1582. <pre data-bind="html: logs, logScroller: logs"></pre>
  1583. </div>
  1584. <div class="tab-pane" id="bundle-page-metadata${ SUFFIX }">
  1585. <div data-bind="template: { name: 'render-properties${ SUFFIX }', data: properties['properties'] }"></div>
  1586. </div>
  1587. <div class="tab-pane" id="bundle-page-xml${ SUFFIX }">
  1588. <div data-bind="readOnlyAce: properties['xml'], path: 'xml', type: 'xml'"></div>
  1589. </div>
  1590. </div>
  1591. </div>
  1592. </div>
  1593. </script>
  1594. <script type="text/html" id="render-properties${ SUFFIX }">
  1595. <!-- ko hueSpinner: { spin: !$data.properties, center: true, size: 'xlarge' } --><!-- /ko -->
  1596. <!-- ko if: $data.properties -->
  1597. <!-- ko if: !$root.isMini() -->
  1598. <form class="form-search">
  1599. <input type="text" data-bind="clearable: $parent.propertiesFilter, valueUpdate: 'afterkeydown'" class="input-xlarge search-query" placeholder="${_('Text Filter')}">
  1600. </form>
  1601. <br>
  1602. <!-- /ko -->
  1603. <table id="jobbrowserJobPropertiesTable" class="table table-condensed">
  1604. <thead>
  1605. <tr>
  1606. <th>${ _('Name') }</th>
  1607. <th>${ _('Value') }</th>
  1608. </tr>
  1609. </thead>
  1610. <tbody data-bind="foreach: Object.keys($data.properties)">
  1611. <tr>
  1612. <td data-bind="text: $data"></td>
  1613. <td>
  1614. <!-- ko template: { name: 'link-or-text${ SUFFIX }', data: { name: $data, value: $parent.properties[$data] } } --><!-- /ko -->
  1615. </td>
  1616. </tr>
  1617. </tbody>
  1618. </table>
  1619. <!-- /ko -->
  1620. </script>
  1621. <script type="text/html" id="render-page-counters${ SUFFIX }">
  1622. <!-- ko hueSpinner: { spin: !$data, center: true, size: 'xlarge' } --><!-- /ko -->
  1623. <!-- ko if: $data -->
  1624. <!-- ko ifnot: $data.counterGroup -->
  1625. <span class="muted">${ _('There are currently no counters to be displayed.') }</span>
  1626. <!-- /ko -->
  1627. <!-- ko if: $data.counterGroup -->
  1628. <!-- ko foreach: $data.counterGroup -->
  1629. <h3 data-bind="text: counterGroupName"></h3>
  1630. <table class="table table-condensed">
  1631. <thead>
  1632. <tr>
  1633. <th>${ _('Name') }</th>
  1634. <th width="15%">${ _('Maps total') }</th>
  1635. <th width="15%">${ _('Reduces total') }</th>
  1636. <th width="15%">${ _('Total') }</th>
  1637. </tr>
  1638. </thead>
  1639. <tbody data-bind="foreach: counter">
  1640. <tr>
  1641. <td data-bind="text: name"></td>
  1642. <td data-bind="text: mapCounterValue"></td>
  1643. <td data-bind="text: reduceCounterValue"></td>
  1644. <td data-bind="text: totalCounterValue"></td>
  1645. </tr>
  1646. </tbody>
  1647. </table>
  1648. <!-- /ko -->
  1649. <!-- /ko -->
  1650. <!-- /ko -->
  1651. </script>
  1652. <script type="text/html" id="render-task-counters${ SUFFIX }">
  1653. <!-- ko hueSpinner: { spin: !$data.id, center: true, size: 'xlarge' } --><!-- /ko -->
  1654. <!-- ko if: $data.id -->
  1655. <!-- ko ifnot: $data.taskCounterGroup -->
  1656. <span class="muted">${ _('There are currently no counters to be displayed.') }</span>
  1657. <!-- /ko -->
  1658. <!-- ko if: $data.taskCounterGroup -->
  1659. <!-- ko foreach: $data.taskCounterGroup -->
  1660. <h3 data-bind="text: counterGroupName"></h3>
  1661. <table class="table table-condensed">
  1662. <thead>
  1663. <tr>
  1664. <th>${ _('Name') }</th>
  1665. <th width="30%">${ _('Value') }</th>
  1666. </tr>
  1667. </thead>
  1668. <tbody data-bind="foreach: counter">
  1669. <tr>
  1670. <td data-bind="text: name"></td>
  1671. <td data-bind="text: value"></td>
  1672. </tr>
  1673. </tbody>
  1674. </table>
  1675. <!-- /ko -->
  1676. <!-- /ko -->
  1677. <!-- /ko -->
  1678. </script>
  1679. <script type="text/html" id="render-attempt-counters${ SUFFIX }">
  1680. <!-- ko hueSpinner: { spin: !$data.id, center: true, size: 'xlarge' } --><!-- /ko -->
  1681. <!-- ko if: $data.id -->
  1682. <!-- ko ifnot: $data.taskAttemptCounterGroup -->
  1683. <span class="muted">${ _('There are currently no counters to be displayed.') }</span>
  1684. <!-- /ko -->
  1685. <!-- ko if: $data.taskAttemptCounterGroup -->
  1686. <!-- ko foreach: $data.taskAttemptCounterGroup -->
  1687. <h3 data-bind="text: counterGroupName"></h3>
  1688. <table class="table table-condensed">
  1689. <thead>
  1690. <tr>
  1691. <th>${ _('Name') }</th>
  1692. <th width="30%">${ _('Value') }</th>
  1693. </tr>
  1694. </thead>
  1695. <tbody data-bind="foreach: counter">
  1696. <tr>
  1697. <td data-bind="text: name"></td>
  1698. <td data-bind="text: value"></td>
  1699. </tr>
  1700. </tbody>
  1701. </table>
  1702. <!-- /ko -->
  1703. <!-- /ko -->
  1704. <!-- /ko -->
  1705. </script>
  1706. <script type="text/html" id="render-metadata${ SUFFIX }">
  1707. <!-- ko hueSpinner: { spin: !$data.property, center: true, size: 'xlarge' } --><!-- /ko -->
  1708. <!-- ko if: $data.property -->
  1709. <form class="form-search">
  1710. <input type="text" data-bind="clearable: $parent.metadataFilter, valueUpdate: 'afterkeydown'" class="input-xlarge search-query" placeholder="${_('Text Filter')}">
  1711. </form>
  1712. %if not is_mini:
  1713. <div id="job-mapreduce-page-metadata-template${ SUFFIX }" style="overflow-y: hidden; height: calc(100vh - 350px);">
  1714. % else:
  1715. <div id="job-mapreduce-page-metadata-template${ SUFFIX }" style="overflow-y: hidden; height: 400px;">
  1716. %endif
  1717. <table id="jobbrowserJobMetadataTable" class="table table-condensed">
  1718. <thead>
  1719. <tr>
  1720. <th>${ _('Name') }</th>
  1721. <th width="50%">${ _('Value') }</th>
  1722. </tr>
  1723. </thead>
  1724. <tbody data-bind="foreachVisible: { data: property, minHeight: 20, container: '#job-mapreduce-page-metadata-template${ SUFFIX }'}">
  1725. <tr>
  1726. <td data-bind="text: name"></td>
  1727. <td>
  1728. <!-- ko template: { name: 'link-or-text${ SUFFIX }', data: { name: name, value: value } } --><!-- /ko -->
  1729. </td>
  1730. </tr>
  1731. </tbody>
  1732. </table>
  1733. </div>
  1734. <!-- /ko -->
  1735. </script>
  1736. <script type="text/html" id="link-or-text${ SUFFIX }">
  1737. <!-- ko if: typeof $data.value === 'string' -->
  1738. <!-- ko if: $data.name.indexOf('logs') > -1 -->
  1739. <a href="javascript:void(0);" data-bind="text: $data.value, attr: { href: $data.value }" target="_blank"></a>
  1740. <!-- /ko -->
  1741. <!-- ko if: $data.name.indexOf('dir') > -1 || $data.name.indexOf('path') > -1 || $data.name.indexOf('output') > -1 || $data.name.indexOf('input') > -1 || $data.value.startsWith('/') || $data.value.startsWith('hdfs://') -->
  1742. <a href="javascript:void(0);" data-bind="hueLink: '/filebrowser/view=' + $root.getHDFSPath($data.value), text: $data.value"></a>
  1743. <a href="javascript: void(0);" data-bind="storageContextPopover: { path: $root.getHDFSPath($data.value), offset: { left: 5 } }"><i class="fa fa-info"></i></a>
  1744. <!-- /ko -->
  1745. <!-- ko ifnot: $data.name.indexOf('logs') > -1 || $data.name.indexOf('dir') > -1 || $data.name.indexOf('path') > -1 || $data.name.indexOf('output') > -1 || $data.name.indexOf('input') > -1 || $data.value.startsWith('/') || $data.value.startsWith('hdfs://') -->
  1746. <span data-bind="text: $data.value"></span>
  1747. <!-- /ko -->
  1748. <!-- /ko -->
  1749. <!-- ko ifnot: typeof $data.value === 'string' -->
  1750. <span data-bind="text: $data.value"></span>
  1751. <!-- /ko -->
  1752. </script>
  1753. <script type="text/javascript">
  1754. (function () {
  1755. var Job = function (vm, job) {
  1756. var self = this;
  1757. self.id = ko.observableDefault(job.id);
  1758. %if not is_mini:
  1759. self.id.subscribe(function () {
  1760. huePubSub.publish('graph.stop.refresh.view');
  1761. });
  1762. %endif
  1763. self.doc_url = ko.observableDefault(job.doc_url);
  1764. self.name = ko.observableDefault(job.name || job.id);
  1765. self.type = ko.observableDefault(job.type);
  1766. self.status = ko.observableDefault(job.status);
  1767. self.apiStatus = ko.observableDefault(job.apiStatus);
  1768. self.progress = ko.observableDefault(job.progress);
  1769. self.isRunning = ko.computed(function() {
  1770. return self.apiStatus() == 'RUNNING' || self.apiStatus() == 'PAUSED' || job.isRunning;
  1771. });
  1772. self.user = ko.observableDefault(job.user);
  1773. self.queue = ko.observableDefault(job.queue);
  1774. self.cluster = ko.observableDefault(job.cluster);
  1775. self.duration = ko.observableDefault(job.duration);
  1776. self.submitted = ko.observableDefault(job.submitted);
  1777. self.canWrite = ko.observableDefault(job.canWrite == true);
  1778. self.logActive = ko.observable('default');
  1779. self.logsByName = ko.observable({});
  1780. self.logs = ko.pureComputed(function() {
  1781. return self.logsByName()[self.logActive()];
  1782. });
  1783. self.properties = ko.mapping.fromJS(job.properties || {});
  1784. self.mainType = ko.observable(vm.interface());
  1785. self.lastEvent = ko.observable(job.lastEvent || '');
  1786. self.coordinatorActions = ko.pureComputed(function() {
  1787. if (self.mainType() == 'schedules' && self.properties['tasks']) {
  1788. var apps = [];
  1789. self.properties['tasks']().forEach(function (instance) {
  1790. var job = new Job(vm, ko.mapping.toJS(instance));
  1791. job.resumeEnabled = function() { return false };
  1792. job.properties = instance;
  1793. apps.push(job);
  1794. });
  1795. var instances = new Jobs(vm);
  1796. instances.apps(apps)
  1797. instances.isCoordinator(true);
  1798. return instances;
  1799. }
  1800. });
  1801. self.textFilter = ko.observable('').extend({ rateLimit: { method: "notifyWhenChangesStop", timeout: 1000 } });
  1802. self.statesValuesFilter = ko.observableArray([
  1803. ko.mapping.fromJS({'value': 'completed', 'name': '${_("Succeeded")}', 'checked': false, 'klass': 'green'}),
  1804. ko.mapping.fromJS({'value': 'running', 'name': '${_("Running")}', 'checked': false, 'klass': 'orange'}),
  1805. ko.mapping.fromJS({'value': 'failed', 'name': '${_("Failed")}', 'checked': false, 'klass': 'red'}),
  1806. ]);
  1807. self.statesFilter = ko.computed(function () {
  1808. var checkedStates = ko.utils.arrayFilter(self.statesValuesFilter(), function (state) {
  1809. return state.checked();
  1810. });
  1811. return ko.utils.arrayMap(checkedStates, function(state){
  1812. return state.value()
  1813. });
  1814. });
  1815. self.typesValuesFilter = ko.observableArray([
  1816. ko.mapping.fromJS({'value': 'map', 'name': '${_("Map")}', 'checked': false, 'klass': 'green'}),
  1817. ko.mapping.fromJS({'value': 'reduce', 'name': '${_("Reduce")}', 'checked': false, 'klass': 'orange'}),
  1818. ]);
  1819. self.typesFilter = ko.computed(function () {
  1820. var checkedTypes = ko.utils.arrayFilter(self.typesValuesFilter(), function (type) {
  1821. return type.checked();
  1822. });
  1823. return ko.utils.arrayMap(checkedTypes, function(type){
  1824. return type.value()
  1825. });
  1826. });
  1827. self.filters = ko.pureComputed(function() {
  1828. return [
  1829. {'text': self.textFilter()},
  1830. {'states': ko.mapping.toJS(self.statesFilter())},
  1831. {'types': ko.mapping.toJS(self.typesFilter())},
  1832. ];
  1833. });
  1834. self.filters.subscribe(function(value) {
  1835. self.fetchProfile('tasks');
  1836. });
  1837. self.metadataFilter = ko.observable('');
  1838. self.metadataFilter.subscribe(function(newValue) {
  1839. $("#jobbrowserJobMetadataTable tbody tr").removeClass("hide");
  1840. $("#jobbrowserJobMetadataTable tbody tr").each(function () {
  1841. if ($(this).text().toLowerCase().indexOf(newValue.toLowerCase()) == -1) {
  1842. $(this).addClass("hide");
  1843. }
  1844. });
  1845. });
  1846. self.propertiesFilter = ko.observable('');
  1847. self.propertiesFilter.subscribe(function(newValue) {
  1848. $("#jobbrowserJobPropertiesTable tbody tr").removeClass("hide");
  1849. $("#jobbrowserJobPropertiesTable tbody tr").each(function () {
  1850. if ($(this).text().toLowerCase().indexOf(newValue.toLowerCase()) == -1) {
  1851. $(this).addClass("hide");
  1852. }
  1853. });
  1854. });
  1855. self.rerunModalContent = ko.observable('');
  1856. self.hasKill = ko.pureComputed(function() {
  1857. return self.type() && (['MAPREDUCE', 'SPARK', 'workflow', 'schedule', 'bundle', 'QUERY'].indexOf(self.type()) != -1 || self.type().indexOf('Altus') != -1);
  1858. });
  1859. self.killEnabled = ko.pureComputed(function() {
  1860. // Impala can kill queries that are finished, but not yet terminated
  1861. return self.hasKill() && self.canWrite() && self.isRunning();
  1862. });
  1863. self.hasResume = ko.pureComputed(function() {
  1864. return ['workflow', 'schedule', 'bundle'].indexOf(self.type()) != -1;
  1865. });
  1866. self.resumeEnabled = ko.pureComputed(function() {
  1867. return self.hasResume() && self.canWrite() && self.apiStatus() == 'PAUSED';
  1868. });
  1869. self.hasRerun = ko.pureComputed(function() {
  1870. return ['workflow', 'schedule-task'].indexOf(self.type()) != -1;
  1871. });
  1872. self.rerunEnabled = ko.pureComputed(function() {
  1873. return self.hasRerun() && self.canWrite() && ! self.isRunning();
  1874. });
  1875. self.hasPause = ko.pureComputed(function() {
  1876. return ['workflow', 'schedule', 'bundle'].indexOf(self.type()) != -1;
  1877. });
  1878. self.pauseEnabled = ko.pureComputed(function() {
  1879. return self.hasPause() && self.canWrite() && self.apiStatus() == 'RUNNING';
  1880. });
  1881. self.hasIgnore = ko.pureComputed(function() {
  1882. return ['schedule-task'].indexOf(self.type()) != -1;
  1883. });
  1884. self.ignoreEnabled = ko.pureComputed(function() {
  1885. return self.hasIgnore() && self.canWrite() && ! self.isRunning();
  1886. });
  1887. self.loadingJob = ko.observable(false);
  1888. var lastFetchJobRequest = null;
  1889. var lastUpdateJobRequest = null;
  1890. self._fetchJob = function (callback) {
  1891. return $.post("/jobbrowser/api/job/" + vm.interface(), {
  1892. app_id: ko.mapping.toJSON(self.id),
  1893. interface: ko.mapping.toJSON(vm.interface)
  1894. }, function (data) {
  1895. if (data.status == 0) {
  1896. if (callback) {
  1897. callback(data);
  1898. };
  1899. } else {
  1900. $(document).trigger("error", data.message);
  1901. }
  1902. });
  1903. };
  1904. self.fetchJob = function () {
  1905. vm.apiHelper.cancelActiveRequest(lastFetchJobRequest);
  1906. vm.apiHelper.cancelActiveRequest(lastUpdateJobRequest);
  1907. self.loadingJob(true);
  1908. var interface = vm.interface();
  1909. if (/application_/.test(self.id()) || /job_/.test(self.id()) || /attempt_/.test(self.id())) {
  1910. interface = 'jobs';
  1911. }
  1912. if (/oozie-\w+-W/.test(self.id())) {
  1913. interface = 'workflows';
  1914. }
  1915. else if (/oozie-\w+-C/.test(self.id())) {
  1916. interface = 'schedules';
  1917. }
  1918. else if (/oozie-\w+-B/.test(self.id())) {
  1919. interface = 'bundles';
  1920. }
  1921. else if (/[a-z0-9]{8}\-[a-z0-9]{4}\-[a-z0-9]{4}\-[a-z0-9]{4}\-[a-z0-9]{12}/.test(self.id())) {
  1922. interface = 'dataeng-jobs';
  1923. }
  1924. else if (/[a-z0-9]{16}:[a-z0-9]{16}/.test(self.id())) {
  1925. interface = 'queries';
  1926. }
  1927. else if (/livy-[0-9]+/.test(self.id())) {
  1928. interface = 'livy-sessions';
  1929. }
  1930. interface = vm.isValidInterface(interface);
  1931. vm.interface(interface);
  1932. lastFetchJobRequest = self._fetchJob(function (data) {
  1933. if (data.status == 0) {
  1934. vm.interface(interface);
  1935. vm.job(new Job(vm, data.app));
  1936. if (window.location.hash !== '#!id=' + vm.job().id()) {
  1937. hueUtils.changeURL('#!id=' + vm.job().id());
  1938. }
  1939. var crumbs = [];
  1940. if (/^appattempt_/.test(vm.job().id())) {
  1941. crumbs.push({'id': vm.job().properties['app_id'], 'name': vm.job().properties['app_id'], 'type': 'app'});
  1942. }
  1943. if (/^attempt_/.test(vm.job().id())) {
  1944. crumbs.push({'id': vm.job().properties['app_id'], 'name': vm.job().properties['app_id'], 'type': 'app'});
  1945. crumbs.push({'id': vm.job().properties['task_id'], 'name': vm.job().properties['task_id'], 'type': 'task'});
  1946. }
  1947. if (/^task_/.test(vm.job().id())) {
  1948. crumbs.push({'id': vm.job().properties['app_id'], 'name': vm.job().properties['app_id'], 'type': 'app'});
  1949. }
  1950. if (/_executor_/.test(vm.job().id())) {
  1951. crumbs.push({'id': vm.job().properties['app_id'], 'name': vm.job().properties['app_id'], 'type': 'app'});
  1952. }
  1953. var oozieWorkflow = vm.job().name().match(/oozie:launcher:T=.+?:W=.+?:A=.+?:ID=(.+?-oozie-\w+-W)$/i);
  1954. if (oozieWorkflow) {
  1955. crumbs.push({'id': oozieWorkflow[1], 'name': oozieWorkflow[1], 'type': 'workflow'});
  1956. }
  1957. if (/-oozie-\w+-W@/.test(vm.job().id())) {
  1958. crumbs.push({'id': vm.job().properties['workflow_id'], 'name': vm.job().properties['workflow_id'], 'type': 'workflow'});
  1959. }
  1960. else if (/-oozie-\w+-W/.test(vm.job().id())) {
  1961. if (vm.job().properties['bundle_id']()) {
  1962. crumbs.push({'id': vm.job().properties['bundle_id'](), 'name': vm.job().properties['bundle_id'](), 'type': 'bundle'});
  1963. }
  1964. if (vm.job().properties['coordinator_id']()) {
  1965. crumbs.push({'id': vm.job().properties['coordinator_id'](), 'name': vm.job().properties['coordinator_id'](), 'type': 'schedule'});
  1966. }
  1967. }
  1968. else if (/-oozie-\w+-C/.test(vm.job().id())) {
  1969. if (vm.job().properties['bundle_id']()) {
  1970. crumbs.push({'id': vm.job().properties['bundle_id'](), 'name': vm.job().properties['bundle_id'](), 'type': 'bundle'});
  1971. }
  1972. }
  1973. if (vm.job().type() == 'SPARK_EXECUTOR') {
  1974. crumbs.push({'id': vm.job().id(), 'name': vm.job().properties['executor_id'](), 'type': vm.job().type()});
  1975. }
  1976. else {
  1977. crumbs.push({'id': vm.job().id(), 'name': vm.job().name(), 'type': vm.job().type()});
  1978. }
  1979. vm.resetBreadcrumbs(crumbs);
  1980. // Show is still bound to old job, setTimeout allows knockout model change event done at begining of this method to sends it's notification
  1981. setTimeout(function () {
  1982. if (vm.job().type() === 'queries' && !$("#queries-page-plan${ SUFFIX }").parent().children().hasClass("active")) {
  1983. $("a[href=\'#queries-page-plan${ SUFFIX }\']").tab("show");
  1984. }
  1985. }, 0);
  1986. %if not is_mini:
  1987. if (vm.job().type() === 'workflow' && !vm.job().workflowGraphLoaded) {
  1988. vm.job().updateWorkflowGraph();
  1989. }
  1990. %else:
  1991. if (vm.job().type() === 'workflow') {
  1992. vm.job().fetchProfile('properties');
  1993. $('a[href="#workflow-page-metadata${ SUFFIX }"]').tab('show');
  1994. }
  1995. %endif
  1996. vm.job().fetchLogs();
  1997. } else {
  1998. $(document).trigger("error", data.message);
  1999. }
  2000. }).always(function () {
  2001. self.loadingJob(false);
  2002. });
  2003. };
  2004. self.updateJob = function () {
  2005. vm.apiHelper.cancelActiveRequest(lastUpdateJobRequest);
  2006. huePubSub.publish('graph.refresh.view');
  2007. if (vm.job() == self && self.apiStatus() == 'RUNNING') {
  2008. lastFetchJobRequest = self._fetchJob(function (data) {
  2009. if (vm.job().type() == 'schedule') {
  2010. vm.job(new Job(vm, data.app)); // Updates everything but redraw the page
  2011. } else {
  2012. vm.job().fetchStatus();
  2013. vm.job().fetchLogs(vm.job().logActive());
  2014. }
  2015. var profile = $("div[data-jobType] .tab-content .active").data("profile")
  2016. if (profile) {
  2017. vm.job().fetchProfile(profile);
  2018. }
  2019. });
  2020. }
  2021. };
  2022. self.fetchLogs = function (name) {
  2023. name = name || 'default';
  2024. $.post("/jobbrowser/api/job/logs?is_embeddable=${ str(is_embeddable).lower() }", {
  2025. app_id: ko.mapping.toJSON(self.id),
  2026. interface: ko.mapping.toJSON(vm.interface),
  2027. type: ko.mapping.toJSON(self.type),
  2028. name: ko.mapping.toJSON(name)
  2029. }, function (data) {
  2030. if (data.status == 0) {
  2031. var result = self.logsByName();
  2032. result[name] = data.logs.logs;
  2033. self.logsByName(result);
  2034. if ($('.jb-panel pre:visible').length > 0){
  2035. $('.jb-panel pre:visible').css('overflow-y', 'auto').height(Math.max(200, $(window).height() - $('.jb-panel pre:visible').offset().top - $('.page-content').scrollTop() - 75));
  2036. }
  2037. } else {
  2038. $(document).trigger("error", data.message);
  2039. }
  2040. });
  2041. };
  2042. self.fetchProfile = function (name, callback) {
  2043. $.post("/jobbrowser/api/job/profile", {
  2044. app_id: ko.mapping.toJSON(self.id),
  2045. interface: ko.mapping.toJSON(vm.interface),
  2046. app_type: ko.mapping.toJSON(self.type),
  2047. app_property: ko.mapping.toJSON(name),
  2048. app_filters: ko.mapping.toJSON(self.filters),
  2049. }, function (data) {
  2050. if (data.status == 0) {
  2051. self.properties[name](data[name]);
  2052. if (callback) {
  2053. callback(data);
  2054. }
  2055. } else {
  2056. $(document).trigger("error", data.message);
  2057. }
  2058. });
  2059. };
  2060. self.fetchStatus = function () {
  2061. $.post("/jobbrowser/api/job", {
  2062. app_id: ko.mapping.toJSON(self.id),
  2063. interface: ko.mapping.toJSON(self.mainType)
  2064. }, function (data) {
  2065. if (data.status == 0) {
  2066. self.status(data.app.status);
  2067. self.apiStatus(data.app.apiStatus);
  2068. self.progress(data.app.progress);
  2069. self.canWrite(data.app.canWrite);
  2070. } else {
  2071. $(document).trigger("error", data.message);
  2072. }
  2073. });
  2074. };
  2075. self.control = function (action) {
  2076. if (action == 'rerun') {
  2077. $.get('/oozie/rerun_oozie_job/' + self.id() + '/?format=json', function(response) {
  2078. $('#rerun-modal${ SUFFIX }').modal('show');
  2079. self.rerunModalContent(response);
  2080. });
  2081. } else {
  2082. vm.jobs._control([self.id()], action, function(data) {
  2083. $(document).trigger("info", data.message);
  2084. self.fetchStatus();
  2085. });
  2086. }
  2087. }
  2088. self.troubleshoot = function (action) {
  2089. $.post('/metadata/api/workload_analytics/get_operation_execution_details', {
  2090. operation_id: ko.mapping.toJSON(self.id())
  2091. }, function(data) {
  2092. console.log(ko.mapping.toJSON(data));
  2093. });
  2094. }
  2095. self.workflowGraphLoaded = false;
  2096. self.lastArrowsPosition = {
  2097. top: 0,
  2098. left: 0
  2099. }
  2100. self.initialArrowsDrawingCount = 0;
  2101. self.initialArrowsDrawing = function() {
  2102. if (self.initialArrowsDrawingCount < 20) {
  2103. self.initialArrowsDrawingCount++;
  2104. huePubSub.publish('graph.draw.arrows');
  2105. window.setTimeout(self.initialArrowsDrawing, 100);
  2106. }
  2107. else if (self.initialArrowsDrawingCount < 30){
  2108. self.initialArrowsDrawingCount++;
  2109. huePubSub.publish('graph.draw.arrows');
  2110. window.setTimeout(self.initialArrowsDrawing, 500);
  2111. }
  2112. else {
  2113. self.initialArrowsDrawingCount = 0;
  2114. }
  2115. }
  2116. self.updateArrowsInterval = -1;
  2117. self.updateArrows = function() {
  2118. if ($('canvas').length > 0 && $('canvas').position().top !== self.lastArrowsPosition.top && $('canvas').position().left !== self.lastArrowsPosition.left) {
  2119. self.lastArrowsPosition = $('canvas').position();
  2120. }
  2121. if ($('#workflow-page-graph${ SUFFIX }').is(':visible')){
  2122. if ($('canvas').length === 0){
  2123. huePubSub.publish('graph.draw.arrows');
  2124. }
  2125. }
  2126. else {
  2127. $('canvas').remove();
  2128. }
  2129. }
  2130. self.updateWorkflowGraph = function() {
  2131. huePubSub.publish('graph.stop.refresh.view');
  2132. $('canvas').remove();
  2133. if (!IS_HUE_4) {
  2134. huePubSub.subscribe('hue4.process.headers', function (opts) {
  2135. opts.callback(opts.response);
  2136. });
  2137. }
  2138. if (vm.job().type() === 'workflow') {
  2139. $('#workflow-page-graph${ SUFFIX }').html('<div class="hue-spinner"><i class="fa fa-spinner fa-spin hue-spinner-center hue-spinner-xlarge"></i></div>');
  2140. $.ajax({
  2141. url: "/oozie/list_oozie_workflow/" + vm.job().id(),
  2142. data: {
  2143. 'graph': true,
  2144. 'element': 'workflow-page-graph${ SUFFIX }',
  2145. 'is_jb2': true
  2146. },
  2147. beforeSend: function (xhr) {
  2148. xhr.setRequestHeader("X-Requested-With", "Hue");
  2149. },
  2150. dataType: "html",
  2151. success: function (response) {
  2152. self.workflowGraphLoaded = true;
  2153. huePubSub.publish('hue4.process.headers', {
  2154. response: response,
  2155. callback: function (r) {
  2156. $('#workflow-page-graph${ SUFFIX }').html(r);
  2157. window.clearInterval(self.updateArrowsInterval);
  2158. self.initialArrowsDrawing();
  2159. self.updateArrowsInterval = window.setInterval(self.updateArrows, 100, 'jobbrowser');
  2160. }
  2161. });
  2162. }
  2163. });
  2164. }
  2165. };
  2166. };
  2167. var Jobs = function (vm) {
  2168. var self = this;
  2169. self.apps = ko.observableArray().extend({ rateLimit: 50 });
  2170. self.runningApps = ko.pureComputed(function() {
  2171. return $.grep(self.apps(), function(app) {
  2172. return app.isRunning();
  2173. });
  2174. });
  2175. self.finishedApps = ko.pureComputed(function() {
  2176. return $.grep(self.apps(), function(app) {
  2177. return !app.isRunning();
  2178. });
  2179. });
  2180. self.totalApps = ko.observable(null);
  2181. self.isCoordinator = ko.observable(false);
  2182. self.loadingJobs = ko.observable(false);
  2183. self.selectedJobs = ko.observableArray();
  2184. self.hasKill = ko.pureComputed(function() {
  2185. return ['jobs', 'workflows', 'schedules', 'bundles', 'queries', 'dataeng-jobs', 'dataeng-clusters'].indexOf(vm.interface()) != -1 && !self.isCoordinator();
  2186. });
  2187. self.killEnabled = ko.pureComputed(function() {
  2188. return self.hasKill() && self.selectedJobs().length > 0 && $.grep(self.selectedJobs(), function(job) {
  2189. return job.killEnabled();
  2190. }).length == self.selectedJobs().length;
  2191. });
  2192. self.hasResume = ko.pureComputed(function() {
  2193. return ['workflows', 'schedules', 'bundles'].indexOf(vm.interface()) != -1 && !self.isCoordinator();
  2194. });
  2195. self.resumeEnabled = ko.pureComputed(function() {
  2196. return self.hasResume() && self.selectedJobs().length > 0 && $.grep(self.selectedJobs(), function(job) {
  2197. return job.resumeEnabled();
  2198. }).length == self.selectedJobs().length;
  2199. });
  2200. self.hasRerun = ko.pureComputed(function() {
  2201. return self.isCoordinator();
  2202. });
  2203. self.rerunEnabled = ko.pureComputed(function() {
  2204. return self.hasRerun() && self.selectedJobs().length == 1 && $.grep(self.selectedJobs(), function(job) {
  2205. return job.rerunEnabled();
  2206. }).length == self.selectedJobs().length;
  2207. });
  2208. self.hasPause = ko.pureComputed(function() {
  2209. return ['workflows', 'schedules', 'bundles'].indexOf(vm.interface()) != -1 && !self.isCoordinator();
  2210. });
  2211. self.pauseEnabled = ko.pureComputed(function() {
  2212. return self.hasPause() && self.selectedJobs().length > 0 && $.grep(self.selectedJobs(), function(job) {
  2213. return job.pauseEnabled();
  2214. }).length == self.selectedJobs().length;
  2215. });
  2216. self.hasIgnore = ko.pureComputed(function() {
  2217. return self.isCoordinator();
  2218. });
  2219. self.ignoreEnabled = ko.pureComputed(function() {
  2220. return self.hasIgnore() && self.selectedJobs().length > 0 && $.grep(self.selectedJobs(), function(job) {
  2221. return job.ignoreEnabled();
  2222. }).length == self.selectedJobs().length;
  2223. });
  2224. self.textFilter = ko.observable('user:${ user.username } ').extend({ rateLimit: { method: "notifyWhenChangesStop", timeout: 1000 } });
  2225. self.statesValuesFilter = ko.observableArray([
  2226. ko.mapping.fromJS({'value': 'completed', 'name': '${_("Succeeded")}', 'checked': false, 'klass': 'green'}),
  2227. ko.mapping.fromJS({'value': 'running', 'name': '${_("Running")}', 'checked': false, 'klass': 'orange'}),
  2228. ko.mapping.fromJS({'value': 'failed', 'name': '${_("Failed")}', 'checked': false, 'klass': 'red'}),
  2229. ]);
  2230. self.statesFilter = ko.computed(function () {
  2231. var checkedStates = ko.utils.arrayFilter(self.statesValuesFilter(), function (state) {
  2232. return state.checked();
  2233. });
  2234. return ko.utils.arrayMap(checkedStates, function(state){
  2235. return state.value()
  2236. });
  2237. });
  2238. self.timeValueFilter = ko.observable(7).extend({ throttle: 500 });
  2239. self.timeUnitFilter = ko.observable('days').extend({ throttle: 500 });
  2240. self.timeUnitFilterUnits = ko.observable([
  2241. {'value': 'days', 'name': '${_("days")}'},
  2242. {'value': 'hours', 'name': '${_("hours")}'},
  2243. {'value': 'minutes', 'name': '${_("minutes")}'},
  2244. ]);
  2245. self.hasPagination = ko.computed(function() {
  2246. return ['workflows', 'schedules', 'bundles'].indexOf(vm.interface()) != -1;
  2247. });
  2248. self.paginationPage = ko.observable(1);
  2249. self.paginationOffset = ko.observable(1); // Starting index
  2250. self.paginationResultPage = ko.observable(100);
  2251. self.pagination = ko.computed(function() {
  2252. return {
  2253. 'page': self.paginationPage(),
  2254. 'offset': self.paginationOffset(),
  2255. 'limit': self.paginationResultPage()
  2256. };
  2257. });
  2258. self.showPreviousPage = ko.computed(function() {
  2259. return self.paginationOffset() > 1;
  2260. });
  2261. self.showNextPage = ko.computed(function() {
  2262. return self.totalApps() != null && (self.paginationOffset() + self.paginationResultPage()) < self.totalApps();
  2263. });
  2264. self.previousPage = function() {
  2265. self.paginationOffset(self.paginationOffset() - self.paginationResultPage());
  2266. };
  2267. self.nextPage = function() {
  2268. self.paginationOffset(self.paginationOffset() + self.paginationResultPage());
  2269. };
  2270. self.searchFilters = ko.pureComputed(function() {
  2271. return [
  2272. {'text': self.textFilter()},
  2273. {'time': {'time_value': self.timeValueFilter(), 'time_unit': self.timeUnitFilter()}},
  2274. {'states': ko.mapping.toJS(self.statesFilter())},
  2275. ];
  2276. });
  2277. self.searchFilters.subscribe(function() {
  2278. self.paginationOffset(1);
  2279. });
  2280. self.paginationFilters = ko.pureComputed(function() {
  2281. return [
  2282. {'pagination': self.pagination()},
  2283. ];
  2284. });
  2285. self.filters = ko.pureComputed(function() {
  2286. return self.searchFilters().concat(self.paginationFilters());
  2287. });
  2288. self.filters.subscribe(function(value) {
  2289. self.fetchJobs();
  2290. });
  2291. self._fetchJobs = function (callback) {
  2292. return $.post("/jobbrowser/api/jobs/" + vm.interface(), {
  2293. interface: ko.mapping.toJSON(vm.interface),
  2294. filters: ko.mapping.toJSON(self.filters),
  2295. }, function (data) {
  2296. if (data.status == 0) {
  2297. if (callback) {
  2298. callback(data);
  2299. };
  2300. } else {
  2301. $(document).trigger("error", data.message);
  2302. }
  2303. });
  2304. };
  2305. var lastFetchJobsRequest = null;
  2306. var lastUpdateJobsRequest = null;
  2307. self.showJobCountBanner = ko.pureComputed(function() {
  2308. return self.apps().length == ${ MAX_JOB_FETCH.get() };
  2309. });
  2310. self.fetchJobs = function () {
  2311. vm.apiHelper.cancelActiveRequest(lastUpdateJobsRequest);
  2312. vm.apiHelper.cancelActiveRequest(lastFetchJobsRequest);
  2313. self.loadingJobs(true);
  2314. vm.job(null);
  2315. lastFetchJobsRequest = self._fetchJobs(function(data) {
  2316. var apps = [];
  2317. if (data && data.apps) {
  2318. data.apps.forEach(function (job) {
  2319. apps.push(new Job(vm, job));
  2320. });
  2321. }
  2322. self.apps(apps);
  2323. self.totalApps(data.total);
  2324. }).always(function () {
  2325. self.loadingJobs(false);
  2326. });
  2327. }
  2328. self.updateJobs = function () {
  2329. vm.apiHelper.cancelActiveRequest(lastUpdateJobsRequest);
  2330. lastFetchJobsRequest = self._fetchJobs(function(data) {
  2331. if (data && data.apps) {
  2332. var i = 0, j = 0;
  2333. var newJobs = [];
  2334. while ((self.apps().length == 0 || i < self.apps().length) && j < data.apps.length) { // Nothing displayed or compare existing
  2335. if (self.apps().length == 0 || self.apps()[i].id() != data.apps[j].id) {
  2336. // New Job
  2337. newJobs.unshift(new Job(vm, data.apps[j]));
  2338. j++;
  2339. } else {
  2340. // Updated jobs
  2341. if (self.apps()[i].status() != data.apps[j].status) {
  2342. self.apps()[i].status(data.apps[j].status);
  2343. self.apps()[i].apiStatus(data.apps[j].apiStatus);
  2344. self.apps()[i].canWrite(data.apps[j].canWrite);
  2345. }
  2346. i++;
  2347. j++;
  2348. }
  2349. }
  2350. if (i < self.apps().length) {
  2351. self.apps.splice(i, self.apps().length - i);
  2352. }
  2353. newJobs.forEach(function (job) {
  2354. self.apps.unshift(job);
  2355. });
  2356. self.totalApps(data.total);
  2357. }
  2358. });
  2359. };
  2360. self.createCluster = function() {
  2361. $.post("/metadata/api/dataeng/create_cluster/", {
  2362. "cluster_name": "cluster_name",
  2363. "cdh_version": "CDH514",
  2364. "public_key": "public_key",
  2365. "instance_type": "m4.xlarge",
  2366. "environment_name": "crn:altus:environments:us-west-1:12a0079b-1591-4ca0-b721-a446bda74e67:environment:analytics/236ebdda-18bd-428a-9d2b-cd6973d42946",
  2367. "workers_group_size": "3",
  2368. "namespace_name": "crn:altus:sdx:us-west-1:12a0079b-1591-4ca0-b721-a446bda74e67:namespace:analytics/7ea35fe5-dbc9-4b17-92b1-97a1ab32e410"
  2369. }, function(data) {
  2370. console.log(ko.mapping.toJSON(data));
  2371. $(document).trigger("info", ko.mapping.toJSON(data));
  2372. self.updateJobs();
  2373. });
  2374. }
  2375. self.control = function (action) {
  2376. if (action == 'rerun') {
  2377. $.get('/oozie/rerun_oozie_coord/' + vm.job().id() + '/?format=json', function(response) {
  2378. $('#rerun-modal${ SUFFIX }').modal('show');
  2379. vm.job().rerunModalContent(response);
  2380. var frag = document.createDocumentFragment();
  2381. vm.job().coordinatorActions().selectedJobs().forEach(function (item) {
  2382. var option = $('<option>', {
  2383. value: item.properties.number(),
  2384. selected: true
  2385. });
  2386. option.appendTo($(frag));
  2387. });
  2388. $('#id_actions').find('option').remove();
  2389. $(frag).appendTo('#id_actions');
  2390. });
  2391. } else if (action == 'ignore') {
  2392. $.post('/oozie/manage_oozie_jobs/' + vm.job().id() + '/ignore', {
  2393. actions: $.map(vm.job().coordinatorActions().selectedJobs(), function(wf) {
  2394. return wf.properties.number();
  2395. }).join(' ')
  2396. }, function(response) {
  2397. vm.job().apiStatus('RUNNING');
  2398. vm.job().updateJob();
  2399. });
  2400. } else {
  2401. self._control(
  2402. $.map(self.selectedJobs(), function(job) {
  2403. return job.id();
  2404. }),
  2405. action,
  2406. function(data) {
  2407. $(document).trigger("info", data.message);
  2408. self.updateJobs();
  2409. }
  2410. )
  2411. }
  2412. }
  2413. self._control = function (app_ids, action, callback) {
  2414. $.post("/jobbrowser/api/job/action/" + vm.interface() + "/" + action, {
  2415. app_ids: ko.mapping.toJSON(app_ids),
  2416. interface: ko.mapping.toJSON(vm.interface),
  2417. operation: ko.mapping.toJSON({action: action})
  2418. }, function (data) {
  2419. if (data.status == 0) {
  2420. if (callback) {
  2421. callback(data);
  2422. }
  2423. } else {
  2424. $(document).trigger("error", data.message);
  2425. }
  2426. }).always(function () {
  2427. });
  2428. };
  2429. };
  2430. var JobBrowserViewModel = function () {
  2431. var self = this;
  2432. self.apiHelper = ApiHelper.getInstance();
  2433. self.assistAvailable = ko.observable(true);
  2434. self.isLeftPanelVisible = ko.observable();
  2435. self.apiHelper.withTotalStorage('assist', 'assist_panel_visible', self.isLeftPanelVisible, true);
  2436. self.appConfig = ko.observable();
  2437. self.clusterType = ko.observable();
  2438. self.isMini = ko.observable(false);
  2439. self.availableComputes = ko.observableArray();
  2440. self.compute = ko.observable();
  2441. ContextCatalog.getComputes({ sourceType: 'jobs' }).done(self.availableComputes);
  2442. self.availableInterfaces = ko.pureComputed(function () {
  2443. var jobsInterfaceCondition = function () {
  2444. return self.appConfig() && self.appConfig()['browser'] && self.appConfig()['browser']['interpreter_names'].indexOf('yarn') != -1 && self.clusterType() != '${ ANALYTIC_DB }' && (!self.compute() || self.compute()['type'].indexOf('altus') == -1);
  2445. }
  2446. var dataEngInterfaceCondition = function () {
  2447. // return self.appConfig() && self.appConfig()['browser'] && self.appConfig()['browser']['interpreter_names'].indexOf('dataeng') != -1;
  2448. return self.compute() && self.compute()['type'].indexOf('altus') >= 0;
  2449. }
  2450. var schedulerInterfaceCondition = function () {
  2451. return '${ user.has_hue_permission(action="access", app="oozie") }' == 'True' && self.clusterType() != '${ ANALYTIC_DB }' && (!self.compute() || self.compute()['type'].indexOf('altus') == -1);
  2452. }
  2453. var livyInterfaceCondition = function () {
  2454. return self.appConfig() && self.appConfig()['editor'] && self.appConfig()['editor']['interpreter_names'].indexOf('pyspark') != -1 && (!self.compute() || self.compute()['type'].indexOf('altus') == -1);
  2455. }
  2456. var queryInterfaceCondition = function () {
  2457. return '${ ENABLE_QUERY_BROWSER.get() }' == 'True' && self.appConfig() && self.appConfig()['editor'] && self.appConfig()['editor']['interpreter_names'].indexOf('impala') != -1 && (!self.compute() || self.compute()['type'].indexOf('altus') == -1);
  2458. }
  2459. var interfaces = [
  2460. {'interface': 'jobs', 'label': '${ _ko('Jobs') }', 'condition': jobsInterfaceCondition},
  2461. {'interface': 'dataeng-jobs', 'label': '${ _ko('Jobs') }', 'condition': dataEngInterfaceCondition},
  2462. {'interface': 'dataeng-clusters', 'label': '${ _ko('Clusters') }', 'condition': dataEngInterfaceCondition},
  2463. {'interface': 'queries', 'label': '${ _ko('Queries') }', 'condition': queryInterfaceCondition},
  2464. {'interface': 'workflows', 'label': '${ _ko('Workflows') }', 'condition': schedulerInterfaceCondition},
  2465. {'interface': 'schedules', 'label': '${ _ko('Schedules') }', 'condition': schedulerInterfaceCondition},
  2466. {'interface': 'bundles', 'label': '${ _ko('Bundles') }', 'condition': schedulerInterfaceCondition},
  2467. {'interface': 'slas', 'label': '${ _ko('SLAs') }', 'condition': schedulerInterfaceCondition},
  2468. {'interface': 'livy-sessions', 'label': '${ _ko('Livy') }', 'condition': livyInterfaceCondition},
  2469. ];
  2470. return interfaces.filter(function (i) {
  2471. return i.condition();
  2472. });
  2473. });
  2474. self.slasLoadedOnce = false;
  2475. self.slasLoading = ko.observable(true);
  2476. self.loadSlaPage = function(){
  2477. if (!self.slasLoadedOnce) {
  2478. $.ajax({
  2479. url: '/oozie/list_oozie_sla/?is_embeddable=true',
  2480. beforeSend: function (xhr) {
  2481. xhr.setRequestHeader('X-Requested-With', 'Hue');
  2482. },
  2483. dataType: 'html',
  2484. success: function (response) {
  2485. self.slasLoading(false);
  2486. $('#slas').html(response);
  2487. }
  2488. });
  2489. }
  2490. }
  2491. self.oozieInfoLoadedOnce = false;
  2492. self.oozieInfoLoading = ko.observable(true);
  2493. self.loadOozieInfoPage = function(){
  2494. if (!self.oozieInfoLoadedOnce) {
  2495. self.oozieInfoLoadedOnce = true;
  2496. $.ajax({
  2497. url: '/oozie/list_oozie_info/?is_embeddable=true',
  2498. beforeSend: function (xhr) {
  2499. xhr.setRequestHeader('X-Requested-With', 'Hue');
  2500. },
  2501. dataType: 'html',
  2502. success: function (response) {
  2503. self.oozieInfoLoading(false);
  2504. $('#oozieInfo').html(response);
  2505. }
  2506. });
  2507. }
  2508. }
  2509. self.interface = ko.observable();
  2510. self.isValidInterface = function(name) {
  2511. var flatAvailableInterfaces = self.availableInterfaces().map(function (i) {
  2512. return i.interface;
  2513. });
  2514. if (flatAvailableInterfaces.indexOf(name) != -1 || name == 'oozie-info') {
  2515. return name;
  2516. } else {
  2517. return flatAvailableInterfaces[0];
  2518. }
  2519. };
  2520. self.selectInterface = function(interface) {
  2521. interface = self.isValidInterface(interface);
  2522. self.interface(interface);
  2523. self.resetBreadcrumbs();
  2524. % if not is_mini:
  2525. huePubSub.publish('graph.stop.refresh.view');
  2526. if (window.location.hash !== '#!' + interface) {
  2527. hueUtils.changeURL('#!' + interface);
  2528. }
  2529. % endif
  2530. self.jobs.selectedJobs([]);
  2531. self.job(null);
  2532. if (interface === 'slas'){
  2533. % if not is_mini:
  2534. self.loadSlaPage();
  2535. % endif
  2536. }
  2537. else if (interface === 'oozie-info') {
  2538. % if not is_mini:
  2539. self.loadOozieInfoPage();
  2540. % endif
  2541. }
  2542. else {
  2543. self.jobs.fetchJobs();
  2544. }
  2545. };
  2546. self.jobs = new Jobs(self);
  2547. self.job = ko.observable();
  2548. var updateJobInterval = -1;
  2549. var updateJobsInterval = -1;
  2550. self.job.subscribe(function(val) {
  2551. window.clearInterval(updateJobInterval);
  2552. window.clearInterval(updateJobsInterval);
  2553. if (self.interface() && self.interface() !== 'slas' && self.interface() !== 'oozie-info'){
  2554. if (val) {
  2555. if (val.apiStatus() == 'RUNNING') {
  2556. updateJobInterval = setInterval(val.updateJob, 5000, 'jobbrowser');
  2557. }
  2558. }
  2559. else {
  2560. updateJobsInterval = setInterval(self.jobs.updateJobs, 20000, 'jobbrowser');
  2561. }
  2562. }
  2563. });
  2564. self.breadcrumbs = ko.observableArray([]);
  2565. self.resetBreadcrumbs = function(extraCrumbs) {
  2566. var crumbs = [{'id': '', 'name': self.interface(), 'type': self.interface()}]
  2567. if (extraCrumbs) {
  2568. crumbs = crumbs.concat(extraCrumbs);
  2569. }
  2570. self.breadcrumbs(crumbs);
  2571. }
  2572. self.resetBreadcrumbs();
  2573. self.getHDFSPath = function (path) {
  2574. if (path.startsWith('hdfs://')) {
  2575. var bits = path.substr(7).split('/');
  2576. bits.shift();
  2577. return '/' + bits.join('/');
  2578. }
  2579. return path;
  2580. }
  2581. self.formatProgress = function (progress) {
  2582. if (typeof progress === 'function') {
  2583. progress = progress();
  2584. }
  2585. if (!isNaN(progress)) {
  2586. return Math.round(progress*100)/100 + '%';
  2587. }
  2588. return progress;
  2589. }
  2590. self.load = function() {
  2591. var h = window.location.hash;
  2592. %if not is_mini:
  2593. huePubSub.publish('graph.stop.refresh.view');
  2594. %endif
  2595. h = h.indexOf('#!') === 0 ? h.substr(2) : '';
  2596. switch (h) {
  2597. case '':
  2598. h = 'jobs';
  2599. case 'slas':
  2600. case 'oozie-info':
  2601. case 'jobs':
  2602. case 'queries':
  2603. case 'workflows':
  2604. case 'schedules':
  2605. case 'bundles':
  2606. case 'dataeng-clusters':
  2607. case 'dataeng-jobs':
  2608. case 'livy-sessions':
  2609. self.selectInterface(h);
  2610. break;
  2611. default:
  2612. if (h.indexOf('id=') === 0 && !self.isMini()){
  2613. new Job(self, {id: h.substr(3)}).fetchJob();
  2614. }
  2615. else {
  2616. self.selectInterface('reset');
  2617. }
  2618. }
  2619. }
  2620. };
  2621. $(document).ready(function () {
  2622. var jobBrowserViewModel = new JobBrowserViewModel();
  2623. function openJob(id) {
  2624. if (jobBrowserViewModel.job() == null) {
  2625. jobBrowserViewModel.job(new Job(jobBrowserViewModel, {}));
  2626. }
  2627. jobBrowserViewModel.job().id(id);
  2628. jobBrowserViewModel.job().fetchJob();
  2629. }
  2630. % if not is_mini:
  2631. ko.applyBindings(jobBrowserViewModel, $('#jobbrowserComponents')[0]);
  2632. huePubSub.subscribe('oozie.action.logs.click', function (widget) {
  2633. $.get(widget.logsURL(), {
  2634. format: 'link'
  2635. },
  2636. function(data) {
  2637. var id = data.job || data.attemptid;
  2638. if (id) {
  2639. openJob(id);
  2640. } else {
  2641. $(document).trigger("error", '${ _("No log available") }');
  2642. }
  2643. }
  2644. );
  2645. }, 'jobbrowser');
  2646. huePubSub.subscribe('oozie.action.click', function (widget) {
  2647. openJob(widget.externalId());
  2648. }, 'jobbrowser');
  2649. huePubSub.subscribe('browser.job.open.link', function (id) {
  2650. openJob(id);
  2651. }, 'jobbrowser');
  2652. % else:
  2653. ko.applyBindings(jobBrowserViewModel, $('#jobbrowserMiniComponents')[0]);
  2654. jobBrowserViewModel.isMini(true);
  2655. % endif
  2656. huePubSub.subscribe('app.gained.focus', function (app) {
  2657. if (app === 'jobbrowser') {
  2658. huePubSub.publish('graph.draw.arrows');
  2659. loadHash();
  2660. }
  2661. }, 'jobbrowser');
  2662. var loadHash = function () {
  2663. if (window.location.pathname.indexOf('jobbrowser') > -1) {
  2664. jobBrowserViewModel.load();
  2665. }
  2666. };
  2667. window.onhashchange = function () {
  2668. loadHash();
  2669. }
  2670. huePubSub.subscribe('cluster.config.set.config', function (clusterConfig) {
  2671. jobBrowserViewModel.appConfig(clusterConfig && clusterConfig['app_config']);
  2672. jobBrowserViewModel.clusterType(clusterConfig && clusterConfig['cluster_type']);
  2673. loadHash();
  2674. });
  2675. huePubSub.publish('cluster.config.get.config');
  2676. huePubSub.subscribe('submit.rerun.popup.return', function (data) {
  2677. $.jHueNotify.info('${_('Rerun submitted.')}');
  2678. $('#rerun-modal${ SUFFIX }').modal('hide');
  2679. jobBrowserViewModel.job().apiStatus('RUNNING');
  2680. jobBrowserViewModel.job().updateJob();
  2681. }, 'jobbrowser');
  2682. % if is_mini:
  2683. huePubSub.subscribe('mini.jb.navigate', function (interface) {
  2684. $('#jobsPanel .nav-pills li').removeClass('active');
  2685. interface = jobBrowserViewModel.isValidInterface(interface);
  2686. $('#jobsPanel .nav-pills li[data-interface="' + interface + '"]').addClass('active');
  2687. jobBrowserViewModel.selectInterface(interface);
  2688. });
  2689. huePubSub.subscribe('mini.jb.open.job', openJob);
  2690. huePubSub.subscribe('mini.jb.expand', function () {
  2691. if (jobBrowserViewModel.job()) {
  2692. huePubSub.publish('open.link', '/jobbrowser/#!id=' + jobBrowserViewModel.job().id());
  2693. }
  2694. else {
  2695. huePubSub.publish('open.link', '/jobbrowser/#!' + jobBrowserViewModel.interface());
  2696. }
  2697. });
  2698. % endif
  2699. $(document).on('shown', '.jb-logs-link', function (e) {
  2700. var dest = $(e.target).attr('href');
  2701. if (dest.indexOf('logs') > -1 && $(dest).find('pre:visible').length > 0){
  2702. $(dest).find('pre').css('overflow-y', 'auto').height(Math.max(200, $(window).height() - $(dest).find('pre').offset().top - $('.page-content').scrollTop() - 75));
  2703. }
  2704. });
  2705. });
  2706. })();
  2707. </script>
  2708. </span>
  2709. % if not is_embeddable:
  2710. ${ commonfooter(request, messages) | n,unicode }
  2711. % endif