execute.mako 96 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801
  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 desktop.lib.django_util import extract_field_data
  18. from desktop.views import commonheader, commonfooter, commonshare, _ko
  19. from beeswax import conf as beeswax_conf
  20. from django.utils.translation import ugettext as _
  21. %>
  22. <%namespace name="comps" file="beeswax_components.mako" />
  23. <%namespace name="layout" file="layout.mako" />
  24. <%namespace name="dashboard" file="common_dashboard.mako" />
  25. <%namespace name="koComponents" file="/ko_components.mako" />
  26. ${ commonheader(_('Query'), app_name, user) | n,unicode }
  27. ${ layout.menubar(section='query') }
  28. <div id="temporaryPlaceholder"></div>
  29. <div id="beeswax-execute">
  30. <div id="query-editor" class="container-fluid hide section">
  31. <div class="panel-container">
  32. <div class="left-panel" id="navigator">
  33. <ul class="nav nav-tabs" style="margin-bottom: 0">
  34. <li class="active"><a href="#navigatorTab" data-toggle="tab" class="sidetab">${_('Assist')}</a></li>
  35. <li><a href="#settingsTab" data-toggle="tab" class="sidetab">${_('Settings')} <span data-bind="visible:design.settings.values().length + design.fileResources.values().length + design.functions.values().length > 0, text: design.settings.values().length + design.fileResources.values().length + design.functions.values().length" class="badge badge-info">12</span></a></li>
  36. % if app_name == 'impala':
  37. <li><a href="#sessionTab" data-toggle="tab" class="sidetab">${_('Session')}</a></li>
  38. % endif
  39. </ul>
  40. <div class="tab-content">
  41. <div class="tab-pane active" id="navigatorTab">
  42. <div class="card card-small card-tab">
  43. <div class="card-body" style="margin-top: 0;">
  44. <div class="assist" data-bind="component: { name: 'assist-panel', params: { assistHelper: assistHelper, appName: '${ app_name }' }}"></div>
  45. </div>
  46. </div>
  47. </div>
  48. <div class="tab-pane" id="settingsTab">
  49. <div class="card card-small card-tab">
  50. <div class="card-body">
  51. <div id="advanced-settings">
  52. <form id="advancedSettingsForm" action="" method="POST" class="form form-horizontal">
  53. ${ csrf_token(request) | n,unicode }
  54. <ul class="nav nav-list" style="border: none; padding: 0;">
  55. <li class="nav-header">${_('settings')}</li>
  56. <li class="white paramContainer">
  57. <!-- ko foreach: design.settings.values -->
  58. <div class="param">
  59. <div class="remove">
  60. <button data-bind="click: $root.removeSetting.bind(this, $index())" type="button" class="btn btn-mini settingsDelete" title="${_('Delete this setting')}">x
  61. </button>
  62. </div>
  63. <div data-bind="css: {'error': $root.getSettingKeyErrors($index()).length > 0}" class="control-group">
  64. <label>${_('Key')}</label>
  65. <input data-bind="value: key" type="text" class="settingsField" autocomplete="off" placeholder="${ 'impala.resultset.cache.size' if app_name == 'impala' else 'mapred.reduce.tasks' }"/>
  66. </div>
  67. <div data-bind="css: {'error': $root.getSettingValueErrors($index()).length > 0}" class="control-group">
  68. <label>${_('Value')}</label>
  69. <input data-bind="value: value" type="text" class="settingValuesField" placeholder="${ '5000' if app_name == 'impala' else '1' }"/>
  70. </div>
  71. </div>
  72. <!-- /ko -->
  73. <div class="control-group">
  74. <a data-bind="click: function() { $root.addSetting('','') }" class="btn btn-mini paramAdd">${_('Add')}</a>
  75. </div>
  76. </li>
  77. <li class="nav-header
  78. % if app_name == 'impala':
  79. hide
  80. % endif
  81. ">
  82. ${_('File Resources')}
  83. </li>
  84. <li class="white paramContainer
  85. % if app_name == 'impala':
  86. hide
  87. % endif
  88. ">
  89. <!-- ko foreach: design.fileResources.values -->
  90. <div class="param">
  91. <div class="remove">
  92. <button data-bind="click: $root.removeFileResource.bind(this, $index())" type="button" class="btn btn-mini" title="${_('Delete this setting')}">&times;</button>
  93. </div>
  94. <div data-bind="css: {'error': $root.getFileResourceTypeErrors($index()).length > 0}" class="control-group">
  95. <label>${_('Type')}</label>
  96. <select data-bind="value: type" class="input-small">
  97. <option value="JAR">${_('jar')}</option>
  98. <option value="ARCHIVE">${_('archive')}</option>
  99. <option value="FILE">${_('file')}</option>
  100. </select>
  101. </div>
  102. <div data-bind="css: {'error': $root.getFileResourcePathErrors($index()).length > 0}" class="control-group">
  103. <label>${_('Path')}</label>
  104. <input data-bind="value: path" type="text" class="filesField fileChooser" placeholder="/user/foo/udf.jar"/>
  105. </div>
  106. </div>
  107. <!-- /ko -->
  108. <div class="control-group">
  109. <a data-bind="click: function() { $root.addFileResource('','') }" class="btn btn-mini paramAdd">${_('Add')}</a>
  110. </div>
  111. </li>
  112. <li title="${ _('User-Defined Functions') }" class="nav-header
  113. % if app_name == 'impala':
  114. hide
  115. % endif
  116. ">
  117. ${_('UDFs')}
  118. </li>
  119. <li class="white paramContainer
  120. % if app_name == 'impala':
  121. hide
  122. % endif
  123. ">
  124. <!-- ko foreach: design.functions.values -->
  125. <div class="param">
  126. <div class="remove">
  127. <button data-bind="click: $root.removeFunction.bind(this, $index())" type="button" class="btn btn-mini settingsDelete" title="${_('Delete this setting')}">&times;</button>
  128. </div>
  129. <div data-bind="css: {'error': $root.getFunctionNameErrors($index()).length > 0}" class="control-group">
  130. <label>${_('Name')}</label>
  131. <input data-bind="value: name" type="text" class="functionsField" autocomplete="off" placeholder="myFunction"/>
  132. </div>
  133. <div data-bind="css: {'error': $root.getFunctionClassNameErrors($index()).length > 0}" class="control-group">
  134. <label>${_('Class name')}</label>
  135. <input data-bind="value: class_name" type="text" class="classNamesField" placeholder="com.acme.example"/>
  136. </div>
  137. </div>
  138. <!-- /ko -->
  139. <div class="control-group">
  140. <a data-bind="click: function() { $root.addFunction('','') }" class="btn btn-mini paramAdd">${_('Add')}</a>
  141. </div>
  142. </li>
  143. <li class="nav-header">${_('Options')}</li>
  144. <li class="white" style="padding-top:0; padding-left:0">
  145. <label class="checkbox" rel="tooltip" data-original-title="${_("If checked (the default), you can include parameters like $parameter_name in your query, and users will be prompted for a value when the query is run.")}">
  146. <input data-bind="checked: design.isParameterized" type="checkbox"/>
  147. ${_("Enable parameterization")}
  148. </label>
  149. </li>
  150. % if app_name == 'impala':
  151. <li class="nav-header">
  152. ${_('Metastore Catalog')}
  153. </li>
  154. <li class="white" style="padding-top:0; padding-left:0">
  155. <div class="control-group">
  156. <span id="refresh-dyk">
  157. <i class="fa fa-refresh"></i>
  158. ${ _('Sync tables tips') }
  159. </span>
  160. <div id="refresh-content" class="hide">
  161. <ul style="text-align: left;">
  162. <li>"invalidate
  163. metadata" ${ _("invalidates the entire catalog metadata. All table metadata will be reloaded on the next access.") }</li>
  164. <li>"invalidate metadata
  165. &lt;table&gt;" ${ _("invalidates the metadata, load on the next access") }</li>
  166. <li>"refresh
  167. &lt;table&gt;" ${ _("refreshes the metadata immediately. It is a faster, incremental refresh.") }</li>
  168. </ul>
  169. </div>
  170. </div>
  171. </li>
  172. % endif
  173. </ul>
  174. </form>
  175. </div>
  176. </div>
  177. </div>
  178. </div>
  179. % if app_name == 'impala':
  180. <div class="tab-pane" id="sessionTab">
  181. <div class="card card-small card-tab">
  182. <div class="card-body">
  183. <!-- ko if: $root.fetchingImpalaSession() -->
  184. <div style="margin: 5px">
  185. <!--[if !IE]><!--><i class="fa fa-spinner fa-spin" style="font-size: 20px; color: #BBB"></i><!--<![endif]-->
  186. <!--[if IE]><img src="${ static('desktop/art/spinner.gif') }"/><![endif]-->
  187. </div>
  188. <!-- /ko -->
  189. <!-- ko ifnot: $root.fetchingImpalaSession() -->
  190. <!-- ko if: $root.impalaSessionLink() != '' -->
  191. <ul class="nav nav-list" style="border: none; padding: 0;">
  192. <li class="nav-header">${ _('address')}</li>
  193. </ul>
  194. <div style="margin: 2px">
  195. <a data-bind="attr: {'href': $root.impalaSessionLink()}" target="_blank"><span data-bind="text: $root.impalaSessionLink().replace(/^(https?):\/\//, '')"></span> <i class="fa fa-external-link"></i></a>
  196. </div>
  197. <!-- /ko -->
  198. <!-- ko if: $root.impalaSessionLink() == '' -->
  199. <div style="margin: 5px">
  200. ${ _("There's currently no valid session") }
  201. </div>
  202. <!-- /ko -->
  203. <!-- /ko -->
  204. </div>
  205. </div>
  206. </div>
  207. % endif
  208. </div>
  209. </div>
  210. <div class="resizer" data-bind="splitDraggable : { appName: '${app_name}', onPosition: onPanelPosition }"><div class="resize-bar"><i class="fa fa-ellipsis-v"></i></div></div>
  211. <div class="right-panel" id="querySide">
  212. <div class="alert" data-bind="visible: design.isRedacted">
  213. ${ _('This query had some sensitive information removed when saved.') }
  214. </div>
  215. <div id="queryContainer" class="card card-small">
  216. <div class="pull-right" style="margin: 10px">
  217. <i class="fa fa-question-circle" id="help"></i>
  218. <div id="help-content" class="hide">
  219. <ul style="text-align: left;">
  220. <li>${ _('Press CTRL + Space to autocomplete') }</li>
  221. <li>${ _("You can execute queries with multiple SQL statements delimited by a semicolon ';'") }</li>
  222. <li>${ _('You can highlight and run a fragment of a query') }</li>
  223. </ul>
  224. </div>
  225. </div>
  226. <div style="margin-bottom: 30px">
  227. % if can_edit_name:
  228. <h1 class="card-heading simple">
  229. <a class="share-link" rel="tooltip" data-placement="bottom" style="padding-left:10px; padding-right: 10px" data-bind="click: openShareModal,
  230. attr: {'data-original-title': '${ _ko("Share") } '+name},
  231. css: {'baseShared': true, 'isShared': isShared()}">
  232. <i class="fa fa-users"></i>
  233. </a>
  234. <a href="javascript:void(0);"
  235. id="query-name"
  236. data-type="text"
  237. data-name="name"
  238. data-value="${design.name}"
  239. data-original-title="${ _('Query name') }"
  240. data-placement="right">
  241. </a>
  242. <a href="javascript:void(0);"
  243. id="query-description"
  244. data-type="textarea"
  245. data-name="description"
  246. data-value="${design.desc}"
  247. data-original-title="${ _('Query description') }"
  248. data-placement="right" style="font-size: 14px; margin-left: 10px">
  249. </a>
  250. </h1>
  251. %endif
  252. </div>
  253. <div class="card-body">
  254. <div class="tab-content">
  255. <div id="queryPane">
  256. <div data-bind="css: {'hide': design.errors().length == 0 || design.inlineErrors().length > 0}" class="alert alert-error">
  257. <!-- ko if: $root.getQueryErrors().length > 0 -->
  258. <p><strong>${_('Please provide a query')}</strong></p>
  259. <!-- /ko -->
  260. <!-- ko if: $root.getQueryErrors().length == 0 -->
  261. <p><strong>${_('Your query has the following error(s):')}</strong></p>
  262. <div data-bind="foreach: design.errors">
  263. <p data-bind="text: $data" class="queryErrorMessage"></p>
  264. </div>
  265. <!-- /ko -->
  266. </div>
  267. <div data-bind="css: {'hide': design.watch.errors().length == 0 || design.watch.inlineErrors().length > 0}" class="alert alert-error">
  268. <p><strong>${_('Your query has the following error(s):')}</strong></p>
  269. <div data-bind="foreach: design.watch.errors">
  270. <p data-bind="text: $data" class="queryErrorMessage"></p>
  271. </div>
  272. </div>
  273. <textarea class="hide" tabindex="1" name="query" id="queryField"></textarea>
  274. <div class="actions">
  275. <button data-bind="click: tryExecuteQuery, visible: $root.canExecute, enable: $root.queryEditorBlank" type="button" id="executeQuery" class="btn btn-primary disable-feedback" tabindex="2">${_('Execute')}</button>
  276. <button data-bind="click: tryCancelQuery, visible: $root.design.isRunning()" class="btn btn-danger" data-loading-text="${ _('Canceling...') }" rel="tooltip" data-original-title="${ _('Cancel the query') }">${ _('Cancel') }</button>
  277. <button data-bind="click: tryExecuteNextStatement, visible: !$root.design.isFinished()" type="button" class="btn btn-primary disable-feedback" tabindex="2">${_('Next')}</button>
  278. <button data-bind="click: tryExecuteQuery, visible: !$root.design.isFinished()" type="button" id="executeQuery" class="btn btn-primary disable-feedback" tabindex="2">${_('Restart')}</button>
  279. % if can_edit:
  280. <button data-bind="click: trySaveDesign, css: {'hide': !$root.design.id() || $root.design.id() == -1}" type="button" class="btn hide">${_('Save')}</button>
  281. % endif
  282. <button data-bind="click: saveAsModal" type="button" class="btn">${_('Save as...')}</button>
  283. <button data-bind="click: tryExplainQuery, visible: $root.canExecute" type="button" id="explainQuery" class="btn">${_('Explain')}</button>
  284. &nbsp; ${_('or create a')} &nbsp;
  285. <button data-bind="click: createNewQuery" type="button" class="btn">${_('New query')}</button>
  286. <br/><br/>
  287. </div>
  288. </div>
  289. </div>
  290. </div>
  291. </div>
  292. <div id="resizePanel"><a href="javascript:void(0)"><i class="fa fa-ellipsis-h"></i></a></div>
  293. <div class="card card-small scrollable resultsContainer">
  294. <div data-bind="visible: !design.explain() && $root.hasResults()">
  295. <a id="expandResults" href="javascript:void(0)" title="${_('See results in full screen')}" rel="tooltip"
  296. class="view-query-results hide pull-right"><h4 style="margin-right: 20px"><i class="fa fa-expand"></i></h4></a>
  297. <a id="save-results" data-bind="click: saveResultsModal" href="javascript:void(0)" title="${_('Save the results to HDFS or a new Hive table')}" rel="tooltip"
  298. class="view-query-results hide pull-right"><h4 style="margin-right: 20px"><i class="fa fa-save"></i></h4>
  299. </a>
  300. <a id="download-csv" data-bind="attr: {'href': '/${ app_name }/download/' + $root.design.history.id() + '/csv'}" href="javascript:void(0)" title="${_('Download the results in CSV format')}" rel="tooltip"
  301. class="view-query-results download hide pull-right"><h4 style="margin-right: 20px"><i class="hfo hfo-file-csv"></i></h4>
  302. </a>
  303. <a id="download-excel" data-bind="attr: {'href': '/${ app_name }/download/' + $root.design.history.id() + '/xls'}" href="javascript:void(0)" title="${_('Download the results in XLS format')}" rel="tooltip"
  304. class="view-query-results download hide pull-right"><h4 style="margin-right: 20px"><i class="hfo hfo-file-xls"></i></h4></a>
  305. </div>
  306. <div class="card-body">
  307. <ul class="nav nav-tabs">
  308. <li class="active recentLi"><a href="#recentTab" data-toggle="tab">${_('Recent queries')}</a></li>
  309. <li><a href="#query" data-toggle="tab">${_('Query')}</a></li>
  310. <!-- ko if: !design.explain() -->
  311. <li><a href="#log" data-toggle="tab">${_('Log')}</a></li>
  312. <!-- /ko -->
  313. <!-- ko if: !design.explain() -->
  314. <li><a href="#columns" data-toggle="tab">${_('Columns')}</a></li>
  315. <li><a href="#results" data-toggle="tab">${_('Results')}</a></li>
  316. <li><a href="#chart" data-toggle="tab">${_('Chart')}</a></li>
  317. <!-- /ko -->
  318. <!-- ko if: design.explain() && !design.isRunning() -->
  319. <li><a href="#explanation" data-toggle="tab">${_('Explanation')}</a></li>
  320. <!-- /ko -->
  321. </ul>
  322. <div class="tab-content">
  323. <div class="active tab-pane" id="recentTab">
  324. <div id="recentLoader">
  325. <!--[if !IE]><!--><i class="fa fa-spinner fa-spin" style="font-size: 20px; color: #DDD"></i><!--<![endif]-->
  326. <!--[if IE]><img src="${ static('desktop/art/spinner.gif') }"/><![endif]-->
  327. </div>
  328. <table id="recentQueries" class="table table-striped table-condensed datatables" cellpadding="0" cellspacing="0" data-tablescroller-enforce-height="true">
  329. <thead>
  330. <tr>
  331. <th>${_('Time')}</th>
  332. <th>${_('Query')}</th>
  333. <th>${_('Result')}</th>
  334. <th>&nbsp;</th>
  335. </tr>
  336. </thead>
  337. <tbody>
  338. </tbody>
  339. </table>
  340. </div>
  341. <div class="tab-pane" id="query">
  342. <pre data-bind="visible: viewModel.design.statement() == ''">${_('There is currently no query to visualize.')}</pre>
  343. <pre data-bind="visible: viewModel.design.statement() != '', text: viewModel.design.statement()"></pre>
  344. </div>
  345. <!-- ko if: design.explain() -->
  346. <div class="tab-pane" id="explanation">
  347. <pre data-bind="text: $root.design.results.explanation()"></pre>
  348. </div>
  349. <!-- /ko -->
  350. <!-- ko if: !design.explain() -->
  351. <div class="tab-pane" id="log">
  352. <div style="position:relative">
  353. <ul data-bind="foreach: $root.design.watch.jobUrls" class="unstyled jobs-overlay">
  354. <li><a data-bind="text: $.trim($data.name), attr: { href: $data.url }" target="_blank"></a></li>
  355. </ul>
  356. <pre data-bind="visible: $root.design.watch.logs().length == 0">${_('There are currently no logs to visualize.')} <img src="${ static('desktop/art/spinner.gif') }" data-bind="visible: $root.design.isRunning()"/></pre>
  357. <pre data-bind="visible: $root.design.watch.logs().length > 0, text: $root.design.watch.logs().join('\n')"></pre>
  358. </div>
  359. </div>
  360. <div class="tab-pane" id="columns">
  361. <pre data-bind="visible: $root.design.results.columns().length == 0">${_('There are currently no columns to visualize.')}</pre>
  362. <div data-bind="visible: $root.design.results.columns().length > 10">
  363. <input id="columnFilter" class="input-xlarge" type="text" placeholder="${_('Filter for column name or type...')}" />
  364. </div>
  365. <table class="table table-striped table-condensed" cellpadding="0" cellspacing="0">
  366. <tbody data-bind="foreach: $root.design.results.columns">
  367. <tr class="columnRow" data-bind="visible: $index() > 0">
  368. <td rel="columntooltip" data-placement="left" data-bind="attr: {title: '${ _ko("Scroll to the column") }">
  369. <a href="javascript:void(0)" data-row-selector="true" class="column-selector" data-bind="text: $data.name"></a>
  370. </td>
  371. <td class="columnType" data-bind="text: $.trim($data.type)"></td>
  372. </tr>
  373. </tbody>
  374. </table>
  375. </div>
  376. <div class="tab-pane" id="results">
  377. <div data-bind="css: {'hide': design.results.errors().length == 0}" class="alert alert-error">
  378. <p><strong>${_('Fetching results ran into the following error(s):')}</strong></p>
  379. <div data-bind="foreach: design.results.errors">
  380. <p data-bind="text: $data" class="queryErrorMessage"></p>
  381. </div>
  382. </div>
  383. <div data-bind="css: {'hide': !$root.hasResults()}">
  384. <table id="resultTable" class="table table-striped table-condensed" cellpadding="0" cellspacing="0" data-tablescroller-enforce-height="true">
  385. <thead>
  386. <tr data-bind="foreach: $root.design.results.columns">
  387. <th data-bind="html: ($index() == 0 ? '&nbsp;' : $data.name), css: { 'sort-numeric': isNumericColumn($data.type), 'sort-date': isDateTimeColumn($data.type), 'sort-string': isStringColumn($data.type), 'datatables-counter-col': $index() == 0}"></th>
  388. </tr>
  389. </thead>
  390. </table>
  391. % if app_name == 'impala':
  392. <a class="pointer" data-bind="visible: $root.scrollNotWorking() && $root.hasMoreResults(), click: manualFetch" style="padding: 10px">${ _('Show more results...') }</a>
  393. % endif
  394. </div>
  395. <div data-bind="css: {'hide': !$root.design.results.empty() || $root.design.results.expired()}" id="resultEmpty">
  396. <pre>${_('The operation has no results.')}</pre>
  397. </div>
  398. <div data-bind="css: {'hide': !$root.design.results.expired()}" id="resultExpired">
  399. <pre>${_('The results have expired, rerun the query if needed.')}</pre>
  400. </div>
  401. </div>
  402. <div class="tab-pane" id="chart">
  403. <pre data-bind="visible: $root.design.results.empty() || $root.design.results.expired()">${_('There is currently no data to build a chart on.')}</pre>
  404. <div class="alert hide">
  405. <strong>${_('Warning:')}</strong> ${_('the results on the chart have been limited to 1000 rows.')}
  406. </div>
  407. <div data-bind="visible: ! $root.design.results.empty() && ! $root.design.results.expired()" style="text-align: center">
  408. <form class="form-inline">
  409. ${_('Chart type')}&nbsp;
  410. <div class="btn-group" data-toggle="buttons-radio">
  411. <a rel="tooltip" data-placement="top" title="${_('Bars')}" id="blueprintBars" href="javascript:void(0)" class="btn"><i class="hcha hcha-bar-chart"></i></a>
  412. <a rel="tooltip" data-placement="top" title="${_('Lines')}" id="blueprintLines" href="javascript:void(0)" class="btn"><i class="hcha hcha-line-chart"></i></a>
  413. <a rel="tooltip" data-placement="top" title="${_('Pie')}" id="blueprintPie" href="javascript:void(0)" class="btn"><i class="hcha hcha-pie-chart"></i></a>
  414. <a rel="tooltip" data-placement="top" title="${_('Map')}" id="blueprintMap" href="javascript:void(0)" class="btn"><i class="hcha hcha-map-chart"></i></a>
  415. </div>&nbsp;&nbsp;
  416. <span id="blueprintAxis" class="hide">
  417. <label>${_('X-Axis')}
  418. <select id="blueprintX" class="blueprintSelect"></select>
  419. </label>&nbsp;&nbsp;
  420. <label>${_('Y-Axis')}
  421. <select id="blueprintY" class="blueprintSelect"></select>
  422. </label>&nbsp;
  423. <div class="btn-group" data-toggle="buttons-radio">
  424. <a rel="tooltip" data-placement="top" title="${_('No sorting')}" id="blueprintNoSort" href="javascript:void(0)" class="btn active"><i class="fa fa-align-left fa-rotate-270"></i></a>
  425. <a rel="tooltip" data-placement="top" title="${_('Sort ascending')}" id="blueprintSortAsc" href="javascript:void(0)" class="btn"><i class="fa fa-sort-amount-asc fa-rotate-270"></i></a>
  426. <a rel="tooltip" data-placement="top" title="${_('Sort descending')}" id="blueprintSortDesc" href="javascript:void(0)" class="btn"><i class="fa fa-sort-amount-desc fa-rotate-270"></i></a>
  427. </div>&nbsp;&nbsp;
  428. </span>
  429. <span id="blueprintLatLng" class="hide">
  430. <label>${_('Latitude')}
  431. <select id="blueprintLat" class="blueprintSelect"></select>
  432. </label>&nbsp;&nbsp;
  433. <label>${_('Longitude')}
  434. <select id="blueprintLng" class="blueprintSelect"></select>
  435. </label>&nbsp;&nbsp;
  436. <label>${_('Label')}
  437. <select id="blueprintDesc" class="blueprintSelect"></select>
  438. </label>
  439. </span>
  440. </form>
  441. </div>
  442. <div data-bind="visible: ! $root.design.results.empty() && ! $root.design.results.expired()" id="blueprint" class="empty center">${_("Please select a chart type.")}</div>
  443. <div style="margin: 10px" data-bind="visible: ! $root.design.results.empty() && ! $root.design.results.expired()">
  444. <div id="pieChart" data-bind="pieChart: {data: {counts: $root.chartData}, fqs: ko.observableArray([]),
  445. transformer: pieChartDataTransformer,
  446. maxWidth: 350 }, visible: $root.chartType() == 'pie'"></div>
  447. <div id="barChart" data-bind="barChart: {datum: {counts: $root.chartData}, fqs: ko.observableArray([]), hideSelection: true,
  448. transformer: barChartDataTransformer}, visible: $root.chartType() == 'bars'"></div>
  449. <div id="lineChart" data-bind="lineChart: {datum: {counts: $root.chartData},
  450. transformer: lineChartDataTransformer,
  451. showControls: false }, visible: $root.chartType() == 'lines'"></div>
  452. <div id="leafletMapChart" data-bind="leafletMapChart: {datum: {counts: $root.chartData},
  453. transformer: leafletMapChartDataTransformer,
  454. showControls: false }, visible: $root.chartType() == 'map'"></div>
  455. </div>
  456. </div>
  457. <!-- /ko -->
  458. </div>
  459. </div>
  460. </div>
  461. </div>
  462. </div>
  463. </div>
  464. <div id="execute-parameter-selection" class="container-fluid hide section">
  465. <div class="row-fluid">
  466. <div class="card card-small">
  467. <h1 class="card-heading simple">${_('Please specify parameters for this query')}</h1>
  468. <div class="card-body">
  469. <p>
  470. <form method="POST" action="" class="form-horizontal">
  471. ${ csrf_token(request) | n,unicode }
  472. <fieldset>
  473. <!-- ko foreach: $root.design.parameters -->
  474. <div class="control-group">
  475. <label data-bind="text: name" class="control-label"></label>
  476. <div class="controls">
  477. <input data-bind="value: value, valueUpdate:'afterkeydown'" type="text"/>
  478. </div>
  479. </div>
  480. <!-- /ko -->
  481. <div class="form-actions" style="padding-left: 10px">
  482. <a class="btn" href="javascript:history.go(-1);">${_('Cancel')}</a>
  483. <button data-bind="enable: $root.hasParametersFilled, click: tryExecuteParameterizedQuery" type="button" class="btn btn-primary">${_('Execute query')}</button>
  484. </div>
  485. </fieldset>
  486. </form>
  487. </p>
  488. </div>
  489. </div>
  490. </div>
  491. </div>
  492. <div id="explain-parameter-selection" class="container-fluid hide section">
  493. <div class="row-fluid">
  494. <div class="card card-small">
  495. <h1 class="card-heading simple">${_('Please specify parameters for this query')}</h1>
  496. <div class="card-body">
  497. <p>
  498. <form method="POST" action="" class="form-horizontal">
  499. ${ csrf_token(request) | n,unicode }
  500. <fieldset>
  501. <!-- ko foreach: $root.design.parameters -->
  502. <div class="control-group">
  503. <label data-bind="text: name" class="control-label"></label>
  504. <div class="controls">
  505. <input data-bind="value: value, valueUpdate:'afterkeydown'" type="text"/>
  506. </div>
  507. </div>
  508. <!-- /ko -->
  509. <div class="form-actions" style="padding-left: 10px">
  510. <a class="btn" href="javascript:history.go(-1);">${_('Cancel')}</a>
  511. <button data-bind="enable: $root.hasParametersFilled, click: tryExplainParameterizedQuery" type="button" class="btn btn-primary">${_('Explain query')}</button>
  512. </div>
  513. </fieldset>
  514. </form>
  515. </p>
  516. </div>
  517. </div>
  518. </div>
  519. </div>
  520. <div id="chooseFile" class="modal hide fade">
  521. <div class="modal-header">
  522. <a href="#" class="close" data-dismiss="modal">&times;</a>
  523. <h3>${_('Choose a file')}</h3>
  524. </div>
  525. <div class="modal-body">
  526. <div id="filechooser">
  527. </div>
  528. </div>
  529. <div class="modal-footer">
  530. </div>
  531. </div>
  532. <div id="chooseFolder" class="modal hide fade">
  533. <div class="modal-header">
  534. <a href="#" class="close" data-dismiss="modal">&times;</a>
  535. <h3>${_('Select a directory')}</h3>
  536. </div>
  537. <div class="modal-body">
  538. <div id="folderchooser">
  539. </div>
  540. </div>
  541. <div class="modal-footer">
  542. </div>
  543. </div>
  544. <div id="choosePath" class="modal hide fade">
  545. <div class="modal-header">
  546. <a href="#" class="close" data-dismiss="modal">&times;</a>
  547. <h3>${_('Select a file or directory')}</h3>
  548. </div>
  549. <div class="modal-body">
  550. <div id="pathchooser">
  551. </div>
  552. </div>
  553. <div class="modal-footer">
  554. </div>
  555. </div>
  556. <div id="saveAs" class="modal hide fade">
  557. <div class="modal-header">
  558. <a href="#" class="close" data-dismiss="modal">&times;</a>
  559. <h3>${_('Choose a name')}</h3>
  560. </div>
  561. <form class="form-horizontal">
  562. <div class="control-group" id="saveas-query-name">
  563. <label class="control-label">${_('Name')}</label>
  564. <div class="controls">
  565. <input data-bind="value: $root.design.name, html" type="text" class="input-xlarge">
  566. </div>
  567. </div>
  568. <div class="control-group">
  569. <label class="control-label">${_('Description')}</label>
  570. <div class="controls">
  571. <input data-bind="value: $root.design.description, html" type="text" class="input-xlarge">
  572. </div>
  573. </div>
  574. </form>
  575. <div class="modal-footer">
  576. <button class="btn" data-dismiss="modal">${_('Cancel')}</button>
  577. <button data-bind="click: trySaveAsDesign" class="btn btn-primary">${_('Save')}</button>
  578. </div>
  579. </div>
  580. <div id="saveResultsModal" class="modal hide fade">
  581. <div class="loader">
  582. <div class="overlay"></div>
  583. <!--[if !IE]><!--><i class="fa fa-spinner fa-spin"></i><!--<![endif]-->
  584. <!--[if IE]><img class="spinner" src="${ static('desktop/art/spinner-big-inverted.gif') }"/><![endif]-->
  585. </div>
  586. <div class="modal-header">
  587. <a href="#" class="close" data-dismiss="modal">&times;</a>
  588. <h3>${_('Save Query Results')}</h3>
  589. </div>
  590. <div class="modal-body" style="padding: 4px">
  591. <!-- ko if: $root.design.results.save.saveTargetError() -->
  592. <h4 data-bind="text: $root.design.results.save.saveTargetError()"></h4>
  593. <!-- /ko -->
  594. <!-- ko if: $root.design.results.save.targetTableError() -->
  595. <h4 data-bind="text: $root.design.results.save.targetTableError()"></h4>
  596. <!-- /ko -->
  597. <!-- ko if: $root.design.results.save.targetDirectoryError() -->
  598. <h4 data-bind="text: $root.design.results.save.targetDirectoryError()"></h4>
  599. <!-- /ko -->
  600. <form id="saveResultsForm" method="POST" class="form form-inline">
  601. ${ csrf_token(request) | n,unicode }
  602. <fieldset>
  603. <div data-bind="css: {'error': $root.design.results.save.targetFileError()}" class="control-group">
  604. <div class="controls">
  605. <label class="radio">
  606. <input data-bind="checked: $root.design.results.save.type" type="radio" name="save-results-type" value="hdfs-file">
  607. &nbsp;${ _('In an HDFS file') }
  608. </label>
  609. <span data-bind="visible: $root.design.results.save.type() == 'hdfs-file'">
  610. <input data-bind="value: $root.design.results.save.path" type="text" name="target_file" placeholder="${_('Path to CSV file')}" class="pathChooser">
  611. </span>
  612. <label class="radio" data-bind="visible: $root.design.results.save.type() == 'hdfs-file'">
  613. <input data-bind="checked: $root.design.results.save.overwrite" type="checkbox" name="overwrite">
  614. ${ _('Overwrite') }
  615. </label>
  616. </div>
  617. </div>
  618. <div data-bind="css: {'error': $root.design.results.save.targetTableError()}" class="control-group">
  619. <div class="controls">
  620. <label class="radio">
  621. <input data-bind="checked: $root.design.results.save.type" type="radio" name="save-results-type" value="hive-table">
  622. &nbsp;${ _('In a new table') }
  623. </label>
  624. <span data-bind="visible: $root.design.results.save.type() == 'hive-table'">
  625. <input data-bind="value: $root.design.results.save.path" type="text" name="target_table" class="span4" placeholder="${_('Table name or <database name>.<table name>')}">
  626. </span>
  627. </div>
  628. </div>
  629. <div data-bind="css: {'error': $root.design.results.save.targetDirectoryError()}" class="control-group hide advanced">
  630. <div class="controls">
  631. <label class="radio">
  632. <input data-bind="checked: $root.design.results.save.type" type="radio" name="save-results-type" value="hdfs-directory">
  633. &nbsp;${ _('Big Query in HDFS') }
  634. </label>
  635. <span data-bind="visible: $root.design.results.save.type() == 'hdfs-directory'">
  636. <input data-bind="value: $root.design.results.save.path" type="text" name="target_dir" placeholder="${_('Path to directory')}" class="folderChooser">
  637. <i class="fa fa-question-circle" id="hdfs-directory-help"></i>
  638. </span>
  639. </div>
  640. </div>
  641. </fieldset>
  642. </form>
  643. <div id="hdfs-directory-help-content" class="hide">
  644. <p>${ _("Use this option if you have a large result. It will rerun the entire query and save the results to the chosen HDFS directory.") }</p>
  645. </div>
  646. </div>
  647. <div class="modal-footer">
  648. <a id="save-results-advanced" href="javascript:void(0)" class="pull-left">${ _('Show advanced fields') }</a>
  649. <a id="save-results-simple" href="javascript:void(0)" class="pull-left hide">${ _('Hide advanced fields') }</a>
  650. <button class="btn" data-dismiss="modal">${_('Cancel')}</button>
  651. <button data-bind="click: trySaveResults" class="btn btn-primary disable-feedback">${_('Save')}</button>
  652. </div>
  653. </div>
  654. <div id="navigatorQuicklook" class="modal hide fade">
  655. <div class="modal-header">
  656. <a href="#" class="close" data-dismiss="modal">&times;</a>
  657. % if has_metastore:
  658. <a class="tableLink pull-right" href="#" target="_blank" style="margin-right: 20px;margin-top:6px">
  659. <i class="fa fa-external-link"></i> ${ _('View in Metastore Browser') }
  660. </a>
  661. % endif
  662. <h3>${_('Data sample for')} <span class="tableName"></span></h3>
  663. </div>
  664. <div class="modal-body" style="min-height: 100px">
  665. <div class="loader">
  666. <!--[if !IE]><!--><i class="fa fa-spinner fa-spin" style="font-size: 30px; color: #DDD"></i><!--<![endif]-->
  667. <!--[if IE]><img src="${ static('desktop/art/spinner.gif') }"/><![endif]-->
  668. </div>
  669. <div class="sample"></div>
  670. </div>
  671. <div class="modal-footer">
  672. <button class="btn btn-primary disable-feedback" data-dismiss="modal">${_('Ok')}</button>
  673. </div>
  674. </div>
  675. </div>
  676. <div id="tableAnalysis" class="popover mega-popover right">
  677. <div class="arrow"></div>
  678. <h3 class="popover-title" style="text-align: left">
  679. <a class="pull-right pointer close-popover" style="margin-left: 8px"><i class="fa fa-times"></i></a>
  680. <a class="pull-right pointer stats-refresh" style="margin-left: 8px"><i class="fa fa-refresh"></i></a>
  681. <span class="pull-right stats-warning muted" rel="tooltip" data-placement="top" title="${ _('The column stats for this table are not accurate') }" style="margin-left: 8px"><i class="fa fa-exclamation-triangle"></i></span>
  682. <strong class="table-name"></strong> ${ _(' table analysis') }
  683. </h3>
  684. <div class="popover-content">
  685. <div id="tableAnalysisStats">
  686. <div class="content"></div>
  687. </div>
  688. </div>
  689. </div>
  690. <div id="columnAnalysis" class="popover mega-popover right">
  691. <div class="arrow"></div>
  692. <h3 class="popover-title" style="text-align: left">
  693. <a class="pull-right pointer close-popover" style="margin-left: 8px"><i class="fa fa-times"></i></a>
  694. <a class="pull-right pointer stats-refresh" style="margin-left: 8px"><i class="fa fa-refresh"></i></a>
  695. <strong class="column-name"></strong> ${ _(' column analysis') }
  696. </h3>
  697. <div class="popover-content">
  698. <div class="pull-right hide filter">
  699. <input id="columnAnalysisTermsFilter" type="text" placeholder="${ _('Prefix filter...') }"/>
  700. </div>
  701. <ul class="nav nav-tabs" role="tablist">
  702. <li class="active"><a href="#columnAnalysisStats" role="tab" data-toggle="tab">${ _('Stats') }</a></li>
  703. <li><a href="#columnAnalysisTerms" role="tab" data-toggle="tab">${ _('Terms') }</a></li>
  704. </ul>
  705. <div class="tab-content">
  706. <div class="tab-pane active" id="columnAnalysisStats" style="text-align: left">
  707. <div class="content"></div>
  708. </div>
  709. <div class="tab-pane" id="columnAnalysisTerms" style="text-align: left">
  710. <div class="alert">${ _('There are no terms to be shown') }</div>
  711. <div class="content"></div>
  712. </div>
  713. </div>
  714. </div>
  715. </div>
  716. ${ commonshare() | n,unicode }
  717. <script src="${ static('desktop/js/hue.json.js') }" type="text/javascript" charset="utf-8"></script>
  718. <script src="${ static('desktop/ext/js/jquery/plugins/jquery-ui-1.10.4.draggable-droppable-sortable.min.js') }" type="text/javascript" charset="utf-8"></script>
  719. <script src="${ static('desktop/ext/js/routie-0.3.0.min.js') }" type="text/javascript" charset="utf-8"></script>
  720. <script src="${ static('desktop/ext/js/knockout.min.js') }" type="text/javascript" charset="utf-8"></script>
  721. <script src="${ static('desktop/ext/js/knockout-mapping.min.js') }" type="text/javascript" charset="utf-8"></script>
  722. <script src="${ static('desktop/js/ko.hue-bindings.js') }" type="text/javascript" charset="utf-8"></script>
  723. <script src="${ static('desktop/js/assistHelper.js') }" type="text/javascript" charset="utf-8"></script>
  724. <script src="${ static('desktop/js/autocomplete.js') }" type="text/javascript" charset="utf-8"></script>
  725. <script src="${ static('beeswax/js/beeswax.vm.js') }"></script>
  726. <script src="${ static('desktop/js/share.vm.js') }"></script>
  727. <script src="${ static('desktop/ext/js/codemirror-3.11.js') }"></script>
  728. <link rel="stylesheet" href="${ static('desktop/ext/css/codemirror.css') }">
  729. <script src="${ static('desktop/js/codemirror-hql.js') }"></script>
  730. % if app_name == 'impala':
  731. <script src="${ static('desktop/js/codemirror-isql-hint.js') }"></script>
  732. % else:
  733. <script src="${ static('desktop/js/codemirror-hql-hint.js') }"></script>
  734. % endif
  735. <script src="${ static('desktop/js/codemirror-show-hint.js') }"></script>
  736. <link href="${ static('desktop/ext/css/bootstrap-editable.css') }" rel="stylesheet">
  737. <script src="${ static('desktop/ext/js/bootstrap-editable.min.js') }"></script>
  738. <script src="${ static('desktop/ext/js/moment-with-locales.min.js') }"></script>
  739. <script src="${ static('beeswax/js/stats.utils.js') }"></script>
  740. <link rel="stylesheet" href="${ static('desktop/ext/select2/select2.css') }">
  741. <script src="${ static('desktop/ext/select2/select2.min.js') }" type="text/javascript" charset="utf-8"></script>
  742. ${ koComponents.assistPanel() }
  743. <style type="text/css">
  744. h1 {
  745. margin-bottom: 5px;
  746. }
  747. .panel-container {
  748. width: 100%;
  749. position: relative;
  750. }
  751. .left-panel {
  752. position: absolute;
  753. }
  754. .resizer {
  755. position: absolute;
  756. width: 20px;
  757. text-align: center;
  758. z-index: 1000;
  759. }
  760. .resize-bar {
  761. top: 50%;
  762. position: relative;
  763. cursor: ew-resize;
  764. }
  765. .right-panel {
  766. position: absolute;
  767. }
  768. #chooseFile, #chooseFolder, #choosePath {
  769. z-index: 1100;
  770. }
  771. #filechooser, #folderchooser, #pathchooser {
  772. min-height: 100px;
  773. overflow-y: auto;
  774. }
  775. .control-group {
  776. margin-bottom: 3px !important;
  777. }
  778. .control-group label {
  779. float: left;
  780. padding-top: 5px;
  781. text-align: left;
  782. width: 40px;
  783. }
  784. .control-group label.radio {
  785. float: none;
  786. width: auto;
  787. }
  788. .sidebar-nav {
  789. margin-bottom: 90px !important;
  790. }
  791. .paramContainer {
  792. padding-top: 3px!important;
  793. padding-left: 0px!important;
  794. padding-right: 0px!important;
  795. }
  796. .param {
  797. margin-bottom: 5px;
  798. padding:4px;
  799. padding-left:8px;
  800. border-bottom: 1px solid #F6F6F6;
  801. }
  802. .param:nth-child(even) {
  803. background-color: #F0F0F0;
  804. }
  805. .table-actions {
  806. position: absolute;
  807. right: 0;
  808. padding-left: 3px;
  809. background-color: #FFF;
  810. }
  811. .preview-data {
  812. margin-right: 5px;
  813. }
  814. .remove {
  815. float: right;
  816. }
  817. .fileChooserBtn {
  818. border-radius: 0 3px 3px 0;
  819. height: 31px;
  820. }
  821. .CodeMirror {
  822. border: 1px solid #eee;
  823. margin-bottom: 20px;
  824. }
  825. .editorError {
  826. color: #B94A48;
  827. background-color: #F2DEDE;
  828. padding: 4px;
  829. font-size: 11px;
  830. }
  831. .editable-empty, .editable-empty:hover {
  832. color: #666;
  833. font-style: normal;
  834. }
  835. .tooltip.left {
  836. margin-left: -13px;
  837. }
  838. .fullscreen {
  839. position: absolute;
  840. top: 70px;
  841. left: 0;
  842. width: 100%;
  843. background-color: #FFFFFF;
  844. z-index: 100;
  845. }
  846. .map {
  847. height: 200px;
  848. }
  849. #resultTable td, #resultTable th {
  850. white-space: nowrap;
  851. }
  852. .tab-content {
  853. min-height: 100px;
  854. }
  855. .columnType {
  856. text-align: right!important;
  857. color: #999;
  858. }
  859. #queryContainer {
  860. margin-bottom: 0;
  861. }
  862. #resizePanel a {
  863. position: absolute;
  864. cursor: ns-resize;
  865. color: #666;
  866. margin-left: auto;
  867. margin-right: auto;
  868. }
  869. .resultsContainer {
  870. margin-top: 20px;
  871. }
  872. #recentQueries {
  873. width: 100%;
  874. }
  875. #recentQueries code {
  876. cursor: pointer;
  877. white-space: normal;
  878. }
  879. #recentQueries tr td:first-child {
  880. white-space: nowrap;
  881. }
  882. .table-container {
  883. margin-right:10px;
  884. }
  885. #navigator .card-body {
  886. margin-top: 1px !important;
  887. padding: 7px !important;
  888. }
  889. #navigator .nav-header {
  890. padding-left: 0;
  891. }
  892. #navigator .control-group {
  893. padding-left: 0;
  894. }
  895. #navigator .nav-list > li.white, #navigator .nav-list .nav-header {
  896. margin: 0;
  897. }
  898. .jobs-overlay {
  899. background-color: #FFF;
  900. opacity: 0.8;
  901. position: absolute;
  902. top: 10px;
  903. right: 15px;
  904. }
  905. .jobs-overlay li {
  906. padding: 5px;
  907. }
  908. .jobs-overlay:hover {
  909. opacity: 1;
  910. }
  911. #saveResultsModal .overlay {
  912. background: black; opacity: 0.5;
  913. position: absolute;
  914. top: 0px;
  915. right:0px;
  916. left: 0px;
  917. bottom: 0px;
  918. z-index: 100;
  919. }
  920. #saveResultsModal .loader {
  921. text-align: center;
  922. position: absolute;
  923. top: 0px;
  924. right:0px;
  925. left: 0px;
  926. bottom: 0px;
  927. }
  928. #saveResultsModal i.fa-spinner, #saveResultsModal img.spinner {
  929. margin-top: -30px;
  930. margin-left: -30px;
  931. position: absolute;
  932. top: 50%;
  933. left: 50%;
  934. z-index: 101;
  935. }
  936. #saveResultsModal i.fa-spinner {
  937. font-size: 60px;
  938. color: #DDD;
  939. }
  940. .tooltip {
  941. z-index: 10001;
  942. }
  943. .filesField, .functionsField, .classNamesField, .settingsField, .settingValuesField {
  944. width: 60%;
  945. }
  946. .fileChooser, .folderChooser {
  947. border-radius: 3px 0 0 3px !important;
  948. border-right: 0 !important;
  949. }
  950. </style>
  951. <link rel="stylesheet" href="${ static('desktop/ext/css/hue-filetypes.css') }">
  952. <link rel="stylesheet" href="${ static('desktop/ext/css/hue-charts.css') }">
  953. <script src="${ static('desktop/ext/js/jquery/plugins/jquery-fieldselection.js') }" type="text/javascript"></script>
  954. <script src="${ static('beeswax/js/autocomplete.utils.js') }" type="text/javascript" charset="utf-8"></script>
  955. <link rel="stylesheet" href="${ static('desktop/ext/chosen/chosen.min.css') }">
  956. <script src="${ static('desktop/ext/chosen/chosen.jquery.min.js') }" type="text/javascript" charset="utf-8"></script>
  957. ${ dashboard.import_charts() }
  958. <script type="text/javascript" charset="utf-8">
  959. // avoid blinking of the panels
  960. var leftPanelWidth = $.totalStorage("${app_name}_left_panel_width") != null ? $.totalStorage("${app_name}_left_panel_width") : 250;
  961. $(".left-panel").css("width", leftPanelWidth + "px");
  962. $(".right-panel").css("left", leftPanelWidth + 20 + "px");
  963. var codeMirror, resizeNavigator, dataTable, renderRecent, syncWithHive;
  964. var HIVE_AUTOCOMPLETE_BASE_URL = "${ autocomplete_base_url | n,unicode }";
  965. var HIVE_AUTOCOMPLETE_FAILS_QUIETLY_ON = [500]; // error codes from beeswax/views.py - autocomplete
  966. var HIVE_AUTOCOMPLETE_USER = "${ user }";
  967. var HIVE_AUTOCOMPLETE_APP = "${app_name}";
  968. var STATS_PROBLEMS = "${ _('There was a problem loading the stats.') }";
  969. var assistHelper = new AssistHelper({
  970. app: HIVE_AUTOCOMPLETE_APP,
  971. user: HIVE_AUTOCOMPLETE_USER
  972. });
  973. var autocompleter = new Autocompleter({
  974. assistHelper: assistHelper,
  975. mode: HIVE_AUTOCOMPLETE_APP
  976. });
  977. var escapeOutput = function (str) {
  978. return $('<span>').text(str).html().trim();
  979. };
  980. var truncateOutput = function (obj) {
  981. //default to 20 characters (column output displays first 21 chars so we need to consider the length of both column name and type
  982. var chars = obj.chars || 20,
  983. name = obj.name || '',
  984. type = obj.type || '',
  985. output = name.length + type.length,
  986. suffix = '',
  987. trim;
  988. if (output > chars) {
  989. trim = Math.abs((output + 4) - chars); // 4 accounts for ellipsis, spaces, parenthesis
  990. type = type.slice(0, Math.abs(type.length - trim));
  991. suffix = '&hellip;';
  992. }
  993. return escapeOutput(type) + suffix;
  994. };
  995. var reinitTimeout = -1;
  996. function onPanelPosition() {
  997. placeResizePanelHandle();
  998. window.clearTimeout(reinitTimeout);
  999. reinitTimeout = window.setTimeout(function () {
  1000. reinitializeTableExtenders();
  1001. }, 50);
  1002. }
  1003. function placeResizePanelHandle() {
  1004. // dynamically positioning the resize panel handle since IE doesn't play well with styles.
  1005. $("#resizePanel a").css("left", $("#resizePanel").position().left + $("#resizePanel").width()/2 - 8);
  1006. }
  1007. function reinitializeTableExtenders() {
  1008. $("#resultTable").jHueTableExtender({
  1009. fixedHeader: true,
  1010. includeNavigator: false
  1011. });
  1012. $("#recentQueries").jHueTableExtender({
  1013. fixedHeader: true,
  1014. includeNavigator: false
  1015. });
  1016. }
  1017. var CURRENT_CODEMIRROR_SIZE = 100;
  1018. var INITIAL_HORIZONTAL_RESIZE_POSITION = -1;
  1019. // Navigator, recent queries
  1020. $(document).ready(function () {
  1021. $("#resizePanel a").draggable({
  1022. axis: "y",
  1023. drag: function (e, ui) {
  1024. draggableHelper($(this), e, ui);
  1025. $(".jHueTableExtenderClonedContainer").hide();
  1026. },
  1027. stop: function (e, ui) {
  1028. $(".jHueTableExtenderClonedContainer").show();
  1029. draggableHelper($(this), e, ui);
  1030. reinitializeTableExtenders();
  1031. }
  1032. });
  1033. function checkForInitialSplitterPosition() {
  1034. INITIAL_HORIZONTAL_RESIZE_POSITION = $("#resizePanel a").position().top;
  1035. if (INITIAL_HORIZONTAL_RESIZE_POSITION <= 0) {
  1036. window.setTimeout(checkForInitialSplitterPosition, 200);
  1037. }
  1038. }
  1039. checkForInitialSplitterPosition();
  1040. function resizeCodeMirror(el) {
  1041. CURRENT_CODEMIRROR_SIZE = 100 + (el.position().top - INITIAL_HORIZONTAL_RESIZE_POSITION);
  1042. codeMirror.setSize("99%", CURRENT_CODEMIRROR_SIZE);
  1043. }
  1044. function draggableHelper(el, e, ui) {
  1045. if (el.position().top > INITIAL_HORIZONTAL_RESIZE_POSITION) {
  1046. resizeCodeMirror(el);
  1047. }
  1048. if (ui.position.top < INITIAL_HORIZONTAL_RESIZE_POSITION) {
  1049. ui.position.top = INITIAL_HORIZONTAL_RESIZE_POSITION;
  1050. resizeCodeMirror(el);
  1051. }
  1052. }
  1053. var recentQueries = $("#recentQueries").dataTable({
  1054. "bPaginate": false,
  1055. "bLengthChange": false,
  1056. "bInfo": false,
  1057. "bFilter": false,
  1058. "aoColumns": [
  1059. { "sWidth" : "100px", "sSortDataType":"dom-sort-value", "sType":"numeric" },
  1060. null,
  1061. { "sWidth" : "80px", "bSortable": false },
  1062. { "bSortable": false, "sWidth" : "4px" }
  1063. ],
  1064. "aaSorting": [
  1065. [0, 'desc']
  1066. ],
  1067. "oLanguage": {
  1068. "sEmptyTable": "${_('No data available')}",
  1069. "sInfo": "${_('Showing _START_ to _END_ of _TOTAL_ entries')}",
  1070. "sInfoEmpty": "${_('Showing 0 to 0 of 0 entries')}",
  1071. "sInfoFiltered": "${_('(filtered from _MAX_ total entries)')}",
  1072. "sZeroRecords": "${_('No matching records')}",
  1073. "oPaginate": {
  1074. "sFirst": "${_('First')}",
  1075. "sLast": "${_('Last')}",
  1076. "sNext": "${_('Next')}",
  1077. "sPrevious": "${_('Previous')}"
  1078. }
  1079. }
  1080. });
  1081. renderRecent = function() {
  1082. $("#recentLoader").show();
  1083. $("#recentQueries").hide();
  1084. recentQueries.fnClearTable();
  1085. var locale = window.navigator.userLanguage || window.navigator.language;
  1086. moment.locale(locale);
  1087. $.getJSON("${ url(app_name + ':list_query_history') }?format=json", function(data) {
  1088. if (data && data.queries) {
  1089. var _rows = [];
  1090. $(data.queries).each(function(cnt, item){
  1091. _rows.push([
  1092. '<span data-sort-value="' + item.timeInMs + '">' + moment(item.timeInMs*1000).format("L LTS") + '</span>',
  1093. '<code style="cursor:pointer">' + item.query + '</code>',
  1094. (item.resultsUrl != "" ? '<a href="' + item.resultsUrl + '" data-row-selector-exclude="true">${_('See results...')}</a>': ''),
  1095. (item.designUrl != "" ? '<a href="' + item.designUrl + '" data-row-selector="true">&nbsp;</a>': '')
  1096. ]);
  1097. });
  1098. recentQueries.fnAddData(_rows);
  1099. }
  1100. $("a[data-row-selector='true']").jHueRowSelector();
  1101. $("#recentLoader").hide();
  1102. $("#recentQueries").show().css("width", "100%");
  1103. reinitializeTableExtenders();
  1104. });
  1105. };
  1106. renderRecent();
  1107. $("#navigatorQuicklook").modal({
  1108. show: false
  1109. });
  1110. $("#navigatorSearch").jHueDelayedInput(function(){
  1111. $("#navigatorTables li").removeClass("hide");
  1112. $("#navigatorTables li").each(function () {
  1113. if ($(this).text().toLowerCase().indexOf($("#navigatorSearch").val().toLowerCase()) == -1) {
  1114. $(this).addClass("hide");
  1115. }
  1116. });
  1117. });
  1118. $("#columnFilter").jHueDelayedInput(function(){
  1119. $(".columnRow").removeClass("hide");
  1120. $(".columnRow").each(function () {
  1121. if ($(this).text().toLowerCase().indexOf($("#columnFilter").val().toLowerCase()) == -1) {
  1122. $(this).addClass("hide");
  1123. }
  1124. });
  1125. });
  1126. resizeNavigator = function () {
  1127. $(".resizer").css("height", ($(window).height() - 150) + "px");
  1128. $("#navigator .card").css("min-height", ($(window).height() - 150) + "px");
  1129. $(".table-container").css("max-height", ($(window).height() - 280) + "px").css("overflow-y", "auto");
  1130. };
  1131. huePubSub.subscribe('assist.dblClickItem', function(value) {
  1132. codeMirror.replaceSelection(value);
  1133. codeMirror.setSelection(codeMirror.getCursor());
  1134. codeMirror.focus();
  1135. });
  1136. $("#expandResults").on("click", function(){
  1137. $("#resultTablejHueTableExtenderClonedContainer").remove();
  1138. if ($(this).find("i").hasClass("fa-expand")){
  1139. $(this).find("i").removeClass("fa-expand").addClass("fa-compress");
  1140. $(this).parent().parent().addClass("fullscreen");
  1141. }
  1142. else {
  1143. $(this).find("i").addClass("fa-expand").removeClass("fa-compress");
  1144. $(this).parent().parent().removeClass("fullscreen");
  1145. }
  1146. reinitializeTable();
  1147. });
  1148. resizeNavigator();
  1149. window.setTimeout(resizeNavigator, 200);
  1150. $(document).on("click", ".column-selector", function () {
  1151. var _t = $("#resultTable");
  1152. var _text = $.trim($(this).text().split("(")[0]);
  1153. var _col = _t.find("th").filter(function() {
  1154. return $.trim($(this).text()) == _text;
  1155. });
  1156. _t.find(".columnSelected").removeClass("columnSelected");
  1157. _t.find("tr td:nth-child(" + (_col.index() + 1) + ")").addClass("columnSelected");
  1158. $("a[href='#results']").click();
  1159. });
  1160. $(document).on("click", "#tableAnalysis .close-popover", function () {
  1161. $("#tableAnalysis").hide();
  1162. });
  1163. $(document).on("click", "#columnAnalysis .close-popover", function () {
  1164. $("#columnAnalysis").hide();
  1165. });
  1166. $(document).on("shown", "a[data-toggle='tab']:not(.sidetab)", function (e) {
  1167. if ($(e.target).attr("href") == "#log") {
  1168. logsAtEnd = true;
  1169. window.setTimeout(resizeLogs, 150);
  1170. }
  1171. if ($(e.target).attr("href") == "#results" && $(e.relatedTarget).attr("href") == "#columns") {
  1172. if ($("#resultTable .columnSelected").length > 0) {
  1173. var _t = $("#resultTable");
  1174. var _col = _t.find("th:nth-child(" + ($("#resultTable .columnSelected").index() + 1) + ")");
  1175. _t.parent().animate({
  1176. scrollLeft: _col.position().left + _t.parent().scrollLeft() - _t.parent().offset().left - 30
  1177. }, 300);
  1178. }
  1179. }
  1180. if ($(e.target).attr("href") == "#results" || $(e.target).attr("href") == "#recentTab") {
  1181. reinitializeTableExtenders();
  1182. }
  1183. if ($(e.target).attr("href") != "#results"){
  1184. $($(e.target).attr("href")).css('height', 'auto');
  1185. if ($(e.target).attr("href") == "#chart") {
  1186. logGA('results/chart');
  1187. predictGraph();
  1188. }
  1189. if ($(e.target).attr("href") == "#resultTab") {
  1190. reinitializeTable();
  1191. }
  1192. } else {
  1193. reinitializeTable();
  1194. }
  1195. if ($(e.target).attr("href") == "#columnAnalysisTerms") {
  1196. $("#columnAnalysis .filter").removeClass("hide");
  1197. }
  1198. if ($(e.target).attr("href") == "#columnAnalysisStats") {
  1199. $("#columnAnalysis .filter").addClass("hide");
  1200. }
  1201. return e;
  1202. });
  1203. });
  1204. // Codemirror query field
  1205. function getHighlightedQuery() {
  1206. var selection = codeMirror.getSelection();
  1207. if (selection != "") {
  1208. return selection;
  1209. }
  1210. return null;
  1211. }
  1212. function reinitializeTable(max) {
  1213. var _max = max || 10;
  1214. function fn(){
  1215. var container = $($("a[data-toggle='tab']:not(.sidetab)").parent(".active").find("a").attr("href"));
  1216. if ($("#results .dataTables_wrapper").height() > 0) {
  1217. $("#results .dataTables_wrapper").jHueTableScroller({
  1218. minHeight: $(window).height() - 150,
  1219. heightAfterCorrection: 0
  1220. });
  1221. $("#recentTab .dataTables_wrapper").jHueTableScroller({
  1222. minHeight: $(window).height() - 150,
  1223. heightAfterCorrection: 0
  1224. });
  1225. reinitializeTableExtenders();
  1226. container.height($(window).height() - 150);
  1227. $("#results .dataTables_wrapper").jHueScrollUp();
  1228. } else if ($('#resultEmpty').height() > 0) {
  1229. container.height($('#resultEmpty').height());
  1230. } else if ($('#resultExpired').height() > 0) {
  1231. container.height($('#resultExpired').height());
  1232. }
  1233. if ($("#results .dataTables_wrapper").data('original-height') == 0 && --_max != 0) {
  1234. $("#results .dataTables_wrapper").data('original-height', $("#results .dataTables_wrapper").height());
  1235. window.setTimeout(fn, 100);
  1236. }
  1237. if ($("#recentTab .dataTables_wrapper").data('original-height') == 0 && --_max != 0) {
  1238. $("#recentTab .dataTables_wrapper").data('original-height', $("#recentTab .dataTables_wrapper").height());
  1239. window.setTimeout(fn, 100);
  1240. }
  1241. }
  1242. window.setTimeout(fn, 100);
  1243. }
  1244. $(document).ready(function () {
  1245. $.jHueScrollUp();
  1246. var queryPlaceholder = $("<span>").html($("<span>").html("${_('Example: SELECT * FROM tablename, or press CTRL + space')}").text()).text();
  1247. $("#executeQuery").tooltip({
  1248. title: '${_("Press \"tab\", then \"enter\".")}'
  1249. });
  1250. initQueryField();
  1251. var resizeTimeout = -1;
  1252. var winWidth = $(window).width();
  1253. var winHeight = $(window).height();
  1254. $(window).on("resize", function () {
  1255. window.clearTimeout(resizeTimeout);
  1256. resizeTimeout = window.setTimeout(function () {
  1257. // prevents endless loop in IE8
  1258. if (winWidth != $(window).width() || winHeight != $(window).height()) {
  1259. resizeNavigator();
  1260. winWidth = $(window).width();
  1261. winHeight = $(window).height();
  1262. }
  1263. }, 200);
  1264. });
  1265. function initQueryField() {
  1266. if ($("#queryField").val() == "") {
  1267. $("#queryField").val(queryPlaceholder);
  1268. }
  1269. }
  1270. var queryEditor = $("#queryField")[0];
  1271. % if app_name == 'impala':
  1272. var AUTOCOMPLETE_SET = CodeMirror.impalaSQLHint;
  1273. % else:
  1274. var AUTOCOMPLETE_SET = CodeMirror.hiveQLHint;
  1275. % endif
  1276. CodeMirror.onAutocomplete = function (data, from, to) {
  1277. if (data.indexOf("(") > -1){
  1278. codeMirror.setCursor({line: from.line, ch: from.ch + data.length - 1});
  1279. codeMirror.execCommand("autocomplete");
  1280. }
  1281. if (CodeMirror.tableFieldMagic) {
  1282. codeMirror.replaceRange(" ", from, from);
  1283. codeMirror.setCursor(from);
  1284. codeMirror.execCommand("autocomplete");
  1285. }
  1286. };
  1287. $(document).on("error.autocomplete", function(){
  1288. $(".CodeMirror-spinner").remove();
  1289. });
  1290. function splitStatements(hql) {
  1291. var statements = [];
  1292. var current = "";
  1293. var betweenQuotes = null;
  1294. for (var i = 0, len = hql.length; i < len; i++) {
  1295. var c = hql[i];
  1296. current += c;
  1297. if ($.inArray(c, ['"', "'"]) > -1) {
  1298. if (betweenQuotes == c) {
  1299. betweenQuotes = null;
  1300. }
  1301. else if (betweenQuotes == null) {
  1302. betweenQuotes = c;
  1303. }
  1304. }
  1305. else if (c == ";") {
  1306. if (betweenQuotes == null) {
  1307. statements.push(current);
  1308. current = "";
  1309. }
  1310. }
  1311. }
  1312. if (current != "" && current != ";") {
  1313. statements.push(current);
  1314. }
  1315. return statements;
  1316. }
  1317. function getStatementAtCursor() {
  1318. var _pos = codeMirror.indexFromPos(codeMirror.getCursor());
  1319. var _statements = splitStatements(codeMirror.getValue());
  1320. var _cumulativePos = 0;
  1321. var _statementAtCursor = "";
  1322. var _relativePos = 0;
  1323. for (var i = 0; i < _statements.length; i++) {
  1324. if (_cumulativePos + _statements[i].length >= _pos && _statementAtCursor == "") {
  1325. _statementAtCursor = _statements[i].split("\n").join(" ");
  1326. _relativePos = _pos - _cumulativePos;
  1327. }
  1328. _cumulativePos += _statements[i].length;
  1329. }
  1330. return {
  1331. statement: _statementAtCursor,
  1332. relativeIndex: _relativePos
  1333. };
  1334. }
  1335. CodeMirror.commands.autocomplete = function (cm) {
  1336. $(document.body).on("contextmenu", function (e) {
  1337. e.preventDefault(); // prevents native menu on FF for Mac from being shown
  1338. });
  1339. var pos = cm.cursorCoords();
  1340. if ($(".CodeMirror-spinner").length == 0) {
  1341. $("<i class='fa fa-spinner fa-spin CodeMirror-spinner'></i>").appendTo($("body"));
  1342. }
  1343. $(".CodeMirror-spinner").css("top", pos.top + "px").css("left", (pos.left - 4) + "px").show();
  1344. var _statementAtCursor = getStatementAtCursor();
  1345. var _before = _statementAtCursor.statement.substr(0, _statementAtCursor.relativeIndex).replace(/;+$/, "");
  1346. var _after = _statementAtCursor.statement.substr(_statementAtCursor.relativeIndex).replace(/;+$/, "");
  1347. autocompleter.autocomplete(_before, _after, function(suggestions) {
  1348. var isFromDot = _before.match(/.*\.[^ ]*$/) != null;
  1349. var isTable = false;
  1350. var tableFieldMagic = false;
  1351. var hasFromPrefix = false;
  1352. var values = suggestions.map(function(suggestion) {
  1353. if (suggestion.meta === "table") {
  1354. isTable = true; // They're all tables.
  1355. var match = suggestion.value.match(/(\? )?from ([^ ]+)$/i);
  1356. if (match != null) {
  1357. if (typeof match[1] != "undefined") {
  1358. tableFieldMagic = true;
  1359. return match[2];
  1360. } else {
  1361. hasFromPrefix = true;
  1362. }
  1363. }
  1364. return suggestion.value;
  1365. } else {
  1366. return isFromDot ? "." + suggestion.value : suggestion.value;
  1367. }
  1368. }).join(" ");
  1369. if (values.length > 0 && !hasFromPrefix) {
  1370. CodeMirror.fromDot = isFromDot;
  1371. CodeMirror.possibleSoloField = true;
  1372. CodeMirror.tableFieldMagic = tableFieldMagic;
  1373. CodeMirror.possibleTable = isTable && !tableFieldMagic;
  1374. CodeMirror.catalogTables = isTable ? values : "";
  1375. CodeMirror.catalogFields = isTable ? "" : values;
  1376. } else {
  1377. CodeMirror.fromDot = false;
  1378. CodeMirror.possibleSoloField = false;
  1379. CodeMirror.tableFieldMagic = false;
  1380. CodeMirror.possibleTable = false;
  1381. CodeMirror.catalogTables = "";
  1382. CodeMirror.catalogFields = "";
  1383. }
  1384. CodeMirror.showHint(cm, AUTOCOMPLETE_SET);
  1385. });
  1386. };
  1387. codeMirror = CodeMirror(function (elt) {
  1388. queryEditor.parentNode.replaceChild(elt, queryEditor);
  1389. }, {
  1390. value: queryEditor.value,
  1391. readOnly: false,
  1392. lineNumbers: true,
  1393. % if app_name == 'impala':
  1394. mode: "text/x-impalaql",
  1395. % else:
  1396. mode: "text/x-hiveql",
  1397. % endif
  1398. extraKeys: {
  1399. "Ctrl-Space": function () {
  1400. codeMirror.execCommand("autocomplete");
  1401. },
  1402. Tab: function (cm) {
  1403. $("#executeQuery").focus();
  1404. }
  1405. },
  1406. onKeyEvent: function (e, s) {
  1407. if (s.type == "keyup") {
  1408. if (s.keyCode == 190) {
  1409. var _statement = getStatementAtCursor().statement;
  1410. if (_statement.toUpperCase().indexOf("FROM") > -1) {
  1411. window.setTimeout(function () {
  1412. codeMirror.execCommand("autocomplete");
  1413. }, 100); // timeout for IE8
  1414. }
  1415. }
  1416. }
  1417. }
  1418. });
  1419. codeMirror.on("focus", function () {
  1420. if (codeMirror.getValue() == queryPlaceholder) {
  1421. codeMirror.setValue("");
  1422. }
  1423. viewModel.queryEditorBlank(true);
  1424. clearErrorWidgets();
  1425. $("#validationResults").empty();
  1426. });
  1427. % if not (design and design.id) and not ( query_history and query_history.id ):
  1428. if ($.totalStorage(hac_getTotalStorageUserPrefix() + "${app_name}_temp_query") != null && $.totalStorage(hac_getTotalStorageUserPrefix() + "${app_name}_temp_query") != "") {
  1429. viewModel.queryEditorBlank(true);
  1430. codeMirror.setValue($.totalStorage(hac_getTotalStorageUserPrefix() + "${app_name}_temp_query"));
  1431. }
  1432. % endif
  1433. codeMirror.on("blur", function () {
  1434. $(document.body).off("contextmenu");
  1435. });
  1436. codeMirror.on("update", function () {
  1437. if (CURRENT_CODEMIRROR_SIZE == 100 && codeMirror.lineCount() > 7){
  1438. CURRENT_CODEMIRROR_SIZE = 270;
  1439. codeMirror.setSize("99%", CURRENT_CODEMIRROR_SIZE);
  1440. reinitializeTableExtenders();
  1441. }
  1442. });
  1443. $("#download-excel").click(function () {
  1444. if (viewModel.design.results.columns().length > 255) {
  1445. $.jHueNotify.warn("${ _('Results exceeds maximum number of columns permitted by Excel, will truncate results to 255 columns.') }")
  1446. }
  1447. });
  1448. });
  1449. var editables = function() {
  1450. // Edit query name and description.
  1451. $("#query-name").editable({
  1452. validate: function (value) {
  1453. if ($.trim(value) == '') {
  1454. return "${ _('This field is required.') }";
  1455. }
  1456. },
  1457. success: function (response, newValue) {
  1458. viewModel.design.name(newValue);
  1459. },
  1460. emptytext: "${ _('Query name') }"
  1461. });
  1462. $("#query-description").editable({
  1463. success: function (response, newValue) {
  1464. viewModel.design.description(newValue);
  1465. },
  1466. emptytext: "${ _('Empty description') }"
  1467. });
  1468. $(".fileChooser:not(:has(~ button))").after(getFileBrowseButton($(".fileChooser:not(:has(~ button))")));
  1469. };
  1470. $(document).one('fetched.design', editables);
  1471. $(document).one('fetched.query', editables);
  1472. function isNumericColumn(type) {
  1473. return $.inArray(type, ['TINYINT_TYPE', 'SMALLINT_TYPE', 'INT_TYPE', 'BIGINT_TYPE', 'FLOAT_TYPE', 'DOUBLE_TYPE', 'DECIMAL_TYPE', 'TIMESTAMP_TYPE', 'DATE_TYPE']) > -1;
  1474. }
  1475. function isDateTimeColumn(type) {
  1476. return $.inArray(type, ['TIMESTAMP_TYPE', 'DATE_TYPE']) > -1;
  1477. }
  1478. function isStringColumn(type) {
  1479. return !isNumericColumn(type) && !isDateTimeColumn(type);
  1480. }
  1481. var map;
  1482. var graphHasBeenPredicted = false;
  1483. function getMapBounds(lats, lngs) {
  1484. lats = lats.sort();
  1485. lngs = lngs.sort();
  1486. return [
  1487. [lats[lats.length - 1], lngs[lngs.length - 1]], // north-east
  1488. [lats[0], lngs[0]] // south-west
  1489. ]
  1490. }
  1491. function generateGraph(graphType) {
  1492. $("#chart").height(Math.max($(window).height() - $("#blueprint").offset().top + 30, 500));
  1493. $("#chart .alert").addClass("hide");
  1494. if (graphType != "") {
  1495. $("#blueprint").attr("class", "").attr("style", "").empty();
  1496. if (graphType == ko.HUE_CHARTS.TYPES.MAP) {
  1497. if ($("#blueprintLat").val() != "-1" && $("#blueprintLng").val() != "-1") {
  1498. var _latCol = $("#blueprintLat").val() * 1;
  1499. var _lngCol = $("#blueprintLng").val() * 1;
  1500. var _descCol = $("#blueprintDesc").val() * 1;
  1501. var _lats = [];
  1502. var _lngs = [];
  1503. $("#resultTable>tbody>tr>td:nth-child(" + _latCol + ")").each(function (cnt) {
  1504. _lats.push($.trim($(this).text()) * 1);
  1505. });
  1506. $("#resultTable>tbody>tr>td:nth-child(" + _lngCol + ")").each(function (cnt) {
  1507. _lngs.push($.trim($(this).text()) * 1);
  1508. });
  1509. var _koData = [];
  1510. try {
  1511. $("#resultTable>tbody>tr>td:nth-child(" + _latCol + ")").each(function (cnt) {
  1512. if (cnt < 1000) {
  1513. if (_descCol != "-1") {
  1514. _koData.push({ lat: $.trim($(this).text()) * 1, lng: $.trim($("#resultTable>tbody>tr:nth-child(" + (cnt + 1) + ")>td:nth-child(" + _lngCol + ")").text()) * 1, label: $.trim($("#resultTable>tbody>tr:nth-child(" + (cnt + 1) + ")>td:nth-child(" + _descCol + ")").text())});
  1515. }
  1516. else {
  1517. _koData.push({ lat: $.trim($(this).text()) * 1, lng: $.trim($("#resultTable>tbody>tr:nth-child(" + (cnt + 1) + ")>td:nth-child(" + _lngCol + ")").text()) * 1});
  1518. }
  1519. }
  1520. });
  1521. viewModel.chartData(_koData);
  1522. }
  1523. catch (err) {
  1524. if (typeof console != "undefined") {
  1525. console.error(err);
  1526. }
  1527. }
  1528. if ($("#resultTable>tbody>tr>td:nth-child(" + _latCol + ")").length > 1000){
  1529. $("#chart .alert").removeClass("hide");
  1530. }
  1531. }
  1532. else {
  1533. $("#blueprint").addClass("empty").css("text-align", "center").text("${_("Please select the latitude and longitude columns.")}");
  1534. }
  1535. }
  1536. else {
  1537. if ($("#blueprintX").val() != "-1" && $("#blueprintY").val() != "-1") {
  1538. var _x = $("#blueprintX").val() * 1;
  1539. var _y = $("#blueprintY").val() * 1;
  1540. var _koData = [];
  1541. $("#resultTable>tbody>tr>td:nth-child(" + _x + ")").each(function (cnt) {
  1542. if (cnt < 1000) {
  1543. _koData.push({ value: $.trim($(this).text()), count: $.trim($("#resultTable>tbody>tr:nth-child(" + (cnt + 1) + ")>td:nth-child(" + _y + ")").text()) * 1});
  1544. }
  1545. });
  1546. viewModel.chartData(_koData);
  1547. if ($("#resultTable>tbody>tr>td:nth-child(" + _x + ")").length > 1000){
  1548. $("#chart .alert").removeClass("hide");
  1549. }
  1550. }
  1551. else {
  1552. $("#blueprint").addClass("empty").css("text-align", "center").text("${_("Please select the columns you would like to see in this chart.")}");
  1553. }
  1554. }
  1555. }
  1556. }
  1557. function getGraphType() {
  1558. var _type = "";
  1559. if ($("#blueprintBars").hasClass("active")) {
  1560. _type = ko.HUE_CHARTS.TYPES.BARCHART;
  1561. }
  1562. if ($("#blueprintLines").hasClass("active")) {
  1563. _type = ko.HUE_CHARTS.TYPES.LINECHART;
  1564. }
  1565. if ($("#blueprintMap").hasClass("active")) {
  1566. _type = ko.HUE_CHARTS.TYPES.MAP;
  1567. }
  1568. if ($("#blueprintPie").hasClass("active")) {
  1569. _type = ko.HUE_CHARTS.TYPES.PIECHART;
  1570. }
  1571. viewModel.chartType(_type);
  1572. return _type;
  1573. }
  1574. function predictGraph() {
  1575. if (!graphHasBeenPredicted) {
  1576. graphHasBeenPredicted = true;
  1577. var _firstAllString, _firstAllNumeric;
  1578. var _cols = viewModel.design.results.columns();
  1579. $(_cols).each(function (cnt, col) {
  1580. if (cnt > 0){
  1581. if (_firstAllString == null && !isNumericColumn(col.type)) {
  1582. _firstAllString = cnt + 1;
  1583. }
  1584. if (_firstAllNumeric == null && isNumericColumn(col.type)) {
  1585. _firstAllNumeric = cnt + 1;
  1586. }
  1587. }
  1588. });
  1589. if (_firstAllString != null && _firstAllNumeric != null) {
  1590. $("#blueprintBars").addClass("active");
  1591. $("#blueprintLines").removeClass("active");
  1592. $("#blueprintPie").removeClass("active");
  1593. $("#blueprintMap").removeClass("active");
  1594. $("#blueprintAxis").removeClass("hide");
  1595. $("#blueprintLatLng").addClass("hide");
  1596. $("#blueprintX").val(_firstAllString);
  1597. $("#blueprintY").val(_firstAllNumeric);
  1598. }
  1599. }
  1600. generateGraph(getGraphType());
  1601. }
  1602. // Logs
  1603. var logsAtEnd = true;
  1604. $(document).ready(function () {
  1605. var labels = {
  1606. MRJOB: "${_('MR Job')}",
  1607. MRJOBS: "${_('MR Jobs')}"
  1608. };
  1609. $(window).resize(function () {
  1610. resizeLogs();
  1611. });
  1612. $("a[href='#log']").on("shown", function () {
  1613. resizeLogs();
  1614. });
  1615. % if app_name == 'impala':
  1616. $("a[href='#sessionTab']").on("shown", function () {
  1617. // get the impala session info
  1618. viewModel.fetchImpalaSession();
  1619. });
  1620. % endif
  1621. $(".blueprintSelect").on("change", function () {
  1622. generateGraph(getGraphType())
  1623. });
  1624. $("#blueprintBars").on("click", function () {
  1625. $("#blueprintAxis").removeClass("hide");
  1626. $("#blueprintLatLng").addClass("hide");
  1627. viewModel.chartType(ko.HUE_CHARTS.TYPES.BARCHART);
  1628. generateGraph(ko.HUE_CHARTS.TYPES.BARCHART)
  1629. });
  1630. $("#blueprintLines").on("click", function () {
  1631. $("#blueprintAxis").removeClass("hide");
  1632. $("#blueprintLatLng").addClass("hide");
  1633. viewModel.chartType(ko.HUE_CHARTS.TYPES.LINECHART);
  1634. generateGraph(ko.HUE_CHARTS.TYPES.LINECHART)
  1635. });
  1636. $("#blueprintPie").on("click", function () {
  1637. $("#blueprintAxis").removeClass("hide");
  1638. $("#blueprintLatLng").addClass("hide");
  1639. viewModel.chartType(ko.HUE_CHARTS.TYPES.PIECHART);
  1640. generateGraph(ko.HUE_CHARTS.TYPES.PIECHART)
  1641. });
  1642. $("#blueprintMap").on("click", function () {
  1643. $("#blueprintAxis").addClass("hide");
  1644. $("#blueprintLatLng").removeClass("hide");
  1645. viewModel.chartType(ko.HUE_CHARTS.TYPES.MAP);
  1646. generateGraph(ko.HUE_CHARTS.TYPES.MAP)
  1647. });
  1648. $("#blueprintNoSort").on("click", function () {
  1649. viewModel.chartSorting("none");
  1650. redrawChart();
  1651. });
  1652. $("#blueprintSortAsc").on("click", function () {
  1653. viewModel.chartSorting("asc");
  1654. redrawChart();
  1655. });
  1656. $("#blueprintSortDesc").on("click", function () {
  1657. viewModel.chartSorting("desc");
  1658. redrawChart();
  1659. });
  1660. function redrawChart() {
  1661. generateGraph(viewModel.chartType());
  1662. }
  1663. $("#log pre:eq(1)").scroll(function () {
  1664. if ($(this).scrollTop() + $(this).height() + 20 >= $(this)[0].scrollHeight) {
  1665. logsAtEnd = true;
  1666. }
  1667. else {
  1668. logsAtEnd = false;
  1669. }
  1670. });
  1671. viewModel.design.watch.logs.subscribe(function(val){
  1672. var _logsEl = $("#log pre:eq(1)");
  1673. if (logsAtEnd && _logsEl[0]) {
  1674. _logsEl.scrollTop(_logsEl[0].scrollHeight - _logsEl.height());
  1675. }
  1676. window.setTimeout(resizeLogs, 10);
  1677. });
  1678. viewModel.design.results.columns.subscribe(function(val){
  1679. $("*[rel=columntooltip]").tooltip({
  1680. delay: {show: 500}
  1681. });
  1682. $("a[data-row-selector='true']").jHueRowSelector();
  1683. });
  1684. });
  1685. function resizeLogs() {
  1686. // Use fixed subtraction since logs aren't always visible.
  1687. if ($("#log pre:eq(1)").length > 0) {
  1688. var _height = Math.max($(window).height() - $("#log pre:eq(1)").offset().top, 250);
  1689. $("#log").height(_height - 10);
  1690. $("#log pre:eq(1)").css("overflow", "auto").height(_height - 50);
  1691. }
  1692. }
  1693. // Result Datatable
  1694. function cleanResultsTable() {
  1695. if (dataTable) {
  1696. viewModel.design.results.rows([]);
  1697. dataTable.fnClearTable();
  1698. dataTable.fnDestroy();
  1699. viewModel.design.results.columns.valueHasMutated();
  1700. viewModel.design.results.rows.valueHasMutated();
  1701. dataTable = null;
  1702. }
  1703. }
  1704. function addRowNumberToResults(data, startIndex) {
  1705. var _tmpdata = [];
  1706. $(data).each(function(cnt, item){
  1707. item.unshift(cnt + startIndex + 1);
  1708. _tmpdata.push(item);
  1709. });
  1710. return _tmpdata;
  1711. }
  1712. var _scrollTimeout = -1;
  1713. function datatableScroll() {
  1714. viewModel.scrollNotWorking(false);
  1715. // Automatic results grower
  1716. var dataTableEl = $("#results .dataTables_wrapper");
  1717. var _lastScrollPosition = dataTableEl.data("scrollPosition") != null ? dataTableEl.data("scrollPosition") : 0;
  1718. window.clearTimeout(_scrollTimeout);
  1719. _scrollTimeout = window.setTimeout(function(){
  1720. dataTableEl.data("scrollPosition", dataTableEl.scrollTop());
  1721. if (_lastScrollPosition != dataTableEl.scrollTop() && dataTableEl.scrollTop() + dataTableEl.outerHeight() + 20 > dataTableEl[0].scrollHeight && dataTable && viewModel.hasMoreResults()) {
  1722. dataTableEl.animate({opacity: '0.55'}, 200);
  1723. viewModel.fetchResults();
  1724. }
  1725. }, 100);
  1726. }
  1727. var firstFnDrawcallback = false;
  1728. var manualFetchResultCounter = 0;
  1729. function addResults(viewModel, dataTable, startRow, nextRow) {
  1730. if (startRow == 0) {
  1731. firstFnDrawcallback = true;
  1732. }
  1733. dataTable.fnAddData(addRowNumberToResults(viewModel.design.results.rows.slice(startRow, nextRow), startRow));
  1734. % if app_name == 'impala':
  1735. manualFetchResultCounter += (nextRow - startRow);
  1736. if (manualFetchResultCounter < 100 && viewModel.scrollNotWorking() && viewModel.hasMoreResults()){
  1737. manualFetch();
  1738. }
  1739. else {
  1740. manualFetchResultCounter = 0;
  1741. }
  1742. %endif
  1743. }
  1744. function resultsTable(e, data) {
  1745. $("#results .dataTables_wrapper").animate({opacity: '1'}, 50);
  1746. $.totalStorage(hac_getTotalStorageUserPrefix() + "${app_name}_temp_query", null);
  1747. if (viewModel.design.results.columns().length > 0) {
  1748. if (!dataTable) {
  1749. dataTable = $("#resultTable").dataTable({
  1750. "bPaginate": false,
  1751. "bLengthChange": false,
  1752. "bInfo": false,
  1753. "bDestroy": true,
  1754. "bAutoWidth": false,
  1755. "oLanguage": {
  1756. "sEmptyTable": "${_('No data available')}",
  1757. "sZeroRecords": "${_('No matching records')}"
  1758. },
  1759. "fnDrawCallback": function (oSettings) {
  1760. reinitializeTableExtenders();
  1761. if (firstFnDrawcallback) {
  1762. firstFnDrawcallback = false;
  1763. window.setTimeout(reinitializeTable, 100);
  1764. }
  1765. },
  1766. "aoColumnDefs": [
  1767. {
  1768. "sType": "numeric",
  1769. "aTargets": [ "sort-numeric" ]
  1770. },
  1771. {
  1772. "sType": "string",
  1773. "aTargets": [ "sort-string" ]
  1774. },
  1775. {
  1776. "sType": "date",
  1777. "aTargets": [ "sort-date" ]
  1778. }
  1779. ]
  1780. });
  1781. $(".dataTables_filter").hide();
  1782. reinitializeTable();
  1783. var _options = '<option value="-1">${ _("Please select a column")}</option>';
  1784. $(viewModel.design.results.columns()).each(function(cnt, item){
  1785. if (cnt > 0){
  1786. _options += '<option value="'+(cnt + 1)+'">'+ item.name +'</option>';
  1787. }
  1788. });
  1789. $(".blueprintSelect").html(_options);
  1790. // Automatic results grower
  1791. var dataTableEl = $("#results .dataTables_wrapper");
  1792. dataTableEl.on("scroll", datatableScroll);
  1793. }
  1794. addResults(viewModel, dataTable, data.start_row, data.next_row);
  1795. }
  1796. }
  1797. function manualFetch() {
  1798. $("#results .dataTables_wrapper").css("opacity", "0.55");
  1799. viewModel.fetchResults();
  1800. }
  1801. $(document).on('execute.query', cleanResultsTable);
  1802. $(document).on('explain.query', cleanResultsTable);
  1803. $(document).on('fetched.results', resultsTable);
  1804. var selectedLine = -1;
  1805. var errorWidgets = [];
  1806. function clearErrorWidgets() {
  1807. $(".jHueTableExtenderClonedContainer").hide();
  1808. $.each(errorWidgets, function(index, errorWidget) {
  1809. errorWidget.clear();
  1810. });
  1811. errorWidgets = [];
  1812. }
  1813. $(document).on('execute.query', clearErrorWidgets);
  1814. $(document).on('error.query', function () {
  1815. $.each(errorWidgets, function(index, el) {
  1816. $(el).remove();
  1817. errorWidgets = [];
  1818. });
  1819. // Move error to codeMirror if we know the line number
  1820. $.each($(".queryErrorMessage"), function(index, el) {
  1821. var err = $(el).text();
  1822. var firstPos = err.toLowerCase().indexOf("line");
  1823. if (firstPos > -1) {
  1824. selectedLine = $.trim(err.substring(err.indexOf(" ", firstPos), err.indexOf(":", firstPos))) * 1;
  1825. if (codeMirror.getSelection()) {
  1826. selectedLine += codeMirror.getCursor(true).line;
  1827. }
  1828. errorWidgets.push(
  1829. codeMirror.addLineWidget(
  1830. selectedLine > 0 ? selectedLine - 1 : selectedLine,
  1831. $("<div>").addClass("editorError").html("<i class='fa fa-exclamation-circle'></i> " + err)[0], {
  1832. coverGutter: true,
  1833. noHScroll: true
  1834. }
  1835. )
  1836. );
  1837. $(el).hide();
  1838. }
  1839. });
  1840. reinitializeTableExtenders();
  1841. });
  1842. // Save
  1843. function trySaveDesign() {
  1844. var query = codeMirror.getValue();
  1845. viewModel.design.query.value(query);
  1846. if (viewModel.design.id() && viewModel.design.id() != -1) {
  1847. viewModel.saveDesign();
  1848. logGA('design/save');
  1849. }
  1850. }
  1851. function saveAsModal() {
  1852. var query = getHighlightedQuery() || codeMirror.getValue();
  1853. viewModel.design.query.value(query);
  1854. $('#saveAs').modal('show');
  1855. }
  1856. function trySaveAsDesign() {
  1857. if (viewModel.design.query.value() && viewModel.design.name()) {
  1858. viewModel.design.id(-1);
  1859. viewModel.saveDesign();
  1860. $('#saveas-query-name').removeClass('error');
  1861. $('#saveAs').modal('hide');
  1862. logGA('design/save-as');
  1863. } else if (viewModel.design.name()) {
  1864. $.jHueNotify.error("${_('No query provided to save.')}");
  1865. $('#saveAs').modal('hide');
  1866. } else {
  1867. $('#saveas-query-name').addClass('error');
  1868. }
  1869. }
  1870. function saveResultsModal() {
  1871. $("#saveResultsModal .loader").hide();
  1872. $('#saveResultsModal').modal('show');
  1873. }
  1874. function trySaveResults() {
  1875. var deferred = viewModel.saveResults();
  1876. if (deferred) {
  1877. $("#saveResultsModal button.btn-primary").button('loading');
  1878. $("#saveResultsModal .loader").show();
  1879. deferred.done(function() {
  1880. $("#saveResultsModal button.btn-primary").button('reset');
  1881. $("#saveResultsModal .loader").hide();
  1882. });
  1883. }
  1884. logGA('results/save');
  1885. }
  1886. $(document).on('saved.results', function() {
  1887. $('#saveResultsModal').modal('hide');
  1888. });
  1889. // Querying and click events.
  1890. function tryExecuteQuery() {
  1891. viewModel.scrollNotWorking(true);
  1892. $("#results .dataTables_wrapper").off("scroll", datatableScroll);
  1893. $(".jHueTableExtenderClonedContainer").hide();
  1894. $(".tooltip").remove();
  1895. var query = getHighlightedQuery() || codeMirror.getValue();
  1896. viewModel.design.query.value(query);
  1897. if ($("#results .dataTables_wrapper").length > 0) { // forces results to be up
  1898. $("#results .dataTables_wrapper").scrollTop(0);
  1899. }
  1900. if ($("#recentQueries .dataTables_wrapper").length > 0) { // forces results to be up
  1901. $("#recentQueries .dataTables_wrapper").scrollTop(0);
  1902. }
  1903. renderRecent();
  1904. clickHard('.resultsContainer .nav-tabs a[href="#log"]');
  1905. graphHasBeenPredicted = false;
  1906. if (viewModel.design.isParameterized()) {
  1907. viewModel.fetchParameters();
  1908. } else {
  1909. viewModel.executeQuery();
  1910. }
  1911. logGA('query/execute');
  1912. }
  1913. function tryExecuteNextStatement() {
  1914. viewModel.scrollNotWorking(true);
  1915. var query = getHighlightedQuery() || codeMirror.getValue();
  1916. // If we highlight a part of query, we update the query and restart the query history
  1917. // In the other case we update the query but continue at the same statement we were
  1918. if (viewModel.design.query.value() != query) {
  1919. viewModel.design.query.value(query);
  1920. if (getHighlightedQuery()) {
  1921. viewModel.executeQuery();
  1922. } else {
  1923. viewModel.executeNextStatement();
  1924. }
  1925. } else {
  1926. viewModel.executeNextStatement();
  1927. }
  1928. logGA('query/execute_next');
  1929. }
  1930. function tryExecuteParameterizedQuery() {
  1931. viewModel.scrollNotWorking(true);
  1932. $(".tooltip").remove();
  1933. viewModel.executeQuery();
  1934. routie('query');
  1935. }
  1936. function tryExplainQuery() {
  1937. $(".tooltip").remove();
  1938. var query = getHighlightedQuery() || codeMirror.getValue();
  1939. viewModel.design.query.value(query);
  1940. viewModel.explainQuery();
  1941. logGA('query/explain');
  1942. }
  1943. function tryExplainParameterizedQuery() {
  1944. $(".tooltip").remove();
  1945. viewModel.explainQuery();
  1946. routie('query');
  1947. }
  1948. function tryCancelQuery() {
  1949. $(".tooltip").remove();
  1950. viewModel.cancelQuery();
  1951. }
  1952. function createNewQuery() {
  1953. $.totalStorage(hac_getTotalStorageUserPrefix() + "${app_name}_temp_query", null);
  1954. location.href="${ url(app_name + ':execute_query') }";
  1955. }
  1956. // Server error handling.
  1957. $(document).on('server.error', function (e, data) {
  1958. $(document).trigger('error', "${_('Server error occurred: ')}" + data.message ? data.message : data.error);
  1959. });
  1960. $(document).on('server.unmanageable_error', function (e, responseText) {
  1961. var message = responseText;
  1962. if (! message) {
  1963. message = '${ _("Hue server is probably down.") }';
  1964. }
  1965. $(document).trigger('error', "${_('Unmanageable server error occurred: ')}" + message);
  1966. });
  1967. // Other
  1968. $(document).on('saved.design', function (e, id) {
  1969. $(document).trigger('info', "${_('Query saved.')}");
  1970. window.location.href = "/${ app_name }/execute/design/" + id;
  1971. });
  1972. $(document).on('error_save.design', function (e, message) {
  1973. var _message = "${_('Could not save design')}";
  1974. if (message) {
  1975. _message += ": " + message;
  1976. }
  1977. $(document).trigger('error', _message);
  1978. });
  1979. $(document).on('error_save.results', function (e, message) {
  1980. var _message = "${_('Could not save results')}";
  1981. if (message) {
  1982. _message += ": " + message;
  1983. }
  1984. $(document).trigger('error', _message);
  1985. });
  1986. $(document).on('error_cancel.query', function (e, message) {
  1987. $(document).trigger("error", "${ _('Problem: ') }" + message);
  1988. });
  1989. $(document).on('cancelled.query', function (e) {
  1990. $(document).trigger("info", "${ _('Query canceled!') }")
  1991. });
  1992. function updateSidebarTooltips(selector) {
  1993. $(selector).each(function(){
  1994. $(this).tooltip({
  1995. placement: "right",
  1996. title: $(this).val()
  1997. }).attr('data-original-title', $(this).val()).tooltip('fixTitle');
  1998. });
  1999. }
  2000. $(document).ready(function () {
  2001. $("*[rel=tooltip]").tooltip({
  2002. placement: 'bottom'
  2003. });
  2004. // hack for select default rendered fields
  2005. $("select").addClass("input-medium");
  2006. // Type ahead for settings.
  2007. $.getJSON("${ url(app_name + ':configuration') }", function (data) {
  2008. $(".settingsField").typeahead({
  2009. source: $.map(data.config_values, function (value, key) {
  2010. return value.key;
  2011. })
  2012. });
  2013. });
  2014. $("#help").popover({
  2015. 'title': "${_('Did you know?')}",
  2016. 'content': $("#help-content").html(),
  2017. 'trigger': 'hover',
  2018. 'placement': 'left',
  2019. 'html': true
  2020. });
  2021. $("#hdfs-directory-help").popover({
  2022. 'title': "${_('Did you know?')}",
  2023. 'content': $("#hdfs-directory-help-content").html(),
  2024. 'trigger': 'hover',
  2025. 'placement': 'right',
  2026. 'html': true
  2027. });
  2028. $(document).on('click', '#save-results-simple', function() {
  2029. $('#save-results-advanced').removeClass('hide');
  2030. $('#save-results-simple').addClass('hide');
  2031. $('#saveResultsForm .advanced').addClass('hide');
  2032. });
  2033. $(document).on('click', '#save-results-advanced', function() {
  2034. $('#save-results-advanced').addClass('hide');
  2035. $('#save-results-simple').removeClass('hide');
  2036. $('#saveResultsForm .advanced').removeClass('hide');
  2037. });
  2038. $(document).on("change", ".settingsField", function(){
  2039. updateSidebarTooltips(".settingsField");
  2040. });
  2041. $(document).on("change", ".settingValuesField", function(){
  2042. updateSidebarTooltips(".settingValuesField");
  2043. });
  2044. $(document).on("change", ".filesField", function(){
  2045. updateSidebarTooltips(".filesField");
  2046. });
  2047. $(document).on("change", ".functionsField", function(){
  2048. updateSidebarTooltips(".functionsField");
  2049. });
  2050. $(document).on("change", ".classNamesField", function(){
  2051. updateSidebarTooltips(".classNamesField");
  2052. });
  2053. // loads default
  2054. updateSidebarTooltips(".settingsField");
  2055. updateSidebarTooltips(".settingValuesField");
  2056. updateSidebarTooltips(".filesField");
  2057. updateSidebarTooltips(".functionsField");
  2058. updateSidebarTooltips(".classNamesField");
  2059. });
  2060. % if app_name == 'impala':
  2061. $(document).ready(function () {
  2062. $("#downloadQuery").click(function () {
  2063. $("<input>").attr("type", "hidden").attr("name", "button-submit").attr("value", "Execute").appendTo($("#advancedSettingsForm"));
  2064. $("<input>").attr("type", "hidden").attr("name", "download").attr("value", "true").appendTo($("#advancedSettingsForm"));
  2065. tryExecuteQuery();
  2066. });
  2067. $("#refresh-dyk").popover({
  2068. 'title': "${_('Missing some tables? In order to update the list of tables/metadata seen by Impala, execute one of these queries:')}",
  2069. 'content': $("#refresh-content").html(),
  2070. 'trigger': 'hover',
  2071. 'html': true
  2072. });
  2073. $("#refresh-tip").popover({
  2074. 'title': "${_('Missing some tables? In order to update the list of tables/metadata seen by Impala, execute one of these queries:')}",
  2075. 'content': $("#refresh-content").html(),
  2076. 'trigger': 'hover',
  2077. 'html': true
  2078. });
  2079. });
  2080. % endif
  2081. <%
  2082. if app_name == 'impala':
  2083. from impala import conf as impala_conf
  2084. %>
  2085. % if ( app_name == 'beeswax' and beeswax_conf.CLOSE_QUERIES.get() ) or ( app_name == 'impala' and impala_conf.CLOSE_QUERIES.get() ):
  2086. $(document).ready(function () {
  2087. $(document).on('explain.query', function() {
  2088. viewModel.closeQuery();
  2089. });
  2090. $(document).on('execute.query', function() {
  2091. viewModel.closeQuery();
  2092. });
  2093. // Tricks for not triggering the closing of the query on download
  2094. $("a.download").hover(function(){
  2095. window.onbeforeunload = null;
  2096. },function() {
  2097. window.onbeforeunload = $(window).data('beforeunload');
  2098. }
  2099. );
  2100. });
  2101. // Close the query when leaving the page, backup for later when disabling the close before downloading results.
  2102. window.onbeforeunload = function(e) {
  2103. viewModel.closeQuery();
  2104. };
  2105. $(window).data('beforeunload', window.onbeforeunload);
  2106. % endif
  2107. $(".folderChooser:not(:has(~ button))").after(getFolderBrowseButton($(".folderChooser:not(:has(~ button))"), true));
  2108. $(".pathChooser:not(:has(~ button))").after(getPathBrowseButton($(".pathChooser:not(:has(~ button))"), true));
  2109. // Routie
  2110. $(document).ready(function () {
  2111. function queryPageComponents() {
  2112. $('#advanced-settings').show();
  2113. $('#navigator').show();
  2114. $('#queryContainer').show();
  2115. $('#resizePanel').show();
  2116. $('a[href="#query"]').parent().show();
  2117. }
  2118. function watchPageComponents() {
  2119. $('#advanced-settings').hide();
  2120. $('#navigator').hide();
  2121. $('#queryContainer').hide();
  2122. $('#resizePanel').hide();
  2123. $('a[href="#query"]').parent().hide();
  2124. $('a[href="#recentTab"]').parent().hide();
  2125. }
  2126. function queryPage() {
  2127. queryPageComponents();
  2128. $('.resultsContainer .watch-query').hide();
  2129. $('.resultsContainer .view-query-results').hide();
  2130. }
  2131. function queryLogPage() {
  2132. queryPageComponents();
  2133. $('.resultsContainer .watch-query').show();
  2134. $('.resultsContainer .view-query-results').hide();
  2135. }
  2136. function queryResultsPage() {
  2137. queryPageComponents();
  2138. $('.resultsContainer .watch-query').hide();
  2139. $('.resultsContainer .view-query-results').show();
  2140. }
  2141. function parametersPage() {
  2142. queryPageComponents();
  2143. $('.resultsContainer .watch-query').hide();
  2144. $('.resultsContainer .view-query-results').hide();
  2145. }
  2146. function watchLogsPage() {
  2147. watchPageComponents();
  2148. $('.resultsContainer .watch-query').show();
  2149. $('.resultsContainer .view-query-results').hide();
  2150. }
  2151. function watchResultsPage() {
  2152. watchPageComponents();
  2153. $('.resultsContainer .watch-query').hide();
  2154. $('.resultsContainer .view-query-results').show();
  2155. }
  2156. routie({
  2157. 'query': function () {
  2158. showSection('query-editor');
  2159. queryPage();
  2160. codeMirror.setSize("99%", CURRENT_CODEMIRROR_SIZE);
  2161. placeResizePanelHandle();
  2162. },
  2163. 'query/execute/params': function () {
  2164. if (viewModel.design.parameters().length == 0) {
  2165. routie('query');
  2166. }
  2167. showSection('execute-parameter-selection');
  2168. parametersPage();
  2169. },
  2170. 'query/explain/params': function () {
  2171. if (viewModel.design.parameters().length == 0) {
  2172. routie('query');
  2173. }
  2174. showSection('explain-parameter-selection');
  2175. parametersPage();
  2176. },
  2177. 'query/logs': function () {
  2178. if (viewModel.design.watch.logs().length == 0 && viewModel.design.watch.errors().length == 0) {
  2179. routie('query');
  2180. }
  2181. showSection('query-editor');
  2182. queryLogPage();
  2183. clickHard('.resultsContainer .nav-tabs a[href="#log"]');
  2184. },
  2185. 'query/results': function () {
  2186. showSection('query-editor');
  2187. queryResultsPage();
  2188. clickHard('.resultsContainer .nav-tabs a[href="#results"]');
  2189. renderRecent();
  2190. placeResizePanelHandle();
  2191. logGA('query/results');
  2192. },
  2193. 'query/explanation': function () {
  2194. if (! viewModel.design.results.explanation()) {
  2195. routie('query');
  2196. }
  2197. showSection('query-editor');
  2198. queryResultsPage();
  2199. clickHard('.resultsContainer .nav-tabs a[href="#explanation"]');
  2200. },
  2201. 'watch/logs': function() {
  2202. showSection('query-editor');
  2203. watchLogsPage();
  2204. clickHard('.resultsContainer .nav-tabs a[href="#log"]');
  2205. logGA('watch/logs');
  2206. },
  2207. 'watch/results': function() {
  2208. showSection('query-editor');
  2209. watchResultsPage();
  2210. clickHard('.resultsContainer .nav-tabs a[href="#results"]');
  2211. logGA('watch/results');
  2212. },
  2213. '*': function () {
  2214. routie('query');
  2215. }
  2216. });
  2217. });
  2218. // Event setup
  2219. function queryEvents() {
  2220. $(document).on('fetched.parameters', function () {
  2221. if (viewModel.design.parameters().length > 0) {
  2222. routie('query/execute/params');
  2223. } else {
  2224. viewModel.executeQuery();
  2225. }
  2226. });
  2227. $(document).on('explained.query', function () {
  2228. routie('query/explanation');
  2229. });
  2230. $(document).on('watched.query', function (e, data) {
  2231. if (data.status != 2) {
  2232. if (data.status && data.status && data.status != 0) {
  2233. viewModel.design.watch.errors.push(data.error || data.message);
  2234. }
  2235. }
  2236. routie('query/logs');
  2237. });
  2238. $(document).on('error_watch.query', function () {
  2239. routie('query/logs');
  2240. });
  2241. $(document).on('fetched.results', function () {
  2242. routie('query/results');
  2243. });
  2244. $(document).on('execute.query', function() {
  2245. routie('query');
  2246. });
  2247. $(document).ready(function() {
  2248. routie('query');
  2249. });
  2250. }
  2251. function watchEvents() {
  2252. $(document).ready(function() {
  2253. routie('watch/logs');
  2254. });
  2255. $(document).on('error_watch.query', function () {
  2256. routie('watch/logs');
  2257. });
  2258. $(document).on('fetched.results', function () {
  2259. routie('watch/results');
  2260. });
  2261. }
  2262. function cacheQueryTextEvents() {
  2263. var _waitForCodemirrorInit = -1;
  2264. _waitForCodemirrorInit = window.setInterval(function () {
  2265. if (typeof codeMirror != "undefined") {
  2266. codeMirror.on("change", function () {
  2267. $(".query").val(codeMirror.getValue());
  2268. $.totalStorage(hac_getTotalStorageUserPrefix() + "${app_name}_temp_query", codeMirror.getValue());
  2269. });
  2270. window.clearInterval(_waitForCodemirrorInit);
  2271. }
  2272. }, 100);
  2273. }
  2274. function loadDesign(design_id) {
  2275. viewModel.design.id(design_id);
  2276. viewModel.fetchDesign();
  2277. setupCodeMirrorSubscription();
  2278. }
  2279. function loadQueryHistory(query_history_id) {
  2280. viewModel.design.history.id(query_history_id);
  2281. viewModel.fetchQueryHistory();
  2282. setupCodeMirrorSubscription();
  2283. }
  2284. function setupCodeMirrorSubscription() {
  2285. var codeMirrorSubscription = viewModel.design.query.value.subscribe(function (value) {
  2286. viewModel.queryEditorBlank(true);
  2287. var _waitForCodemirrorInit = -1;
  2288. _waitForCodemirrorInit = window.setInterval(function () {
  2289. if (typeof codeMirror != "undefined") {
  2290. codeMirror.setValue(value);
  2291. codeMirrorSubscription.dispose();
  2292. window.clearInterval(_waitForCodemirrorInit);
  2293. }
  2294. }, 100);
  2295. });
  2296. }
  2297. // Knockout
  2298. viewModel = new BeeswaxViewModel("${app_name}", assistHelper);
  2299. ko.applyBindings(viewModel, $("#beeswax-execute")[0]);
  2300. shareViewModel = initSharing("#documentShareModal");
  2301. shareViewModel.setDocId(${doc_id});
  2302. % if not beeswax_conf.USE_GET_LOG_API.get() and app_name != 'impala':
  2303. viewModel.shouldAppendLogs = true;
  2304. % endif
  2305. % if query_history:
  2306. loadQueryHistory(${query_history.id});
  2307. % elif design.id:
  2308. loadDesign(${design.id});
  2309. % else:
  2310. $(document).ready(cacheQueryTextEvents);
  2311. % endif
  2312. viewModel.design.fileResources.values.subscribe(function() {
  2313. // File chooser button for file resources.
  2314. $(".fileChooser:not(:has(~ button))").after(getFileBrowseButton($(".fileChooser:not(:has(~ button))")));
  2315. });
  2316. % if action == 'watch-results':
  2317. $(document).ready(watchEvents);
  2318. $(document).one('fetched.query', function(e) {
  2319. viewModel.watchQueryLoop();
  2320. cacheQueryTextEvents();
  2321. });
  2322. % elif action == 'watch-redirect':
  2323. $(document).ready(watchEvents);
  2324. $(document).one('fetched.query', function(e) {
  2325. viewModel.watchQueryLoop();
  2326. cacheQueryTextEvents();
  2327. });
  2328. $(document).on('stop_watch.query', function(e) {
  2329. if (viewModel.design.results.errors().length == 0) {
  2330. window.setTimeout(function(){
  2331. window.location.href = "${request.GET['on_success_url']}";
  2332. }, 200);
  2333. }
  2334. });
  2335. % elif action == 'editor-results':
  2336. $(document).ready(queryEvents);
  2337. $(document).one('fetched.query', function(e) {
  2338. viewModel.watchQueryLoop();
  2339. cacheQueryTextEvents();
  2340. });
  2341. % elif action == 'editor-expired-results':
  2342. $(document).ready(queryEvents);
  2343. $(document).one('fetched.query', function(e) {
  2344. viewModel.design.results.expired(true);
  2345. $(document).trigger('fetched.results', [ [] ]);
  2346. cacheQueryTextEvents();
  2347. });
  2348. % else:
  2349. $(document).ready(queryEvents);
  2350. % endif
  2351. // chart related stuff
  2352. function pieChartDataTransformer(data) {
  2353. var _data = [];
  2354. $(data.counts()).each(function (cnt, item) {
  2355. _data.push({
  2356. label: item.value,
  2357. value: item.count,
  2358. obj: item
  2359. });
  2360. });
  2361. if (viewModel.chartSorting() == "asc"){
  2362. _data.sort(function(a, b){
  2363. return a.value - b.value
  2364. });
  2365. }
  2366. if (viewModel.chartSorting() == "desc"){
  2367. _data.sort(function(a, b){
  2368. return b.value - a.value
  2369. });
  2370. }
  2371. return _data;
  2372. }
  2373. function leafletMapChartDataTransformer(data) {
  2374. if (data != null && data.counts != null) return data.counts();
  2375. }
  2376. function barChartDataTransformer(rawDatum) {
  2377. var _datum = [];
  2378. var _data = [];
  2379. $(rawDatum.counts()).each(function (cnt, item) {
  2380. if (typeof item.from != "undefined") {
  2381. _data.push({
  2382. series: 0,
  2383. x: item.from,
  2384. x_end: item.to,
  2385. y: item.value,
  2386. obj: item
  2387. });
  2388. }
  2389. else {
  2390. _data.push({
  2391. series: 0,
  2392. x: item.value,
  2393. y: item.count,
  2394. obj: item
  2395. });
  2396. }
  2397. });
  2398. if (viewModel.chartSorting() == "asc"){
  2399. _data.sort(function(a, b){
  2400. return a.y - b.y
  2401. });
  2402. }
  2403. if (viewModel.chartSorting() == "desc"){
  2404. _data.sort(function(a, b){
  2405. return b.y - a.y
  2406. });
  2407. }
  2408. _datum.push({
  2409. key: $("#blueprintY option:selected").text(),
  2410. values: _data
  2411. });
  2412. return _datum;
  2413. }
  2414. function lineChartDataTransformer(rawDatum) {
  2415. var _datum = [];
  2416. var _data = [];
  2417. $(rawDatum.counts()).each(function (cnt, item) {
  2418. if (typeof item.from != "undefined") {
  2419. _data.push({
  2420. series: 0,
  2421. x: item.from,
  2422. x_end: item.to,
  2423. y: item.value,
  2424. obj: item
  2425. });
  2426. }
  2427. else {
  2428. _data.push({
  2429. series: 0,
  2430. x: item.value,
  2431. y: item.count,
  2432. obj: item
  2433. });
  2434. }
  2435. });
  2436. if (viewModel.chartSorting() == "asc"){
  2437. _data.sort(function(a, b){
  2438. return a.y - b.y
  2439. });
  2440. }
  2441. if (viewModel.chartSorting() == "desc"){
  2442. _data.sort(function(a, b){
  2443. return b.y - a.y
  2444. });
  2445. }
  2446. _datum.push({
  2447. key: $("#blueprintY option:selected").text(),
  2448. values: _data
  2449. });
  2450. return _datum;
  2451. }
  2452. </script>
  2453. ${ commonfooter(messages) | n,unicode }