| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166 |
- ## Licensed to Cloudera, Inc. under one
- ## or more contributor license agreements. See the NOTICE file
- ## distributed with this work for additional information
- ## regarding copyright ownership. Cloudera, Inc. licenses this file
- ## to you under the Apache License, Version 2.0 (the
- ## "License"); you may not use this file except in compliance
- ## with the License. You may obtain a copy of the License at
- ##
- ## http://www.apache.org/licenses/LICENSE-2.0
- ##
- ## Unless required by applicable law or agreed to in writing, software
- ## distributed under the License is distributed on an "AS IS" BASIS,
- ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ## See the License for the specific language governing permissions and
- ## limitations under the License.
- <%
- from django.utils.translation import ugettext as _
- from desktop import conf
- from desktop.views import commonheader, commonfooter, _ko
- %>
- % if not is_embeddable:
- ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
- <%namespace name="assist" file="/assist.mako" />
- % endif
- <span class="notebook">
- <link rel="stylesheet" href="${ static('desktop/ext/css/basictable.css') }">
- % if not is_embeddable:
- <link rel="stylesheet" href="${ static('notebook/css/notebook.css') }">
- <link rel="stylesheet" href="${ static('notebook/css/notebook-layout.css') }">
- <style type="text/css">
- % if conf.CUSTOM.BANNER_TOP_HTML.get():
- .show-assist {
- top: 110px!important;
- }
- .main-content {
- top: 112px!important;
- }
- % endif
- </style>
- % endif
- <link rel="stylesheet" href="${ static('jobbrowser/css/jobbrowser-embeddable.css') }">
- <script src="${ static('oozie/js/dashboard-utils.js') }" type="text/javascript" charset="utf-8"></script>
- <script src="${ static('desktop/ext/js/jquery/plugins/jquery.basictable.min.js') }"></script>
- <script src="${ static('desktop/ext/js/jquery/plugins/jquery-ui-1.10.4.custom.min.js') }"></script>
- <script src="${ static('desktop/js/ko.charts.js') }"></script>
- <script src="${ static('desktop/ext/js/knockout-sortable.min.js') }"></script>
- <script src="${ static('desktop/js/ko.editable.js') }"></script>
- % if not is_mini:
- <div id="jobbrowserComponents" class="jobbrowser-components">
- % else:
- <div id="jobbrowserMiniComponents" class="jobbrowserComponents">
- % endif
- % if not is_embeddable:
- ${ assist.assistJSModels() }
- ${ assist.assistPanel() }
- <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
- <i class="fa fa-chevron-right"></i>
- </a>
- % endif
- % if not is_mini:
- <div class="navbar hue-title-bar">
- <div class="navbar-inner">
- <div class="container-fluid">
- <div class="nav-collapse">
- <ul class="nav">
- <li class="app-header">
- <a href="/${app_name}">
- <img src="${ static('jobbrowser/art/icon_jobbrowser_48.png') }" class="app-icon" alt="${ _('Job browser icon') }"/>
- ${ _('Job Browser') }
- </a>
- </li>
- <!-- ko foreach: availableInterfaces -->
- <li data-bind="css: {'active': $parent.interface() === interface}, visible: condition()">
- <a class="pointer" data-bind="click: function(){ $parent.selectInterface(interface); }, text: label"></a>
- </li>
- <!-- /ko -->
- </ul>
- % if not hiveserver2_impersonation_enabled:
- <div class="pull-right label label-warning" style="margin-top: 16px">${ _("Hive jobs are running as the 'hive' user") }</div>
- % endif
- </div>
- </div>
- </div>
- </div>
- % endif
- <div class="main-content">
- <div class="vertical-full container-fluid" data-bind="style: { 'padding-left' : $root.isLeftPanelVisible() ? '0' : '20px' }">
- <div class="vertical-full">
- <div class="vertical-full row-fluid panel-container">
- % if not is_embeddable:
- <div class="assist-container left-panel" data-bind="visible: $root.isLeftPanelVisible() && $root.assistAvailable()">
- <a title="${_('Toggle Assist')}" class="pointer hide-assist" data-bind="click: function() { $root.isLeftPanelVisible(false) }">
- <i class="fa fa-chevron-left"></i>
- </a>
- <div class="assist" data-bind="component: {
- name: 'assist-panel',
- params: {
- user: '${user.username}',
- sql: {
- navigationSettings: {
- openItem: false,
- showStats: true
- }
- },
- visibleAssistPanels: ['sql']
- }
- }"></div>
- </div>
- <div class="resizer" data-bind="visible: $root.isLeftPanelVisible() && $root.assistAvailable(), splitDraggable : { appName: 'notebook', leftPanelVisible: $root.isLeftPanelVisible }"><div class="resize-bar"> </div></div>
- % endif
- <div class="content-panel">
- <div class="content-panel-inner">
- <!-- ko if: $root.job() -->
- <div data-bind="template: { name: 'breadcrumbs' }"></div>
- <!-- /ko -->
- <!-- ko if: interface() !== 'slas' && interface() !== 'oozie-info' -->
- <!-- ko if: !$root.job() -->
- <form class="form-inline">
- <input type="text" class="input-large" data-bind="textInput: jobs.textFilter" placeholder="${_('Filter by id, name, user...')}" />
- <!-- ko if: jobs.statesValuesFilter -->
- <span data-bind="foreach: jobs.statesValuesFilter">
- <label class="checkbox">
- <div class="pull-left margin-left-5 status-border status-content" data-bind="css: value, hueCheckbox: checked"></div>
- <div class="inline-block" data-bind="text: name, toggle: checked"></div>
- </label>
- </span>
- <!-- /ko -->
- <!-- ko ifnot: $root.isMini -->
- ${_('in the last')} <input class="input-mini no-margin" type="number" min="1" max="3650" data-bind="value: jobs.timeValueFilter">
- <select class="input-small no-margin" data-bind="value: jobs.timeUnitFilter, options: jobs.timeUnitFilterUnits, optionsText: 'name', optionsValue: 'value'">
- <option value="days">${_('days')}</option>
- <option value="hours">${_('hours')}</option>
- <option value="minutes">${_('minutes')}</option>
- </select>
- <a class="btn" title="${ _('Refresh') }" data-bind="click: jobs.updateJobs">
- <i class="fa fa-refresh"></i>
- </a>
- <div data-bind="template: { name: 'job-actions', 'data': jobs }" class="pull-right"></div>
- <!-- /ko -->
- </form>
- <div class="card card-small">
- <!-- ko hueSpinner: { spin: jobs.loadingJobs(), center: true, size: 'xlarge' } --><!-- /ko -->
- <!-- ko ifnot: jobs.loadingJobs() -->
- <!-- ko if: $root.isMini -->
- <ul class="unstyled status-border-container" id="jobsTable" data-bind="foreach: jobs.apps">
- <li class="status-border pointer" data-bind="css: {'completed': apiStatus() == 'SUCCEEDED', 'running': isRunning(), 'failed': apiStatus() == 'FAILED'}, click: fetchJob">
- <span class="muted pull-left" data-bind="momentFromNow: {data: submitted, interval: 10000, titleFormat: 'LLL'}"></span><span class="muted"> - </span><span class="muted" data-bind="text: status"></span></td>
- <span class="muted pull-right" data-bind="text: duration().toHHMMSS()"></span>
- <div class="clearfix"></div>
- <strong class="pull-left" data-bind="text: type"></strong>
- <div class="inline-block pull-right"><i class="fa fa-user muted"></i> <span data-bind="text: user"></span></div>
- <div class="clearfix"></div>
- <div class="pull-left" data-bind="ellipsis: {data: name(), length: 40 }"></div>
- <div class="pull-right muted" data-bind="text: id"></div>
- <div class="clearfix"></div>
- </li>
- <div class="status-bar status-background" data-bind="css: {'running': isRunning()}, style: {'width': progress() + '%'}"></div>
- </ul>
- <!-- /ko -->
- <!-- ko ifnot: $root.isMini -->
- <table id="jobsTable" class="datatables table table-condensed status-border-container">
- <thead>
- <tr>
- <th width="1%"><div class="select-all hueCheckbox fa" data-bind="hueCheckAll: { allValues: jobs.apps, selectedValues: jobs.selectedJobs }"></div></th>
- <th width="15%">${_('Id')}</th>
- <th width="20%">${_('Name')}</th>
- <th width="3%">${_('Duration')}</th>
- <th width="10%">${_('Started')}</th>
- <th width="7%">${_('Type')}</th>
- <th width="5%">${_('Status')}</th>
- <th width="5%">${_('Progress')}</th>
- <th width="10%">${_('User')}</th>
- </tr>
- </thead>
- <tbody data-bind="foreach: jobs.apps">
- <tr class="status-border pointer" data-bind="css: {'completed': apiStatus() == 'SUCCEEDED', 'running': isRunning(), 'failed': apiStatus() == 'FAILED'}, click: fetchJob">
- <td>
- <div class="hueCheckbox fa" data-bind="click: function() {}, clickBubble: false, multiCheck: '#jobsTable', value: $data, hueChecked: $parent.jobs.selectedJobs"></div>
- </td>
- <td data-bind="text: id"></td>
- <td data-bind="text: name"></td>
- <td data-bind="text: duration().toHHMMSS()"></td>
- <td data-bind="moment: {data: submitted, format: 'LLL'}"></td>
- <td data-bind="text: type"></td>
- <td data-bind="text: status"></td>
- <td data-bind="text: progress"></td>
- <td data-bind="text: user"></td>
- </tr>
- </tbody>
- </table>
- <!-- /ko -->
- <!-- /ko -->
- </div>
- <!-- /ko -->
- <!-- ko if: $root.job() -->
- <!-- ko with: $root.job() -->
- <!-- ko if: mainType() == 'jobs' -->
- <div class="jb-panel" data-bind="template: { name: 'job-page' }"></div>
- <!-- /ko -->
- <!-- ko if: mainType() == 'workflows' -->
- <!-- ko if: type() == 'workflow' -->
- <div class="jb-panel" data-bind="template: { name: 'workflow-page' }"></div>
- <!-- /ko -->
- <!-- ko if: type() == 'workflow-action' -->
- <div class="jb-panel" data-bind="template: { name: 'workflow-action-page' }"></div>
- <!-- /ko -->
- <!-- /ko -->
- <!-- ko if: mainType() == 'schedules' -->
- <div class="jb-panel" data-bind="template: { name: 'schedule-page' }"></div>
- <!-- /ko -->
- <!-- ko if: mainType() == 'bundles' -->
- <div class="jb-panel" data-bind="template: { name: 'bundle-page' }"></div>
- <!-- /ko -->
- <!-- ko if: mainType().startsWith('dataeng-job') -->
- <div data-bind="template: { name: 'dataeng-job-page' }"></div>
- <!-- /ko -->
- <!-- /ko -->
- <!-- /ko -->
- <div data-bind="template: { name: 'pagination', data: $root.jobs }, visible: !$root.job() && !jobs.loadingJobs()"></div>
- <!-- /ko -->
- % if not is_mini:
- <!-- ko if: interface() === 'slas' -->
- <!-- ko hueSpinner: { spin: slasLoading(), center: true, size: 'xlarge' } --><!-- /ko -->
- <!-- /ko -->
- <div id="slas" data-bind="visible: interface() === 'slas'"></div>
- <!-- ko if: interface() === 'oozie-info' -->
- <!-- ko hueSpinner: { spin: oozieInfoLoading(), center: true, size: 'xlarge' } --><!-- /ko -->
- <!-- /ko -->
- <div id="oozieInfo" data-bind="visible: interface() === 'oozie-info'"></div>
- %endif
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- ko if: $root.job() -->
- <div id="rerun-modal" class="modal hide" data-bind="html: $root.job().rerunModalContent"></div>
- <!-- /ko -->
- </div>
- <script type="text/html" id="breadcrumbs-icons">
- <!-- ko switch: type -->
- <!-- ko case: 'workflow' -->
- <img src="${ static('oozie/art/icon_oozie_workflow_48.png') }" class="app-icon" alt="${ _('Oozie workflow icon') }"/>
- <!-- /ko -->
- <!-- ko case: 'workflow-action' -->
- <i class="fa fa-fw fa-code-fork"></i>
- <!-- /ko -->
- <!-- ko case: 'schedule' -->
- <img src="${ static('oozie/art/icon_oozie_coordinator_48.png') }" class="app-icon" alt="${ _('Oozie coordinator icon') }"/>
- <!-- /ko -->
- <!-- ko case: 'bundle' -->
- <img src="${ static('oozie/art/icon_oozie_bundle_48.png') }" class="app-icon" alt="${ _('Oozie bundle icon') }"/>
- <!-- /ko -->
- <!-- /ko -->
- </script>
- <script type="text/html" id="breadcrumbs">
- <h3 class="jb-breadcrumbs">
- <ul class="inline hue-breadcrumbs-bar">
- <!-- ko foreach: breadcrumbs -->
- <li>
- <!-- ko if: $index() > 1 -->
- <span class="divider">></span>
- <!-- /ko -->
- <!-- ko if: $index() != 0 -->
- <!-- ko if: $index() != $parent.breadcrumbs().length - 1 -->
- <a href="javascript:void(0)" data-bind="click: function() { $parent.breadcrumbs.splice($index()); $root.job().id(id); $root.job().fetchJob(); }">
- <span data-bind="template: 'breadcrumbs-icons'"></span>
- <span data-bind="text: name"></span></a>
- <!-- /ko -->
- <!-- ko if: $index() == $parent.breadcrumbs().length - 1 -->
- <span data-bind="template: 'breadcrumbs-icons'"></span>
- <span data-bind="text: name, attr: { title: id }"></span>
- <!-- /ko -->
- <!-- /ko -->
- </li>
- <!-- /ko -->
- <!-- ko if: !$root.isMini() -->
- <!-- ko if: ['workflows', 'schedules', 'bundles', 'slas'].indexOf(interface()) > -1 -->
- <li class="pull-right">
- <a href="javascript:void(0)" data-bind="click: function() { $root.selectInterface('oozie-info') }">${ _('Configuration') }</a>
- </li>
- <!-- /ko -->
- <!-- /ko -->
- </ul>
- </h3>
- </script>
- <script type="text/html" id="pagination">
- <!-- ko ifnot: hasPagination -->
- <div class="inline">
- <span data-bind="text: paginationResultCounts()"></span>
- ${ _('jobs') }
- </div>
- <!-- /ko -->
- <!-- ko if: hasPagination -->
- <div class="inline">
- <div class="inline">
- ${ _('Showing') }
- <span data-bind="text: Math.min((paginationPage() - 1) * paginationResultPage() + 1, paginationResultCounts())"></span>
- ${ _('to')}
- <span data-bind="text: Math.min(paginationPage() * paginationResultPage(), paginationResultCounts())"></span>
- ${ _('of') }
- <span data-bind="text: paginationResultCounts"></span>
- ##${ _('Show')}
- ##<span data-bind="text: paginationResultPage"></span>
- ##${ _('results by page.') }
- </div>
- <ul class="inline">
- <li class="previous-page" data-bind="visible: showPreviousPage">
- <a href="javascript:void(0);" data-bind="click: previousPage" title="${_('Previous page')}"><i class="fa fa-backward"></i></a>
- </li>
- <li class="next-page" data-bind="visible: showNextPage">
- <a href="javascript:void(0);" data-bind="click: nextPage" title="${_('Next page')}"><i class="fa fa-forward"></i></a>
- </li>
- </ul>
- </div>
- <!-- /ko -->
- </script>
- <script type="text/html" id="job-page">
- <!-- ko if: type() == 'MAPREDUCE' -->
- <div data-bind="template: { name: 'job-mapreduce-page', data: $root.job() }"></div>
- <!-- /ko -->
- <!-- ko if: type() == 'MAP' || type() == 'REDUCE' -->
- <div data-bind="template: { name: 'job-mapreduce-task-page', data: $root.job() }"></div>
- <!-- /ko -->
- <!-- ko if: type() == 'MAP_ATTEMPT' || type() == 'REDUCE_ATTEMPT' -->
- <div data-bind="template: { name: 'job-mapreduce-task-attempt-page', data: $root.job() }"></div>
- <!-- /ko -->
- <!-- ko if: type() == 'YARN' -->
- <div data-bind="template: { name: 'job-yarn-page', data: $root.job() }"></div>
- <!-- /ko -->
- <!-- ko if: type() == 'IMPALA' -->
- <div data-bind="template: { name: 'job-impala-page', data: $root.job() }"></div>
- <!-- /ko -->
- <!-- ko if: type() == 'SPARK' -->
- <div data-bind="template: { name: 'job-spark-page', data: $root.job() }"></div>
- <!-- /ko -->
- </script>
- <script type="text/html" id="job-yarn-page">
- <div class="row-fluid">
- <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
- <div class="sidebar-nav">
- <ul class="nav nav-list">
- <li class="nav-header">${ _('Id') }</li>
- <li><span data-bind="text: id"></span></li>
- <li class="nav-header">${ _('Name') }</li>
- <li><span data-bind="text: name"></span></li>
- <li class="nav-header">${ _('Type') }</li>
- <li><span data-bind="text: type"></span></li>
- <li class="nav-header">${ _('Status') }</li>
- <li><span data-bind="text: status"></span></li>
- <li class="nav-header">${ _('User') }</li>
- <li><span data-bind="text: user"></span></li>
- <li class="nav-header">${ _('Progress') }</li>
- <li><span data-bind="text: progress"></span></li>
- <li>
- <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': progress() < 100, 'progress-success': progress() === 100}">
- <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
- </div>
- </li>
- <li class="nav-header">${ _('Duration') }</li>
- <li><span data-bind="text: duration"></span></li>
- <li class="nav-header">${ _('Submitted') }</li>
- <li><span data-bind="text: submitted"></span></li>
- </ul>
- </div>
- </div>
- <div data-bind="css:{'span10': !$root.isMini(), 'span12': $root.isMini() }">
- <div class="pull-right" data-bind="template: { name: 'job-actions' }"></div>
- </div>
- </div>
- </script>
- <script type="text/html" id="job-mapreduce-page">
- <div class="row-fluid">
- <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
- <div class="sidebar-nav">
- <ul class="nav nav-list">
- <li class="nav-header">${ _('Id') }</li>
- <li><span data-bind="text: id"></span></li>
- <li data-bind="visible: id() != name()" class="nav-header">${ _('Name') }</li>
- <li data-bind="visible: id() != name()"><span data-bind="text: name"></span></li>
- <li class="nav-header">${ _('Type') }</li>
- <li><span data-bind="text: type"></span></li>
- <li class="nav-header">${ _('Status') }</li>
- <li><span data-bind="text: status"></span></li>
- <li class="nav-header">${ _('User') }</li>
- <li><span data-bind="text: user"></span></li>
- <li class="nav-header">${ _('Progress') }</li>
- <li><span data-bind="text: progress"></span></li>
- <li>
- <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': progress() < 100, 'progress-success': progress() === 100}">
- <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
- </div>
- </li>
- <!-- ko with: properties -->
- <li class="nav-header">${ _('Map') }</li>
- <li><span data-bind="text: maps_percent_complete"></span> <span data-bind="text: finishedMaps"></span> /<span data-bind="text: desiredMaps"></span></li>
- <li class="nav-header">${ _('Reduce') }</li>
- <li><span data-bind="text: reduces_percent_complete"></span> <span data-bind="text: finishedReduces"></span> / <span data-bind="text: desiredReduces"></span></li>
- <li class="nav-header">${ _('Duration') }</li>
- <li><span data-bind="text: $parent.duration"></span></li>
- <!-- /ko -->
- <li class="nav-header">${ _('Duration') }</li>
- <li><span data-bind="text: duration"></span></li>
- <li class="nav-header">${ _('Submitted') }</li>
- <li><span data-bind="text: submitted"></span></li>
- </ul>
- </div>
- </div>
- <div data-bind="css:{'span10': !$root.isMini(), 'span12': $root.isMini() }">
- <ul class="nav nav-pills margin-top-20">
- <li class="active"><a class="jb-logs-link" href="#job-mapreduce-page-logs" data-toggle="tab">${ _('Logs') }</a></li>
- <li><a href="#job-mapreduce-page-tasks" data-bind="click: function(){ fetchProfile('tasks'); $('a[href=\'#job-mapreduce-page-tasks\']').tab('show'); }">${ _('Tasks') }</a></li>
- <li><a href="#job-mapreduce-page-metadata" data-bind="click: function(){ fetchProfile('metadata'); $('a[href=\'#job-mapreduce-page-metadata\']').tab('show'); }">${ _('Metadata') }</a></li>
- <li><a href="#job-mapreduce-page-counters" data-bind="click: function(){ fetchProfile('counters'); $('a[href=\'#job-mapreduce-page-counters\']').tab('show'); }">${ _('Counters') }</a></li>
- <li class="pull-right" data-bind="template: { name: 'job-actions' }"></li>
- </ul>
- <div class="clearfix"></div>
- <div class="tab-content">
- <div class="tab-pane active" id="job-mapreduce-page-logs">
- % for name in ['stdout', 'stderr', 'syslog']:
- <a href="javascript:void(0)" data-bind="click: function() { fetchLogs('${ name }'); }, text: '${ name }'"></a>
- % endfor
- <br>
- <pre data-bind="html: logs, logScroller: logs"></pre>
- </div>
- <div class="tab-pane" id="job-mapreduce-page-tasks">
- <form class="form-inline">
- <input data-bind="textFilter: textFilter, clearable: {value: textFilter}" type="text" class="input-xlarge search-query" placeholder="${_('Filter by name')}">
- <span data-bind="foreach: statesValuesFilter">
- <label class="checkbox">
- <div class="pull-left margin-left-5 status-border status-content" data-bind="css: value, hueCheckbox: checked"></div>
- <div class="inline-block" data-bind="text: name, toggle: checked"></div>
- </label>
- </span>
- <span data-bind="foreach: typesValuesFilter" class="margin-left-30">
- <label class="checkbox">
- <div class="pull-left margin-left-5" data-bind="css: value, hueCheckbox: checked"></div>
- <div class="inline-block" data-bind="text: name, toggle: checked"></div>
- </label>
- </span>
- </form>
- <table class="table table-condensed">
- <thead>
- <tr>
- <th>${_('Type')}</th>
- <th>${_('Id')}</th>
- <th>${_('elapsedTime')}</th>
- <th>${_('progress')}</th>
- <th>${_('state')}</th>
- <th>${_('startTime')}</th>
- <th>${_('successfulAttempt')}</th>
- <th>${_('finishTime')}</th>
- </tr>
- </thead>
- <tbody data-bind="foreach: properties['tasks']()['task_list']">
- <tr data-bind="click: function() { $root.job().id(id); $root.job().fetchJob(); }" class="pointer">
- <td data-bind="text: type"></td>
- <td data-bind="text: id"></td>
- <td data-bind="text: elapsedTime"></td>
- <td data-bind="text: progress"></td>
- <td data-bind="text: state"></td>
- <td data-bind="text: startTime"></td>
- <td data-bind="text: successfulAttempt"></td>
- <td data-bind="text: finishTime"></td>
- </tr>
- </tbody>
- </table>
- </div>
- <div class="tab-pane" id="job-mapreduce-page-metadata">
- <pre data-bind="text: ko.toJSON(properties['metadata'], null, 2)"></pre>
- </div>
- <div class="tab-pane" id="job-mapreduce-page-counters">
- <pre data-bind="text: ko.toJSON(properties['counters'], null, 2)"></pre>
- </div>
- </div>
- </div>
- </div>
- </script>
- <script type="text/html" id="job-mapreduce-task-page">
- <div class="row-fluid">
- <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
- <div class="sidebar-nav">
- <ul class="nav nav-list">
- <li class="nav-header">${ _('Id') }</li>
- <li><span data-bind="text: id, attr: { 'title': id }"></span></li>
- <li class="nav-header">${ _('Type') }</li>
- <li><span data-bind="text: type"></span></li>
- <li class="nav-header">${ _('Progress') }</li>
- <li><span data-bind="text: progress"></span></li>
- <li>
- <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': progress() < 100, 'progress-success': progress() === 100}">
- <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
- </div>
- </li>
- <!-- ko with: properties -->
- <li class="nav-header">${ _('State') }</li>
- <li><span data-bind="text: state"></span></li>
- <li class="nav-header">${ _('Start time') }</li>
- <li><span data-bind="text: startTime"></span></li>
- <li class="nav-header">${ _('Successful attempt') }</li>
- <li><span data-bind="text: successfulAttempt"></span></li>
- <li class="nav-header">${ _('Finish time') }</li>
- <li><span data-bind="text: finishTime"></span></li>
- <li class="nav-header">${ _('Elapsed time') }</li>
- <li><span data-bind="text: elapsedTime"></span></li>
- <!-- /ko -->
- </ul>
- </div>
- </div>
- <div data-bind="css:{'span10': !$root.isMini(), 'span12': $root.isMini() }">
- <ul class="nav nav-pills margin-top-20">
- <li class="active"><a class="jb-logs-link" href="#job-mapreduce-task-page-logs" data-toggle="tab">${ _('Logs') }</a></li>
- <li><a href="#job-mapreduce-task-page-attempts" data-bind="click: function(){ fetchProfile('attempts'); $('a[href=\'#job-mapreduce-task-page-attempts\']').tab('show'); }">${ _('Attempts') }</a></li>
- <li><a href="#job-mapreduce-task-page-counters" data-bind="click: function(){ fetchProfile('counters'); $('a[href=\'#job-mapreduce-task-page-counters\']').tab('show'); }">${ _('Counters') }</a></li>
- </ul>
- <div class="tab-content">
- <div class="tab-pane active" id="job-mapreduce-task-page-logs">
- % for name in ['stdout', 'stderr', 'syslog']:
- <a href="javascript:void(0)" data-bind="click: function() { fetchLogs('${ name }'); }, text: '${ name }'"></a>
- % endfor
- <br>
- <pre data-bind="html: logs, logScroller: logs"></pre>
- </div>
- <div class="tab-pane" id="job-mapreduce-task-page-attempts">
- <table class="table table-condensed">
- <thead>
- <tr>
- <th width="1%"><div class="select-all hueCheckbox fa"></div></th>
- <th>${_('assignedContainerId')}</th>
- <th>${_('progress')}</th>
- <th>${_('elapsedTime')}</th>
- <th>${_('state')}</th>
- <th>${_('rack')}</th>
- <th>${_('nodeHttpAddress')}</th>
- <th>${_('type')}</th>
- <th>${_('startTime')}</th>
- <th>${_('id')}</th>
- <th>${_('finishTime')}</th>
- </tr>
- </thead>
- <tbody data-bind="foreach: properties['attempts']()['task_list']">
- <tr data-bind="click: function() { $root.job().id(id); $root.job().fetchJob(); }">
- <td><div class="hueCheckbox fa"></div></td>
- <td data-bind="text: assignedContainerId"></td>
- <td data-bind="text: progress"></td>
- <td data-bind="text: elapsedTime"></td>
- <td data-bind="text: state"></td>
- <td data-bind="text: rack"></td>
- <td data-bind="text: nodeHttpAddress"></td>
- <td data-bind="text: type"></td>
- <td data-bind="text: startTime"></td>
- <td data-bind="text: id"></td>
- <td data-bind="text: finishTime"></td>
- </tr>
- </tbody>
- </table>
- </div>
- <div class="tab-pane" id="job-mapreduce-task-page-counters">
- <pre data-bind="text: ko.toJSON(properties['counters'], null, 2)"></pre>
- </div>
- </div>
- </div>
- </div>
- </script>
- <script type="text/html" id="job-mapreduce-task-attempt-page">
- <div class="row-fluid">
- <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
- <div class="sidebar-nav">
- <ul class="nav nav-list">
- <li class="nav-header">${ _('Id') }</li>
- <li><span data-bind="text: id, attr: { 'title': id }"></span></li>
- <li class="nav-header">${ _('Type') }</li>
- <li><span data-bind="text: type"></span></li>
- <li class="nav-header">${ _('Progress') }</li>
- <li><span data-bind="text: progress"></span></li>
- <li>
- <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': progress() < 100, 'progress-success': progress() === 100}">
- <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
- </div>
- </li>
- <!-- ko with: properties -->
- <li class="nav-header">${ _('State') }</li>
- <li><span data-bind="text: state"></span></li>
- <li class="nav-header">${ _('Assigned Container ID') }</li>
- <li><span data-bind="text: assignedContainerId"></span></li>
- <li class="nav-header">${ _('Rack') }</li>
- <li><span data-bind="text: rack"></span></li>
- <li class="nav-header">${ _('Node HTTP address') }</li>
- <li><span data-bind="text: nodeHttpAddress"></span></li>
- <li class="nav-header">${ _('Start time') }</li>
- <li><span data-bind="text: startTime"></span></li>
- <li class="nav-header">${ _('Finish time') }</li>
- <li><span data-bind="text: finishTime"></span></li>
- <li class="nav-header">${ _('Elapsed time') }</li>
- <li><span data-bind="text: elapsedTime"></span></li>
- <!-- /ko -->
- </ul>
- </div>
- </div>
- <div data-bind="css:{'span10': !$root.isMini(), 'span12': $root.isMini() }">
- <ul class="nav nav-pills margin-top-20">
- <li class="active"><a class="jb-logs-link" href="#job-mapreduce-task-attempt-page-logs" data-toggle="tab">${ _('Logs') }</a></li>
- <li><a href="#job-mapreduce-task-attempt-page-counters" data-bind="click: function(){ fetchProfile('counters'); $('a[href=\'#job-mapreduce-task-attempt-page-counters\']').tab('show'); }">${ _('Counters') }</a></li>
- </ul>
- <div class="tab-content">
- <div class="tab-pane active" id="job-mapreduce-task-attempt-page-logs">
- % for name in ['stdout', 'stderr', 'syslog']:
- <a href="javascript:void(0)" data-bind="click: function() { fetchLogs('${ name }'); }, text: '${ name }'"></a>
- % endfor
- <br>
- <pre data-bind="html: logs, logScroller: logs"></pre>
- </div>
- <div class="tab-pane" id="job-mapreduce-task-attempt-page-counters">
- <pre data-bind="text: ko.toJSON(properties['counters'], null, 2)"></pre>
- </div>
- </div>
- </div>
- </div>
- </script>
- <script type="text/html" id="job-impala-page">
- <div class="row-fluid">
- <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
- <div class="sidebar-nav">
- <ul class="nav nav-list">
- <li class="nav-header">${ _('Id') }</li>
- <li><span data-bind="text: id, attr: { 'title': id }"></span></li>
- <li class="nav-header">${ _('Name') }</li>
- <li><span data-bind="text: name"></span></li>
- <li class="nav-header">${ _('Type') }</li>
- <li><span data-bind="text: type"></span></li>
- <li class="nav-header">${ _('Status') }</li>
- <li><span data-bind="text: status"></span></li>
- <li class="nav-header">${ _('User') }</li>
- <li><span data-bind="text: user"></span></li>
- <li class="nav-header">${ _('Progress') }</li>
- <li><span data-bind="text: progress"></span></li>
- <li>
- <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': progress() < 100, 'progress-success': progress() === 100}">
- <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
- </div>
- </li>
- <li class="nav-header">${ _('Duration') }</li>
- <li><span data-bind="text: duration"></span></li>
- <li class="nav-header">${ _('Submitted') }</li>
- <li><span data-bind="text: submitted"></span></li>
- </ul>
- </div>
- </div>
- <div data-bind="css:{'span10': !$root.isMini(), 'span12': $root.isMini() }">
- <div class="pull-right" data-bind="template: { name: 'job-actions' }"></div>
- </div>
- </div>
- </script>
- <script type="text/html" id="job-spark-page">
- <div class="row-fluid">
- <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
- <div class="sidebar-nav">
- <ul class="nav nav-list">
- <li class="nav-header">${ _('Id') }</li>
- <li><span data-bind="text: id, attr: { 'title': id }"></span></li>
- <li class="nav-header">${ _('Name') }</li>
- <li><span data-bind="text: name"></span></li>
- <li class="nav-header">${ _('Type') }</li>
- <li><span data-bind="text: type"></span></li>
- <li class="nav-header">${ _('Status') }</li>
- <li><span data-bind="text: status"></span></li>
- <li class="nav-header">${ _('User') }</li>
- <li><span data-bind="text: user"></span></li>
- <li class="nav-header">${ _('Progress') }</li>
- <li><span data-bind="text: progress"></span></li>
- <li>
- <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': progress() < 100, 'progress-success': progress() === 100}">
- <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
- </div>
- </li>
- <li class="nav-header">${ _('Duration') }</li>
- <li><span data-bind="text: duration"></span></li>
- <li class="nav-header">${ _('Submitted') }</li>
- <li><span data-bind="text: submitted"></span></li>
- </ul>
- </div>
- </div>
- <div data-bind="css:{'span10': !$root.isMini(), 'span12': $root.isMini() }">
- <div class="pull-right" data-bind="template: { name: 'job-actions' }"></div>
- </div>
- </div>
- </script>
- <script type="text/html" id="dataeng-job-page">
- <!-- ko if: type() == 'dataeng-job-HIVE' -->
- <div data-bind="template: { name: 'dataeng-job-hive-page', data: $root.job() }"></div>
- <!-- /ko -->
- </script>
- <script type="text/html" id="dataeng-job-hive-page">
- ${ _('Id') } <span data-bind="text: id"></span>
- ${ _('Name') } <span data-bind="text: name"></span>
- ${ _('Type') } <span data-bind="text: type"></span>
- ${ _('Status') } <span data-bind="text: status"></span>
- ${ _('User') } <span data-bind="text: user"></span>
- ${ _('Progress') } <span data-bind="text: progress"></span>
- ${ _('Duration') } <span data-bind="text: duration"></span>
- ${ _('Submitted') } <span data-bind="text: submitted"></span>
- <div data-bind="template: { name: 'render-properties', data: properties['properties'] }"></div>
- </script>
- <script type="text/html" id="job-actions">
- <div class="btn-group">
- <!-- ko if: hasResume -->
- <button class="btn" title="${ _('Resume selected') }" data-bind="click: function() { control('resume'); }, enable: resumeEnabled">
- <i class="fa fa-play"></i> <!-- ko ifnot: $root.isMini -->${ _('Resume') }<!-- /ko -->
- </button>
- <!-- /ko -->
- <!-- ko if: hasPause -->
- <button class="btn" title="${ _('Suspend selected') }" data-bind="click: function() { control('suspend'); }, enable: pauseEnabled">
- <i class="fa fa-pause"></i> <!-- ko ifnot: $root.isMini -->${ _('Suspend') }<!-- /ko -->
- </button>
- <!-- /ko -->
- <!-- ko if: hasRerun -->
- <button class="btn" title="${ _('Rerun selected') }" data-bind="click: function() { control('rerun'); }, enable: rerunEnabled">
- <i class="fa fa-repeat"></i> <!-- ko ifnot: $root.isMini -->${ _('Rerun') }<!-- /ko -->
- </button>
- <!-- /ko -->
- <!-- ko if: hasKill -->
- <button class="btn btn-danger" title="${_('Stop selected')}" data-bind="click: function() { control('kill'); }, enable: killEnabled">
- ## TODO confirmation
- <i class="fa fa-times"></i> <!-- ko ifnot: $root.isMini -->${_('Kill')}<!-- /ko -->
- </button>
- <!-- /ko -->
- <!-- ko if: hasIgnore -->
- <button class="btn btn-danger" title="${_('Ignore selected')}" data-bind="click: function() { control('ignore'); }, enable: ignoreEnabled">
- ## TODO confirmation
- <i class="fa fa-eraser"></i> <!-- ko ifnot: $root.isMini -->${_('Ignore')}<!-- /ko -->
- </button>
- <!-- /ko -->
- </div>
- </script>
- <script type="text/html" id="workflow-page">
- <div class="row-fluid">
- <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
- <div class="sidebar-nav">
- <ul class="nav nav-list">
- <li class="nav-header">${ _('Id') }</li>
- <li><span data-bind="text: id, attr: { 'title': id }"></span></li>
- <!-- ko if: doc_url -->
- <li class="nav-header">${ _('Document') }</li>
- <li>
- <a data-bind="hueLink: doc_url" href="javascript: void(0);" title="${ _('Open in editor') }">
- <span data-bind="text: name"></span>
- </a>
- </li>
- <!-- /ko -->
- <!-- ko ifnot: doc_url -->
- <li class="nav-header">${ _('Name') }</li>
- <li><span data-bind="text: name"></span></li>
- <!-- /ko -->
- <li class="nav-header">${ _('Status') }</li>
- <li><span data-bind="text: status"></span></li>
- <li class="nav-header">${ _('User') }</li>
- <li><span data-bind="text: user"></span></li>
- <li class="nav-header">${ _('Progress') }</li>
- <li><span data-bind="text: progress"></span></li>
- <li>
- <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': isRunning(), 'progress-success': apiStatus() === 'SUCCEEDED', 'progress-danger': apiStatus() === 'FAILED'}">
- <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
- </div>
- </li>
- <li class="nav-header">${ _('Duration') }</li>
- <li><span data-bind="text: duration"></span></li>
- <li class="nav-header">${ _('Submitted') }</li>
- <li><span data-bind="text: submitted"></span></li>
- <li class="nav-header">${ _('Variables') }</li>
- <li>
- <ul class="nav nav-list" data-bind="foreach: properties['parameters']">
- <li>
- <!-- ko if: link -->
- <a data-bind="hueLink: link" href="javascript: void(0);">
- <span data-bind="text: name, attr: { title: value }"></span>
- </a>
- <!-- /ko -->
- <!-- ko ifnot: link -->
- <span data-bind="text: name, attr: { title: value }"></span>
- <!-- /ko -->
- </li>
- </ul>
- </li>
- </ul>
- </div>
- </div>
- <div data-bind="css:{'span10': !$root.isMini(), 'span12': $root.isMini() }">
- <ul class="nav nav-pills margin-top-20">
- <li class="active"><a href="#workflow-page-graph" data-toggle="tab">${ _('Graph') }</a></li>
- <li><a href="#workflow-page-metadata" data-bind="click: function(){ fetchProfile('properties'); $('a[href=\'#workflow-page-metadata\']').tab('show'); }">${ _('Properties') }</a></li>
- <li><a class="jb-logs-link" href="#workflow-page-logs" data-toggle="tab">${ _('Logs') }</a></li>
- <li><a href="#workflow-page-tasks" data-toggle="tab">${ _('Tasks') }</a></li>
- <li><a href="#workflow-page-xml" data-bind="click: function(){ fetchProfile('xml'); $('a[href=\'#workflow-page-xml\']').tab('show'); }">${ _('XML') }</a></li>
- <li class="pull-right" data-bind="template: { name: 'job-actions' }"></li>
- </ul>
- <div class="clearfix"></div>
- <div class="tab-content">
- <div class="tab-pane active dashboard-container" id="workflow-page-graph">
- </div>
- <div class="tab-pane" id="workflow-page-logs">
- <pre data-bind="html: logs, logScroller: logs"></pre>
- </div>
- <div class="tab-pane" id="workflow-page-tasks">
- <table id="actionsTable" class="datatables table table-condensed">
- <thead>
- <tr>
- <th>${_('Log')}</th>
- <th>${_('Status')}</th>
- <th>${_('Error message')}</th>
- <th>${_('Error code')}</th>
- <th>${_('External id')}</th>
- <th>${_('Id')}</th>
- <th>${_('Start time')}</th>
- <th>${_('End time')}</th>
- </tr>
- </thead>
- <tbody data-bind="foreach: properties['actions']">
- <tr data-bind="click: function() { $root.job().id(id); $root.job().fetchJob(); }" class="pointer">
- <td>
- <a data-bind="hueLink: '/jobbrowser/jobs/' + externalId(), clickBubble: false">
- <i class="fa fa-tasks"></i>
- </a>
- </td>
- <td data-bind="text: status"></td>
- <td data-bind="text: errorMessage"></td>
- <td data-bind="text: errorCode"></td>
- <td data-bind="text: externalId"></td>
- <td data-bind="text: id"></td>
- <td data-bind="text: startTime"></td>
- <td data-bind="text: endTime"></td>
- </tr>
- </tbody>
- </table>
- </div>
- <div class="tab-pane" id="workflow-page-metadata">
- <div data-bind="template: { name: 'render-properties', data: properties['properties'] }"></div>
- </div>
- <div class="tab-pane" id="workflow-page-xml">
- <div data-bind="readonlyXML: properties['xml'], path: 'xml'"></div>
- </div>
- </div>
- </div>
- </div>
- </script>
- <script type="text/html" id="workflow-action-page">
- <div class="row-fluid">
- <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
- <div class="sidebar-nav">
- <ul class="nav nav-list">
- <li class="nav-header">${ _('Id') }</li>
- <li><span data-bind="text: id, attr: { 'title': id }"></span></li>
- <li class="nav-header">${ _('Name') }</li>
- <li><span data-bind="text: name"></span></li>
- <li class="nav-header">${ _('Type') }</li>
- <li><span data-bind="text: type"></span></li>
- <li class="nav-header">${ _('Job') }</li>
- <li>
- <a data-bind="hueLink: '/jobbrowser/jobs/' + properties['externalId']()" href="javascript: void(0);">
- <span data-bind="text: properties['externalId']"></span>
- </a>
- </li>
- <li class="nav-header">${ _('Status') }</li>
- <li><span data-bind="text: status"></span></li>
- </ul>
- </div>
- </div>
- <div data-bind="css:{'span10': !$root.isMini(), 'span12': $root.isMini() }">
- <ul class="nav nav-pills margin-top-20">
- <li class="active"><a href="#workflow-action-page-metadata" data-toggle="tab">${ _('Properties') }</a></li>
- <li><a href="#workflow-action-page-tasks" data-toggle="tab">${ _('Child jobs') }</a></li>
- <li><a href="#workflow-action-page-xml" data-toggle="tab">${ _('XML') }</a></li>
- </ul>
- <div class="tab-content">
- <div class="tab-pane" id="workflow-action-page-metadata">
- <table class="datatables table table-condensed">
- <thead>
- <tr>
- <th>${_('Name')}</th>
- <th>${_('Value')}</th>
- </tr>
- </thead>
- <tbody data-bind="foreach: properties['properties']">
- <tr>
- <td data-bind="text: name"></td>
- <td data-bind="text: value"></td>
- </tr>
- </tbody>
- </table>
- </div>
- <div class="tab-pane" id="workflow-action-page-tasks">
- <table class="table table-condensed datatables">
- <thead>
- <tr>
- <th>${ _('Ids') }</th>
- </tr>
- </thead>
- <tbody data-bind="foreach: properties['externalChildIDs']">
- <tr>
- <td>
- <a data-bind="hueLink: '/jobbrowser/jobs/' + $data, text: $data" href="javascript: void(0);">
- </a>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- <div class="tab-pane" id="workflow-action-page-xml">
- <pre data-bind="text: ko.toJSON(properties['conf'], null, 2)"></pre>
- ## <div data-bind="readonlyXML: properties['conf'](), path: 'xml'"></div>
- </div>
- </div>
- </div>
- </div>
- </script>
- <script type="text/html" id="schedule-page">
- <div class="row-fluid">
- <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
- <div class="sidebar-nav">
- <ul class="nav nav-list">
- <li class="nav-header">${ _('Id') }</li>
- <li><span data-bind="text: id, attr: { 'title': id }"></span></li>
- <li class="nav-header">${ _('Name') }</li>
- <li><span data-bind="text: name"></span></li>
- <li class="nav-header">${ _('Type') }</li>
- <li><span data-bind="text: type"></span></li>
- <li class="nav-header">${ _('Status') }</li>
- <li><span data-bind="text: status"></span></li>
- <li class="nav-header">${ _('User') }</li>
- <li><span data-bind="text: user"></span></li>
- <li class="nav-header">${ _('Progress') }</li>
- <li><span data-bind="text: progress"></span></li>
- <li>
- <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': progress() < 100, 'progress-success': progress() === 100}">
- <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
- </div>
- </li>
- <li class="nav-header">${ _('Duration') }</li>
- <li><span data-bind="text: duration"></span></li>
- <li class="nav-header">${ _('Submitted') }</li>
- <li><span data-bind="text: submitted"></span></li>
- <li class="nav-header">${ _('Next Run') }</li>
- <li><span data-bind="text: properties['nextTime']"></span></li>
- <li class="nav-header">${ _('Total Actions') }</li>
- <li><span data-bind="text: properties['total_actions']"></span></li>
- <li class="nav-header">${ _('End time') }</li>
- <li><span data-bind="text: properties['endTime']"></span></li>
- </ul>
- </div>
- </div>
- <div data-bind="css:{'span10': !$root.isMini(), 'span12': $root.isMini() }">
- <ul class="nav nav-pills margin-top-20">
- <li class="active"><a href="#schedule-page-task" data-toggle="tab">${ _('Tasks') }</a></li>
- <li><a class="jb-logs-link" href="#schedule-page-logs" data-toggle="tab">${ _('Logs') }</a></li>
- <li><a href="#schedule-page-metadata" data-bind="click: function(){ fetchProfile('properties'); $('a[href=\'#schedule-page-metadata\']').tab('show'); }">${ _('Properties') }</a></li>
- <li><a href="#schedule-page-xml" data-bind="click: function(){ fetchProfile('xml'); $('a[href=\'#schedule-page-xml\']').tab('show'); }">${ _('XML') }</a></li>
- <li class="pull-right" data-bind="template: { name: 'job-actions' }"></li>
- </ul>
- <div class="clearfix"></div>
- <div class="tab-content">
- <div class="tab-pane active" id="schedule-page-calendar">
- <!-- ko with: coordinatorActions() -->
- <form class="form-inline">
- <input data-bind="value: textFilter" type="text" class="input-xlarge search-query" placeholder="${_('Filter by name')}">
- <span data-bind="foreach: statesValuesFilter">
- <label class="checkbox">
- <div class="pull-left margin-left-5 status-border status-content" data-bind="css: value, hueCheckbox: checked"></div>
- <div class="inline-block" data-bind="text: name, toggle: checked"></div>
- </label>
- </span>
- <div data-bind="template: { name: 'job-actions' }" class="pull-right"></div>
- </form>
- <table id="schedulesTable" class="datatables table table-condensed status-border-container">
- <thead>
- <tr>
- <th width="1%"><div class="select-all hueCheckbox fa"></div></th>
- <th>${_('Status')}</th>
- <th>${_('Title')}</th>
- <th>${_('type')}</th>
- <th>${_('errorMessage')}</th>
- <th>${_('missingDependencies')}</th>
- <th>${_('number')}</th>
- <th>${_('errorCode')}</th>
- <th>${_('externalId')}</th>
- <th>${_('id')}</th>
- <th>${_('lastModifiedTime')}</th>
- </tr>
- </thead>
- <tbody data-bind="foreach: apps">
- <tr class="status-border pointer" data-bind="css: {'completed': properties.status() == 'SUCCEEDED', 'running': properties.status() !== 'SUCCEEDED' && properties.status() !== 'FAILED', 'failed': properties.status() == 'FAILED'}, click: function() { if (properties.externalId()) { $root.job().id(properties.externalId()); $root.job().fetchJob();} }">
- <td>
- <div class="hueCheckbox fa" data-bind="click: function() {}, clickBubble: false, multiCheck: '#schedulesTable', value: $data, hueChecked: $parent.selectedJobs"></div>
- </td>
- <td data-bind="text: properties.status"></td>
- <td data-bind="text: properties.title"></td>
- <td data-bind="text: properties.type"></td>
- <td data-bind="text: properties.errorMessage"></td>
- <td data-bind="text: properties.missingDependencies"></td>
- <td data-bind="text: properties.number"></td>
- <td data-bind="text: properties.errorCode"></td>
- <td data-bind="text: properties.externalId"></td>
- <td data-bind="text: properties.id"></td>
- <td data-bind="text: properties.lastModifiedTime"></td>
- </tr>
- </tbody>
- </table>
- <!-- /ko -->
- </div>
- <div class="tab-pane" id="schedule-page-logs">
- <pre data-bind="html: logs, logScroller: logs"></pre>
- </div>
- <div class="tab-pane" id="schedule-page-metadata">
- <div data-bind="template: { name: 'render-properties', data: properties['properties'] }"></div>
- </div>
- <div class="tab-pane" id="schedule-page-xml">
- <div data-bind="readonlyXML: properties['xml'], path: 'xml'"></div>
- </div>
- </div>
- </div>
- </div>
- </script>
- <script type="text/html" id="bundle-page">
- <div class="row-fluid">
- <div data-bind="css:{'span2': !$root.isMini(), 'span12': $root.isMini() }">
- <div class="sidebar-nav">
- <ul class="nav nav-list">
- <li class="nav-header">${ _('Id') }</li>
- <li><span data-bind="text: id, attr: { 'title': id }"></span></li>
- <li class="nav-header">${ _('Name') }</li>
- <li><span data-bind="text: name"></span></li>
- <li class="nav-header">${ _('Type') }</li>
- <li><span data-bind="text: type"></span></li>
- <li class="nav-header">${ _('Status') }</li>
- <li><span data-bind="text: status"></span></li>
- <li class="nav-header">${ _('User') }</li>
- <li><span data-bind="text: user"></span></li>
- <li class="nav-header">${ _('Progress') }</li>
- <li><span data-bind="text: progress"></span></li>
- <li>
- <div class="progress-job progress" style="background-color: #FFF; width: 100%" data-bind="css: {'progress-warning': progress() < 100, 'progress-success': progress() === 100}">
- <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
- </div>
- </li>
- <li class="nav-header">${ _('Duration') }</li>
- <li><span data-bind="text: duration"></span></li>
- <li class="nav-header">${ _('Submitted') }</li>
- <li><span data-bind="text: submitted"></span></li>
- <li class="nav-header">${ _('Next Run') }</li>
- <li><span data-bind="text: properties['nextTime']"></span></li>
- <li class="nav-header">${ _('Total Actions') }</li>
- <li><span data-bind="text: properties['total_actions']"></span></li>
- <li class="nav-header">${ _('End time') }</li>
- <li><span data-bind="text: properties['endTime']"></span></li>
- </ul>
- </div>
- </div>
- <div data-bind="css:{'span10': !$root.isMini(), 'span12': $root.isMini() }">
- <ul class="nav nav-pills margin-top-20">
- <li class="active"><a href="#bundle-page-coordinators" data-toggle="tab">${ _('Tasks') }</a></li>
- <li><a class="jb-logs-link" href="#bundle-page-logs" data-toggle="tab">${ _('Logs') }</a></li>
- <li><a href="#bundle-page-metadata" data-bind="click: function(){ fetchProfile('properties'); $('a[href=\'#bundle-page-metadata\']').tab('show'); }">${ _('Properties') }</a></li>
- <li><a href="#bundle-page-xml" data-bind="click: function(){ fetchProfile('xml'); $('a[href=\'#bundle-page-xml\']').tab('show'); }">${ _('XML') }</a></li>
- <li class="pull-right" data-bind="template: { name: 'job-actions' }"></li>
- </ul>
- <div class="clearfix"></div>
- <div class="tab-content">
- <div class="tab-pane active" id="bundle-page-coordinators">
- <input type="text" class="input-xlarge search-query" placeholder="${_('Filter by id, name, user...')}" />
- <div class="btn-group">
- <select size="3" multiple="true"></select>
- <a class="btn btn-status btn-success" data-value="completed">${ _('Succeeded') }</a>
- <a class="btn btn-status btn-warning" data-value="running">${ _('Running') }</a>
- <a class="btn btn-status btn-danger disable-feedback" data-value="failed">${ _('Failed') }</a>
- </div>
- <table id="coordsTable" class="datatables table table-condensed">
- <thead>
- <tr>
- <th width="1%"><div class="select-all hueCheckbox fa"></div></th>
- <th>${_('Status')}</th>
- <th>${_('Name')}</th>
- <th>${_('Type')}</th>
- <th>${_('nextMaterializedTime')}</th>
- <th>${_('lastAction')}</th>
- <th>${_('frequency')}</th>
- <th>${_('timeUnit')}</th>
- <th>${_('externalId')}</th>
- <th>${_('id')}</th>
- <th>${_('pauseTime')}</th>
- </tr>
- </thead>
- <tbody data-bind="foreach: properties['actions']">
- <tr data-bind="click: function() { if (id()) { $root.job().id(id()); $root.job().fetchJob();} }">
- <td><div class="hueCheckbox fa"></div></td>
- <td data-bind="text: status"></td>
- <td data-bind="text: name"></td>
- <td data-bind="text: type"></td>
- <td data-bind="text: nextMaterializedTime"></td>
- <td data-bind="text: lastAction"></td>
- <td data-bind="text: frequency"></td>
- <td data-bind="text: timeUnit"></td>
- <td data-bind="text: externalId"></td>
- <td data-bind="text: id"></td>
- <td data-bind="text: pauseTime"></td>
- </tr>
- </tbody>
- </table> </div>
- <div class="tab-pane" id="bundle-page-logs">
- <pre data-bind="html: logs, logScroller: logs"></pre>
- </div>
- <div class="tab-pane" id="bundle-page-metadata">
- <div data-bind="template: { name: 'render-properties', data: properties['properties'] }"></div>
- </div>
- <div class="tab-pane" id="bundle-page-xml">
- <div data-bind="readonlyXML: properties['xml'], path: 'xml'"></div>
- </div>
- </div>
- </div>
- </div>
- </script>
- <script type="text/html" id="render-properties">
- <!-- ko hueSpinner: { spin: !$data.properties, center: true, size: 'xlarge' } --><!-- /ko -->
- <!-- ko if: $data.properties -->
- <table class="table table-condensed">
- <thead>
- <tr>
- <th>${ _('Name') }</th>
- <th>${ _('Value') }</th>
- </tr>
- </thead>
- <tbody data-bind="foreach: Object.keys($data.properties)">
- <tr>
- <td data-bind="text: $data"></td>
- <td>
- <!-- ko if: $data.indexOf('dir') > -1 || $data.indexOf('path') > -1 || $data.indexOf('output') > -1 || $data.indexOf('input') > -1 || $parent.properties[$data].startsWith('/') || $parent.properties[$data].startsWith('hdfs://') -->
- <a href="javascript:void(0)" data-bind="hueLink: '/filebrowser/view=' + $root.getHDFSPath($parent.properties[$data]) , text: $parent.properties[$data]"></a>
- <!-- /ko -->
- <!-- ko ifnot: $data.indexOf('dir') > -1 || $data.indexOf('path') > -1 || $data.indexOf('output') > -1 || $data.indexOf('input') > -1 || $parent.properties[$data].startsWith('/') || $parent.properties[$data].startsWith('hdfs://') -->
- <span data-bind="text: $parent.properties[$data]"></span>
- <!-- /ko -->
- </td>
- </tr>
- </tbody>
- </table>
- <!-- /ko -->
- </script>
- <script type="text/javascript">
- (function () {
- var Job = function (vm, job) {
- var self = this;
- self.id = ko.observableDefault(job.id);
- self.id.subscribe(function () {
- huePubSub.publish('graph.stop.refresh.view');
- });
- self.doc_url = ko.observableDefault(job.doc_url);
- self.name = ko.observableDefault(job.name || job.id);
- self.type = ko.observableDefault(job.type);
- self.status = ko.observableDefault(job.status);
- self.apiStatus = ko.observableDefault(job.apiStatus);
- self.progress = ko.observableDefault(job.progress);
- self.isRunning = ko.computed(function() {
- return self.apiStatus() == 'RUNNING' || self.apiStatus() == 'PAUSED';
- });
- self.user = ko.observableDefault(job.user);
- self.cluster = ko.observableDefault(job.cluster);
- self.duration = ko.observableDefault(job.duration);
- self.submitted = ko.observableDefault(job.submitted);
- self.logs = ko.observable('');
- self.properties = ko.mapping.fromJS(job.properties || {});
- self.mainType = ko.observable(vm.interface());
- self.coordinatorActions = ko.pureComputed(function() {
- if (self.mainType() == 'schedules' && self.properties['tasks']) {
- var apps = [];
- self.properties['tasks']().forEach(function (instance) {
- var job = new Job(vm, ko.mapping.toJS(instance));
- job.resumeEnabled = function() { return false };
- job.properties = instance;
- apps.push(job);
- });
- var instances = new Jobs(vm);
- instances.apps(apps)
- instances.isCoordinator(true);
- return instances;
- }
- });
- self.textFilter = ko.observable('').extend({ rateLimit: { method: "notifyWhenChangesStop", timeout: 1000 } });
- self.statesValuesFilter = ko.observableArray([
- ko.mapping.fromJS({'value': 'completed', 'name': '${_("Succeeded")}', 'checked': false, 'klass': 'green'}),
- ko.mapping.fromJS({'value': 'running', 'name': '${_("Running")}', 'checked': false, 'klass': 'orange'}),
- ko.mapping.fromJS({'value': 'failed', 'name': '${_("Failed")}', 'checked': false, 'klass': 'red'}),
- ]);
- self.statesFilter = ko.computed(function () {
- var checkedStates = ko.utils.arrayFilter(self.statesValuesFilter(), function (state) {
- return state.checked();
- });
- return ko.utils.arrayMap(checkedStates, function(state){
- return state.value()
- });
- });
- self.typesValuesFilter = ko.observableArray([
- ko.mapping.fromJS({'value': 'map', 'name': '${_("Map")}', 'checked': false, 'klass': 'green'}),
- ko.mapping.fromJS({'value': 'reduce', 'name': '${_("Reduce")}', 'checked': false, 'klass': 'orange'}),
- ]);
- self.typesFilter = ko.computed(function () {
- var checkedTypes = ko.utils.arrayFilter(self.typesValuesFilter(), function (type) {
- return type.checked();
- });
- return ko.utils.arrayMap(checkedTypes, function(type){
- return type.value()
- });
- });
- self.filters = ko.pureComputed(function() {
- return [
- {'text': self.textFilter()},
- {'states': ko.mapping.toJS(self.statesFilter())},
- {'types': ko.mapping.toJS(self.typesFilter())},
- ];
- });
- self.filters.subscribe(function(value) {
- self.fetchProfile('tasks');
- });
- self.rerunModalContent = ko.observable('');
- self.hasKill = ko.pureComputed(function() {
- return ['MAPREDUCE', 'SPARK', 'workflow', 'schedule', 'bundle'].indexOf(self.type()) != -1;
- });
- self.killEnabled = ko.pureComputed(function() {
- return self.hasKill() && self.apiStatus() == 'RUNNING';
- });
- self.hasResume = ko.pureComputed(function() {
- return ['workflow', 'schedule', 'bundle'].indexOf(self.type()) != -1;
- });
- self.resumeEnabled = ko.pureComputed(function() {
- return self.hasResume() && self.apiStatus() == 'PAUSED';
- });
- self.hasRerun = ko.pureComputed(function() {
- return ['workflow', 'schedule-task'].indexOf(self.type()) != -1;
- });
- self.rerunEnabled = ko.pureComputed(function() {
- return self.hasRerun() && ! self.isRunning();
- });
- self.hasPause = ko.pureComputed(function() {
- return ['workflow', 'schedule', 'bundle'].indexOf(self.type()) != -1;
- });
- self.pauseEnabled = ko.pureComputed(function() {
- return self.hasPause() && self.apiStatus() == 'RUNNING';
- });
- self.hasIgnore = ko.pureComputed(function() {
- return ['schedule-task'].indexOf(self.type()) != -1;
- });
- self.ignoreEnabled = ko.pureComputed(function() {
- return self.hasIgnore() && ! self.isRunning();
- });
- self.loadingJob = ko.observable(false);
- var lastFetchJobRequest = null;
- var lastUpdateJobRequest = null;
- self._fetchJob = function (callback) {
- return $.post("/jobbrowser/api/job", {
- app_id: ko.mapping.toJSON(self.id),
- interface: ko.mapping.toJSON(vm.interface)
- }, function (data) {
- if (data.status == 0) {
- if (callback) {
- callback(data);
- };
- } else {
- $(document).trigger("error", data.message);
- }
- });
- };
- self.fetchJob = function () {
- vm.apiHelper.cancelActiveRequest(lastFetchJobRequest);
- vm.apiHelper.cancelActiveRequest(lastUpdateJobRequest);
- self.loadingJob(true);
- var interface = vm.interface();
- if (/application_/.test(self.id()) || /job_/.test(self.id())) {
- interface = 'jobs';
- }
- if (/oozie-oozi-W/.test(self.id())) {
- interface = 'workflows';
- }
- else if (/oozie-oozi-C/.test(self.id())) {
- interface = 'schedules';
- }
- else if (/oozie-oozi-B/.test(self.id())) {
- interface = 'bundles';
- }
- 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())) {
- interface = 'dataeng-jobs';
- }
- interface = vm.isValidInterface(interface);
- vm.interface(interface);
- lastFetchJobRequest = self._fetchJob(function (data) {
- if (data.status == 0) {
- vm.interface(interface);
- vm.job(new Job(vm, data.app));
- hueUtils.changeURL('#!id=' + vm.job().id());
- var crumbs = [];
- if (/^attempt_/.test(vm.job().id())) {
- crumbs.push({'id': vm.job().properties['app_id'], 'name': vm.job().properties['app_id'], 'type': 'app'});
- crumbs.push({'id': vm.job().properties['task_id'], 'name': vm.job().properties['task_id'], 'type': 'task'});
- }
- if (/^task_/.test(vm.job().id())) {
- crumbs.push({'id': vm.job().properties['app_id'], 'name': vm.job().properties['app_id'], 'type': 'app'});
- }
- if (/-oozie-oozi-W@/.test(vm.job().id())) {
- crumbs.push({'id': vm.job().properties['workflow_id'], 'name': vm.job().properties['workflow_id'], 'type': 'workflow'});
- }
- else if (/-oozie-oozi-W/.test(vm.job().id())) {
- if (vm.job().properties['bundle_id']()) {
- crumbs.push({'id': vm.job().properties['bundle_id'](), 'name': vm.job().properties['bundle_id'](), 'type': 'bundle'});
- }
- if (vm.job().properties['coordinator_id']()) {
- crumbs.push({'id': vm.job().properties['coordinator_id'](), 'name': vm.job().properties['coordinator_id'](), 'type': 'schedule'});
- }
- }
- else if (/-oozie-oozi-C/.test(vm.job().id())) {
- if (vm.job().properties['bundle_id']()) {
- crumbs.push({'id': vm.job().properties['bundle_id'](), 'name': vm.job().properties['bundle_id'](), 'type': 'bundle'});
- }
- }
- crumbs.push({'id': vm.job().id(), 'name': vm.job().name(), 'type': vm.job().type()});
- vm.resetBreadcrumbs(crumbs);
- if (vm.job().type() === 'workflow' && !vm.job().workflowGraphLoaded) {
- vm.job().updateWorkflowGraph();
- }
- vm.job().fetchLogs();
- } else {
- $(document).trigger("error", data.message);
- }
- }).always(function () {
- self.loadingJob(false);
- });
- };
- self.updateJob = function () {console.log('update job', vm.isMini());
- vm.apiHelper.cancelActiveRequest(lastUpdateJobRequest);
- huePubSub.publish('graph.refresh.view');
- if (vm.job() == self && self.apiStatus() == 'RUNNING') {
- lastFetchJobRequest = self._fetchJob(function (data) {
- if (vm.job().type() == 'schedule') {
- vm.job(new Job(vm, data.app)); // Updates everything but redraw the page
- } else {
- vm.job().fetchStatus();
- vm.job().fetchLogs();
- }
- // vm.job().fetchProfile(); // Get name of active tab?
- });
- }
- };
- self.fetchLogs = function (name) {
- $.post("/jobbrowser/api/job/logs", {
- app_id: ko.mapping.toJSON(self.id),
- interface: ko.mapping.toJSON(vm.interface),
- type: ko.mapping.toJSON(self.type),
- name: ko.mapping.toJSON(name ? name : 'default')
- }, function (data) {
- if (data.status == 0) {
- self.logs(data.logs.logs)
- } else {
- $(document).trigger("error", data.message);
- }
- });
- };
- self.fetchProfile = function (name) {
- $.post("/jobbrowser/api/job/profile", {
- app_id: ko.mapping.toJSON(self.id),
- interface: ko.mapping.toJSON(vm.interface),
- app_type: ko.mapping.toJSON(self.type),
- app_property: ko.mapping.toJSON(name),
- app_filters: ko.mapping.toJSON(self.filters),
- }, function (data) {
- if (data.status == 0) {
- self.properties[name](data[name]);
- } else {
- $(document).trigger("error", data.message);
- }
- });
- };
- self.fetchStatus = function () {
- $.post("/jobbrowser/api/job", {
- app_id: ko.mapping.toJSON(self.id),
- interface: ko.mapping.toJSON(self.mainType)
- }, function (data) {
- if (data.status == 0) {
- self.status(data.app.status);
- self.apiStatus(data.app.apiStatus);
- self.progress(data.app.progress);
- } else {
- $(document).trigger("error", data.message);
- }
- });
- };
- self.control = function (action) {
- if (action == 'rerun') {
- $.get('/oozie/rerun_oozie_job/' + self.id() + '/?format=json', function(response) {
- $('#rerun-modal').modal('show');
- self.rerunModalContent(response);
- });
- } else {
- vm.jobs._control([self.id()], action, function(data) {
- $(document).trigger("info", data.message);
- self.fetchStatus();
- });
- }
- }
- self.workflowGraphLoaded = false;
- self.lastArrowsPosition = {
- top: 0,
- left: 0
- }
- self.initialArrowsDrawingCount = 0;
- self.initialArrowsDrawing = function() {
- if (self.initialArrowsDrawingCount < 20) {
- self.initialArrowsDrawingCount++;
- huePubSub.publish('graph.draw.arrows');
- window.setTimeout(self.initialArrowsDrawing, 100);
- }
- else if (self.initialArrowsDrawingCount < 30){
- self.initialArrowsDrawingCount++;
- huePubSub.publish('graph.draw.arrows');
- window.setTimeout(self.initialArrowsDrawing, 500);
- }
- else {
- self.initialArrowsDrawingCount = 0;
- }
- }
- self.updateArrowsTimeout = -1;
- self.updateArrows = function() {
- if ($('canvas').length > 0 && $('canvas').position().top !== self.lastArrowsPosition.top && $('canvas').position().left !== self.lastArrowsPosition.left) {
- self.lastArrowsPosition = $('canvas').position();
- }
- if ($('#workflow-page-graph').is(':visible')){
- if ($('canvas').length === 0){
- huePubSub.publish('graph.draw.arrows');
- }
- }
- else {
- $('canvas').remove();
- }
- self.updateArrowsTimeout = window.setTimeout(self.updateArrows, 100);
- }
- self.updateWorkflowGraph = function() {
- huePubSub.publish('graph.stop.refresh.view');
- $('canvas').remove();
- if (!IS_HUE_4) {
- huePubSub.subscribe('hue4.process.headers', function (opts) {
- opts.callback(opts.response);
- });
- }
- if (vm.job().type() === 'workflow') {
- $('#workflow-page-graph').html('<div class="hue-spinner"><i class="fa fa-spinner fa-spin hue-spinner-center hue-spinner-xlarge"></i></div>');
- $.ajax({
- url: "/oozie/list_oozie_workflow/" + vm.job().id(),
- data: {
- 'graph': true,
- 'element': 'workflow-page-graph',
- 'is_jb2': true
- },
- beforeSend: function (xhr) {
- xhr.setRequestHeader("X-Requested-With", "Hue");
- },
- dataType: "html",
- success: function (response) {
- self.workflowGraphLoaded = true;
- huePubSub.publish('hue4.process.headers', {
- response: response,
- callback: function (r) {
- $('#workflow-page-graph').html(r);
- window.clearTimeout(self.updateArrowsTimeout);
- self.initialArrowsDrawing();
- self.updateArrows();
- }
- });
- }
- });
- }
- };
- };
- var Jobs = function (vm) {
- var self = this;
- self.apps = ko.observableArray().extend({ rateLimit: 50 });
- self.totalApps = ko.observable(null);
- self.isCoordinator = ko.observable(false);
- self.loadingJobs = ko.observable(false);
- self.selectedJobs = ko.observableArray();
- self.hasKill = ko.pureComputed(function() {
- return ['jobs', 'workflows', 'schedules', 'bundles'].indexOf(vm.interface()) != -1 && ! self.isCoordinator();
- });
- self.killEnabled = ko.pureComputed(function() {
- return self.hasKill() && self.selectedJobs().length > 0 && $.grep(self.selectedJobs(), function(job) {
- return job.killEnabled();
- }).length == self.selectedJobs().length;
- });
- self.hasResume = ko.pureComputed(function() {
- return ['workflows', 'schedules', 'bundles'].indexOf(vm.interface()) != -1 && ! self.isCoordinator();
- });
- self.resumeEnabled = ko.pureComputed(function() {
- return self.hasResume() && self.selectedJobs().length > 0 && $.grep(self.selectedJobs(), function(job) {
- return job.resumeEnabled();
- }).length == self.selectedJobs().length;
- });
- self.hasRerun = ko.pureComputed(function() {
- return self.isCoordinator();
- });
- self.rerunEnabled = ko.pureComputed(function() {
- return self.hasRerun() && self.selectedJobs().length == 1 && $.grep(self.selectedJobs(), function(job) {
- return job.rerunEnabled();
- }).length == self.selectedJobs().length;
- });
- self.hasPause = ko.pureComputed(function() {
- return ['workflows', 'schedules', 'bundles'].indexOf(vm.interface()) != -1 && ! self.isCoordinator();
- });
- self.pauseEnabled = ko.pureComputed(function() {
- return self.hasPause() && self.selectedJobs().length > 0 && $.grep(self.selectedJobs(), function(job) {
- return job.pauseEnabled();
- }).length == self.selectedJobs().length;
- });
- self.hasIgnore = ko.pureComputed(function() {
- return self.isCoordinator();
- });
- self.ignoreEnabled = ko.pureComputed(function() {
- return self.hasIgnore() && self.selectedJobs().length > 0 && $.grep(self.selectedJobs(), function(job) {
- return job.ignoreEnabled();
- }).length == self.selectedJobs().length;
- });
- self.textFilter = ko.observable('user:${ user.username } ').extend({ rateLimit: { method: "notifyWhenChangesStop", timeout: 1000 } });
- self.statesValuesFilter = ko.observableArray([
- ko.mapping.fromJS({'value': 'completed', 'name': '${_("Succeeded")}', 'checked': false, 'klass': 'green'}),
- ko.mapping.fromJS({'value': 'running', 'name': '${_("Running")}', 'checked': false, 'klass': 'orange'}),
- ko.mapping.fromJS({'value': 'failed', 'name': '${_("Failed")}', 'checked': false, 'klass': 'red'}),
- ]);
- self.statesFilter = ko.computed(function () {
- var checkedStates = ko.utils.arrayFilter(self.statesValuesFilter(), function (state) {
- return state.checked();
- });
- return ko.utils.arrayMap(checkedStates, function(state){
- return state.value()
- });
- });
- self.timeValueFilter = ko.observable(7).extend({ throttle: 500 });
- self.timeUnitFilter = ko.observable('days').extend({ throttle: 500 });
- self.timeUnitFilterUnits = ko.observable([
- {'value': 'days', 'name': '${_("days")}'},
- {'value': 'hours', 'name': '${_("hours")}'},
- {'value': 'minutes', 'name': '${_("minutes")}'},
- ]);
- self.hasPagination = ko.computed(function() {
- return ['workflows', 'schedules', 'bundles'].indexOf(vm.interface()) != -1;
- });
- self.paginationPage = ko.observable(1);
- self.paginationOffset = ko.observable(1);
- self.paginationResultPage = ko.observable(100);
- self.paginationResultCounts = ko.computed(function() {
- return self.apps().length;
- });
- self.pagination = ko.computed(function() {
- return {
- 'page': self.paginationPage(),
- 'offset': self.paginationOffset(),
- 'limit': self.paginationResultPage()
- };
- });
- self.showPreviousPage = ko.computed(function() {
- return self.paginationOffset() > 1;
- });
- self.showNextPage = ko.computed(function() {
- return self.totalApps() != null && (self.paginationOffset() + self.paginationResultPage()) < self.totalApps();
- });
- self.previousPage = function() {
- self.paginationOffset(self.paginationOffset() - self.paginationResultPage());
- };
- self.nextPage = function() {
- self.paginationOffset(self.paginationOffset() + self.paginationResultPage());
- };
- self.filters = ko.pureComputed(function() {
- return [
- {'text': self.textFilter()},
- {'time': {'time_value': self.timeValueFilter(), 'time_unit': self.timeUnitFilter()}},
- {'states': ko.mapping.toJS(self.statesFilter())},
- {'pagination': self.pagination()},
- ];
- });
- self.filters.subscribe(function(value) {
- self.fetchJobs();
- });
- self._fetchJobs = function (callback) {
- return $.post("/jobbrowser/api/jobs", {
- interface: ko.mapping.toJSON(vm.interface),
- filters: ko.mapping.toJSON(self.filters),
- }, function (data) {
- if (data.status == 0) {
- if (callback) {
- callback(data);
- };
- } else {
- $(document).trigger("error", data.message);
- }
- });
- };
- var lastFetchJobsRequest = null;
- var lastUpdateJobsRequest = null;
- self.fetchJobs = function () {
- vm.apiHelper.cancelActiveRequest(lastUpdateJobsRequest);
- vm.apiHelper.cancelActiveRequest(lastFetchJobsRequest);
- self.loadingJobs(true);
- vm.job(null);
- lastFetchJobsRequest = self._fetchJobs(function(data) {
- var apps = [];
- if (data && data.apps) {
- data.apps.forEach(function (job) {
- apps.push(new Job(vm, job));
- });
- }
- self.apps(apps);
- self.totalApps(data.total);
- }).always(function () {
- self.loadingJobs(false);
- });
- }
- self.updateJobs = function () {console.log('update jobs', vm.isMini());
- vm.apiHelper.cancelActiveRequest(lastUpdateJobsRequest);
- lastFetchJobsRequest = self._fetchJobs(function(data) {
- var apps = [];
- if (data && data.apps) {
- var i = 0, j = 0;
- var newJobs = [];
- while (i < self.apps().length && j < data.apps.length) {
- if (self.apps()[i].id() != data.apps[j].id) {
- // New Job
- newJobs.push(new Job(vm, data.apps[j]));
- j++;
- } else {
- // Updated jobs
- if (self.apps()[i].status() != data.apps[j].status) {
- self.apps()[i].status(data.apps[j].status);
- self.apps()[i].apiStatus(data.apps[j].apiStatus);
- }
- i++;
- j++;
- }
- }
- if (i < self.apps().length) {
- self.apps().splice(i, self.apps().length - i);
- }
- newJobs.forEach(function (job) {
- self.apps.push(job);
- });
- self.totalApps(data.total);
- }
- });
- };
- self.control = function (action) {
- if (action == 'rerun') {
- $.get('/oozie/rerun_oozie_coord/' + vm.job().id() + '/?format=json', function(response) {
- $('#rerun-modal').modal('show');
- vm.job().rerunModalContent(response);
- var frag = document.createDocumentFragment();
- vm.job().coordinatorActions().selectedJobs().forEach(function (item) {
- var option = $('<option>', {
- value: item.properties.number(),
- selected: true
- });
- option.appendTo($(frag));
- });
- $('#id_actions').find('option').remove();
- $(frag).appendTo('#id_actions');
- });
- } else if (action == 'ignore') {
- $.post('/oozie/manage_oozie_jobs/' + vm.job().id() + '/ignore', {
- actions: $.map(vm.job().coordinatorActions().selectedJobs(), function(wf) {
- return wf.properties.number();
- }).join(' ')
- }, function(response) {
- vm.job().apiStatus('RUNNING');
- vm.job().updateJob();
- });
- } else {
- self._control(
- $.map(self.selectedJobs(), function(job) {
- return job.id();
- }),
- action,
- function(data) {
- $(document).trigger("info", data.message);
- self.updateJobs();
- }
- )
- }
- }
- self._control = function (app_ids, action, callback) {
- $.post("/jobbrowser/api/job/action", {
- app_ids: ko.mapping.toJSON(app_ids),
- interface: ko.mapping.toJSON(vm.interface),
- operation: ko.mapping.toJSON({action: action})
- }, function (data) {
- if (data.status == 0) {
- if (callback) {
- callback(data);
- }
- } else {
- $(document).trigger("error", data.message);
- }
- }).always(function () {
- });
- };
- };
- var JobBrowserViewModel = function () {
- var self = this;
- self.apiHelper = ApiHelper.getInstance();
- self.assistAvailable = ko.observable(true);
- self.isLeftPanelVisible = ko.observable();
- self.apiHelper.withTotalStorage('assist', 'assist_panel_visible', self.isLeftPanelVisible, true);
- self.appConfig = ko.observable();
- self.isMini = ko.observable(false);
- self.availableInterfaces = ko.pureComputed(function () {
- var jobsInterfaceCondition = function () {
- return self.appConfig() && self.appConfig()['browser'] && self.appConfig()['browser']['interpreter_names'].indexOf('yarn') != -1;
- }
- var dataEngInterfaceCondition = function () {
- return self.appConfig() && self.appConfig()['browser'] && self.appConfig()['browser']['interpreter_names'].indexOf('dataeng') != -1;
- }
- var schedulerInterfaceCondition = function () {
- return self.appConfig() && self.appConfig()['scheduler'] && self.appConfig()['scheduler']['interpreters'].length > 0;
- }
- var interfaces = [
- {'interface': 'jobs', 'label': '${ _ko('Jobs') }', 'condition': jobsInterfaceCondition},
- {'interface': 'dataeng-jobs', 'label': '${ _ko('Jobs') }', 'condition': dataEngInterfaceCondition},
- {'interface': 'workflows', 'label': '${ _ko('Workflows') }', 'condition': schedulerInterfaceCondition},
- {'interface': 'schedules', 'label': '${ _ko('Schedules') }', 'condition': schedulerInterfaceCondition},
- {'interface': 'bundles', 'label': '${ _ko('Bundles') }', 'condition': schedulerInterfaceCondition},
- {'interface': 'slas', 'label': '${ _ko('SLAs') }', 'condition': schedulerInterfaceCondition},
- {'interface': 'dataeng-clusters', 'label': '${ _ko('Clusters') }', 'condition': dataEngInterfaceCondition},
- ];
- return interfaces.filter(function (i) {
- return i.condition();
- });
- });
- self.slasLoadedOnce = false;
- self.slasLoading = ko.observable(true);
- self.loadSlaPage = function(){
- if (!self.slasLoadedOnce) {
- $.ajax({
- url: '/oozie/list_oozie_sla/?is_embeddable=true',
- beforeSend: function (xhr) {
- xhr.setRequestHeader('X-Requested-With', 'Hue');
- },
- dataType: 'html',
- success: function (response) {
- self.slasLoading(false);
- $('#slas').html(response);
- }
- });
- }
- }
- self.oozieInfoLoadedOnce = false;
- self.oozieInfoLoading = ko.observable(true);
- self.loadOozieInfoPage = function(){
- if (!self.oozieInfoLoadedOnce) {
- self.oozieInfoLoadedOnce = true;
- $.ajax({
- url: '/oozie/list_oozie_info/?is_embeddable=true',
- beforeSend: function (xhr) {
- xhr.setRequestHeader('X-Requested-With', 'Hue');
- },
- dataType: 'html',
- success: function (response) {
- self.oozieInfoLoading(false);
- $('#oozieInfo').html(response);
- }
- });
- }
- }
- self.interface = ko.observable();
- self.isValidInterface = function(name) {
- var flatAvailableInterfaces = self.availableInterfaces().map(function (i) {
- return i.interface;
- });
- if (flatAvailableInterfaces.indexOf(name) != -1 || name == 'oozie-info') {
- return name;
- } else {
- return flatAvailableInterfaces[0];
- }
- };
- self.selectInterface = function(interface) {
- huePubSub.publish('graph.stop.refresh.view');
- interface = self.isValidInterface(interface);
- self.interface(interface);
- self.resetBreadcrumbs();
- % if not is_mini:
- hueUtils.changeURL('#!' + interface);
- % endif
- self.job(null);
- if (interface === 'slas'){
- % if not is_mini:
- self.loadSlaPage();
- % endif
- }
- else if (interface === 'oozie-info') {
- % if not is_mini:
- self.loadOozieInfoPage();
- % endif
- }
- else {
- self.jobs.fetchJobs();
- }
- };
- self.jobs = new Jobs(self);
- self.job = ko.observable();
- var updateJobInterval = -1;
- var updateJobsInterval = -1;
- self.job.subscribe(function(val) {
- window.clearInterval(updateJobInterval);
- window.clearInterval(updateJobsInterval);
- if (self.interface() && self.interface() !== 'slas' && self.interface() !== 'oozie-info'){
- if (val) {
- if (val.apiStatus() == 'RUNNING') {
- updateJobInterval = setInterval(val.updateJob, 5000, 'jobbrowser');
- }
- }
- else {
- updateJobsInterval = setInterval(self.jobs.updateJobs, 20000, 'jobbrowser');
- }
- }
- });
- self.breadcrumbs = ko.observableArray([]);
- self.resetBreadcrumbs = function(extraCrumbs) {
- var crumbs = [{'id': '', 'name': self.interface(), 'type': self.interface()}]
- if (extraCrumbs) {
- crumbs = crumbs.concat(extraCrumbs);
- }
- self.breadcrumbs(crumbs);
- }
- self.resetBreadcrumbs();
- self.getHDFSPath = function (path) {
- if (path.startsWith('hdfs://')) {
- var bits = path.substr(7).split('/');
- bits.shift();
- return '/' + bits.join('/');
- }
- return path;
- }
- self.load = function() {
- var h = window.location.hash;
- huePubSub.publish('graph.stop.refresh.view');
- h = h.indexOf('#!') === 0 ? h.substr(2) : '';
- switch (h) {
- case '':
- h = 'jobs';
- case 'slas':
- case 'oozie-info':
- case 'jobs':
- case 'workflows':
- case 'schedules':
- case 'bundles':
- case 'dataeng-clusters':
- case 'dataeng-jobs':
- self.selectInterface(h);
- break;
- default:
- if (h.indexOf('id=') === 0 && ! self.isMini()){
- new Job(self, {id: h.substr(3)}).fetchJob();
- }
- else {
- self.selectInterface('reset');
- }
- }
- }
- };
- $(document).ready(function () {
- var jobBrowserViewModel = new JobBrowserViewModel();
- % if not is_mini:
- ko.applyBindings(jobBrowserViewModel, $('#jobbrowserComponents')[0]);
- huePubSub.subscribe('oozie.action.logs.click', function (widget) {
- var jobId = widget.logsURL().match(/jobbrowser\/jobs\/(.+?)\/single_logs$/i);
- if (jobId) {
- jobBrowserViewModel.job().id(jobId[1]);
- jobBrowserViewModel.job().fetchJob();
- } else {
- console.error('Unknown job log url: ' + widget.logsURL());
- }
- }, 'jobbrowser');
- huePubSub.subscribe('oozie.action.click', function (widget) {
- jobBrowserViewModel.job().id(widget.externalId());
- jobBrowserViewModel.job().fetchJob();
- }, 'jobbrowser');
- % else:
- ko.applyBindings(jobBrowserViewModel, $('#jobbrowserMiniComponents')[0]);
- jobBrowserViewModel.isMini(true);
- % endif
- var loadHash = function () {
- if (window.location.pathname.indexOf('jobbrowser') > -1) {
- jobBrowserViewModel.load();
- }
- };
- window.onhashchange = function () {
- loadHash();
- }
- huePubSub.subscribe('cluster.config.set.config', function (clusterConfig) {
- jobBrowserViewModel.appConfig(clusterConfig && clusterConfig['app_config']);
- loadHash();
- });
- huePubSub.publish('cluster.config.get.config');
- % if not is_mini:
- huePubSub.subscribe('submit.rerun.popup.return', function (data) {
- $.jHueNotify.info('${_('Rerun submitted.')}');
- $('#rerun-modal').modal('hide');
- jobBrowserViewModel.job().apiStatus('RUNNING');
- jobBrowserViewModel.job().updateJob();
- }, 'jobbrowser');
- % else:
- huePubSub.subscribe('mini.jb.navigate', function(interface){
- jobBrowserViewModel.selectInterface(interface);
- });
- % endif
- $(document).on('shown', '.jb-logs-link', function (e) {
- var dest = $(e.target).attr('href');
- if (dest.indexOf('logs') > -1){
- $(dest).find('pre').css('overflow-y', 'auto').height(Math.max(200, $(window).height() - $(dest).find('pre').offset().top - $('.page-content').scrollTop() - 30));
- }
- });
- });
- })();
- </script>
- </span>
- % if not is_embeddable:
- ${ commonfooter(request, messages) | n,unicode }
- % endif
|