execute.mako 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983
  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
  19. from django.utils.translation import ugettext as _
  20. %>
  21. <%namespace name="comps" file="beeswax_components.mako" />
  22. <%namespace name="layout" file="layout.mako" />
  23. ${ commonheader(_('Query'), app_name, user) | n,unicode }
  24. ${layout.menubar(section='query')}
  25. <div id="query-editor" class="container-fluid hide section">
  26. <div class="row-fluid">
  27. <div class="span2" id="advanced-settings">
  28. <form id="advancedSettingsForm" action="" method="POST" class="form form-horizontal">
  29. <div class="sidebar-nav">
  30. <ul class="nav nav-list">
  31. <li class="nav-header">${_('database')}</li>
  32. <li class="white" style="padding-top:0px">
  33. <select data-bind="options: databases, value: database" class="input-medium chosen-select" name="query-database" data-placeholder="${_('Choose a database...')}"></select>
  34. </li>
  35. <li class="nav-header">${_('settings')}</li>
  36. <li class="white paramContainer">
  37. <!-- ko foreach: design.settings -->
  38. <div class="param">
  39. <div class="remove">
  40. <button data-bind="click: $root.removeSetting.bind(this, $index())" type="button" class="btn btn-mini settingsDelete" title="${_('Delete this setting')}">x
  41. </button>
  42. </div>
  43. <div class="control-group">
  44. <label>${_('Key')}</label>
  45. <input data-bind="value: key" type="text" class="settingsField span8" autocomplete="off" placeholder="mapred.reduce.tasks"/>
  46. </div>
  47. <div class="control-group">
  48. <label>${_('Value')}</label>
  49. <input data-bind="value: value" type="text" class="settingValuesField span8" placeholder="1"/>
  50. </div>
  51. </div>
  52. <!-- /ko -->
  53. <div class="control-group">
  54. <a data-bind="click: function() { $root.addSetting('','') }" class="btn btn-mini paramAdd">${_('Add')}</a>
  55. </div>
  56. </li>
  57. <li class="nav-header
  58. % if app_name == 'impala':
  59. hide
  60. % endif
  61. ">
  62. ${_('File Resources')}
  63. </li>
  64. <li class="white paramContainer
  65. % if app_name == 'impala':
  66. hide
  67. % endif
  68. ">
  69. <!-- ko foreach: design.fileResources -->
  70. <div class="param">
  71. <div class="remove">
  72. <button data-bind="click: $root.removeFileResources.bind(this, $index())" type="button" class="btn btn-mini" title="${_('Delete this setting')}">&times;</button>
  73. </div>
  74. <div class="control-group">
  75. <label>${_('Type')}</label>
  76. <select data-bind="value: type" class="input-small">
  77. <option value="JAR">${_('jar')}</option>
  78. <option value="ARCHIVE">${_('archive')}</option>
  79. <option value="FILE">${_('file')}</option>
  80. </select>
  81. </div>
  82. <div class="control-group">
  83. <label>${_('Path')}</label>
  84. <input data-bind="value: path" type="text" class="filesField span7 pathChooser" placeholder="/user/foo/udf.jar"/>
  85. </div>
  86. </div>
  87. <!-- /ko -->
  88. <div class="control-group">
  89. <a data-bind="click: function() { $root.addFileResources('','') }" class="btn btn-mini paramAdd">${_('Add')}</a>
  90. </div>
  91. </li>
  92. <li title="${ _('User-Defined Functions') }" class="nav-header
  93. % if app_name == 'impala':
  94. hide
  95. % endif
  96. ">
  97. ${_('UDFs')}
  98. </li>
  99. <li class="white paramContainer
  100. % if app_name == 'impala':
  101. hide
  102. % endif
  103. ">
  104. <!-- ko foreach: design.functions -->
  105. <div class="param">
  106. <div class="remove">
  107. <button data-bind="click: $root.removeFunction.bind(this, $index())" type="button" class="btn btn-mini settingsDelete" title="${_('Delete this setting')}">&times;</button>
  108. </div>
  109. <div class="control-group">
  110. <label>${_('Name')}</label>
  111. <input data-bind="value: name" type="text" class="functionsField span8" autocomplete="off" placeholder="myFunction"/>
  112. </div>
  113. <div class="control-group">
  114. <label>${_('Class name')}</label>
  115. <input data-bind="value: class_name" type="text" class="classNamesField span8" placeholder="com.acme.example"/>
  116. </div>
  117. </div>
  118. <!-- /ko -->
  119. <div class="control-group">
  120. <a data-bind="click: function() { $root.addFunction('','') }" class="btn btn-mini paramAdd">${_('Add')}</a>
  121. </div>
  122. </li>
  123. <li class="nav-header">${_('Options')}</li>
  124. <li class="white" style="padding-top:0px">
  125. <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.")}">
  126. <input data-bind="checked: design.isParameterized" type="checkbox"/>
  127. ${_("Enable parameterization")}
  128. </label>
  129. <label class="checkbox
  130. % if app_name == 'impala':
  131. hide
  132. % endif
  133. " rel="tooltip" data-original-title="${_("If checked, you will receive an email notification when the query completes.")}">
  134. <input data-bind="checked: design.email" type="checkbox"/>
  135. ${_("Email me on completion")}
  136. </label>
  137. </li>
  138. % if app_name == 'impala':
  139. <li class="nav-header">
  140. ${_('Metastore Catalog')}
  141. </li>
  142. <li class="white">
  143. <div class="control-group">
  144. <span id="refresh-dyk">
  145. <i class="fa fa-refresh"></i>
  146. ${ _('Sync tables tips') }
  147. </span>
  148. <div id="refresh-content" class="hide">
  149. <ul style="text-align: left;">
  150. <li>"invalidate
  151. metadata" ${ _("invalidates the entire catalog metadata. All table metadata will be reloaded on the next access.") }</li>
  152. <li>"invalidate metadata
  153. &lt;table&gt;" ${ _("invalidates the metadata, load on the next access") }</li>
  154. <li>"refresh
  155. &lt;table&gt;" ${ _("refreshes the metadata immediately. It is a faster, incremental refresh.") }</li>
  156. </ul>
  157. </div>
  158. </div>
  159. </li>
  160. % endif
  161. <li class="nav-header"></li>
  162. <li class="white">
  163. <div class="control-group">
  164. <i class="fa fa-question-circle" id="help"></i>
  165. <div id="help-content" class="hide">
  166. <ul style="text-align: left;">
  167. <li>${ _('Press CTRL + Space to autocomplete') }</li>
  168. <li>${ _("You can execute queries with multiple SQL statements delimited by a semicolon ';'") }</li>
  169. <li>${ _('You can highlight and run a fragment of a query') }</li>
  170. </ul>
  171. </div>
  172. </div>
  173. </li>
  174. </ul>
  175. </div>
  176. </form>
  177. </div>
  178. <div id="querySide" class="span8">
  179. <div id="queryContainer" class="card card-small">
  180. <div style="margin-bottom: 30px">
  181. % if can_edit_name:
  182. <h1 class="card-heading simple">
  183. <a href="javascript:void(0);"
  184. id="query-name"
  185. data-type="text"
  186. data-name="name"
  187. data-value="${design.name}"
  188. data-original-title="${ _('Query name') }"
  189. data-placement="right">
  190. </a>
  191. <a href="javascript:void(0);"
  192. id="query-description"
  193. data-type="textarea"
  194. data-name="description"
  195. data-value="${design.desc}"
  196. data-original-title="${ _('Query description') }"
  197. data-placement="right" style="font-size: 14px; margin-left: 10px">
  198. </a>
  199. </h1>
  200. %endif
  201. </div>
  202. <div class="card-body">
  203. <div class="tab-content">
  204. <div id="queryPane">
  205. <div data-bind="css: {'hide': design.errors().length == 0}" class="hide alert alert-error">
  206. <p><strong>${_('Your query has the following error(s):')}</strong></p>
  207. <div data-bind="foreach: design.errors">
  208. <p data-bind="text: $data" class="queryErrorMessage"></p>
  209. </div>
  210. </div>
  211. <div data-bind="css: {'hide': design.watch.errors().length == 0}" class="alert alert-error">
  212. <p><strong>${_('Your query has the following error(s):')}</strong></p>
  213. <div data-bind="foreach: design.watch.errors">
  214. <p data-bind="text: $data" class="queryErrorMessage"></p>
  215. </div>
  216. </div>
  217. <textarea class="hide" tabindex="1" name="query" id="queryField"></textarea>
  218. <div class="actions">
  219. % if app_name == 'impala':
  220. <button data-bind="click: tryExecuteQuery, visible: !$root.design.isRunning() && $root.design.isFinished()" type="button" id="executeQuery" class="btn btn-primary disable-feedback" tabindex="2">${_('Execute')}</button>
  221. <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>
  222. % else:
  223. <button data-bind="click: tryExecuteQuery, enable: !$root.design.isRunning(), visible: $root.design.isFinished()" type="button" id="executeQuery" class="btn btn-primary disable-feedback" tabindex="2">${_('Execute')}</button>
  224. % endif
  225. <button data-bind="click: executeNextStatement, visible: !$root.design.isFinished()" type="button" class="btn btn-primary disable-feedback" tabindex="2">${_('Next')}</button>
  226. <button data-bind="click: trySaveDesign, css: {'hide': !$root.design.id() || $root.design.id() == -1}" type="button" class="btn hide">${_('Save')}</button>
  227. <button data-bind="click: saveAsModal" type="button" class="btn">${_('Save as...')}</button>
  228. <button data-bind="click: tryExplainQuery" type="button" id="explainQuery" class="btn">${_('Explain')}</button>
  229. &nbsp; ${_('or create a')} &nbsp;
  230. <button data-bind="click: createNewQuery" type="button" class="btn">${_('New query')}</button>
  231. <br/><br/>
  232. </div>
  233. </div>
  234. </div>
  235. </div>
  236. </div>
  237. <div class="card card-small scrollable resultsContainer">
  238. <div data-bind="visible: !$root.design.results.empty()">
  239. <a id="expandResults" href="javascript:void(0)" title="${_('See results in full screen')}" rel="tooltip"
  240. class="view-query-results hide pull-right"><h4 style="margin-right: 20px"><i class="fa fa-expand"></i></h4></a>
  241. <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"
  242. class="view-query-results hide pull-right"><h4 style="margin-right: 20px"><i class="fa fa-save"></i></h4></a>
  243. <a id="download-csv" data-bind="attr: {'href': '/beeswax/download/' + $root.design.id() + '/csv'}" href="javascript:void(0)" title="${_('Download the results in CSV format')}" rel="tooltip"
  244. class="view-query-results hide pull-right"><h4 style="margin-right: 20px"><i class="fa fa-arrow-circle-o-down"></i></h4></a>
  245. <a id="download-excel" data-bind="attr: {'href': '/beeswax/download/' + $root.design.id() + '/xls'}" href="javascript:void(0)" title="${_('Download the results for excel')}" rel="tooltip"
  246. class="view-query-results hide pull-right"><h4 style="margin-right: 20px"><i class="fa fa-arrow-circle-o-down"></i></h4></a>
  247. </div>
  248. <div class="card-body">
  249. <ul class="nav nav-tabs">
  250. <li><a href="#query" data-toggle="tab">${_('Query')}</a></li>
  251. <!-- ko if: !design.explain() -->
  252. <li><a href="#log" data-toggle="tab">${_('Log')}</a></li>
  253. <!-- /ko -->
  254. <!-- ko if: !design.explain() && !design.isRunning() -->
  255. <li><a href="#columns" data-toggle="tab">${_('Columns')}</a></li>
  256. <li><a href="#results" data-toggle="tab">${_('Results')}</a></li>
  257. <li><a href="#chart" data-toggle="tab">${_('Chart')}</a></li>
  258. <!-- /ko -->
  259. <!-- ko if: design.explain() && !design.isRunning() -->
  260. <li><a href="#explanation" data-toggle="tab">${_('Explanation')}</a></li>
  261. <!-- /ko -->
  262. </ul>
  263. <div class="tab-content">
  264. <div class="tab-pane" id="query">
  265. <pre data-bind="text: viewModel.design.statement()"></pre>
  266. </div>
  267. <!-- ko if: design.explain() -->
  268. <div class="tab-pane" id="explanation">
  269. <pre data-bind="text: $root.design.results.explanation()"></pre>
  270. </div>
  271. <!-- /ko -->
  272. <!-- ko if: !design.explain() -->
  273. <div class="active tab-pane" id="log">
  274. <pre data-bind="text: $root.design.watch.logs().join('\n')"></pre>
  275. </div>
  276. <div class="tab-pane" id="columns">
  277. <table class="table table-striped table-condensed" cellpadding="0" cellspacing="0">
  278. <thead>
  279. <tr><th>${_('Name')}</th></tr>
  280. </thead>
  281. <tbody data-bind="foreach: $root.design.results.columns">
  282. <tr>
  283. <td><a href="javascript:void(0)" class="column-selector" data-bind="text: $data.name"></a></td>
  284. </tr>
  285. </tbody>
  286. </table>
  287. </div>
  288. <div class="tab-pane" id="results">
  289. <div data-bind="css: {'hide': design.results.errors().length == 0}" class="alert alert-error">
  290. <p><strong>${_('Fetching results ran into the following error(s):')}</strong></p>
  291. <div data-bind="foreach: design.results.errors">
  292. <p data-bind="text: $data" class="queryErrorMessage"></p>
  293. </div>
  294. </div>
  295. <div data-bind="css: {'hide': $root.design.results.empty()}" class="hide">
  296. <table class="table table-striped table-condensed resultTable" cellpadding="0" cellspacing="0" data-tablescroller-enforce-height="true">
  297. <thead>
  298. <tr data-bind="foreach: $root.design.results.columns">
  299. <th data-bind="text: $data.name, css: { 'sort-numeric': $.inArray($data.type, ['TINYINT_TYPE', 'SMALLINT_TYPE', 'INT_TYPE', 'BIGINT_TYPE', 'FLOAT_TYPE', 'DOUBLE_TYPE', 'DECIMAL_TYPE']) > -1, 'sort-date': $.inArray($data.type, ['TIMESTAMP_TYPE', 'DATE_TYPE']) > -1, 'sort-string': $.inArray($data.type, ['TINYINT_TYPE', 'SMALLINT_TYPE', 'INT_TYPE', 'BIGINT_TYPE', 'FLOAT_TYPE', 'DOUBLE_TYPE', 'DECIMAL_TYPE', 'TIMESTAMP_TYPE', 'DATE_TYPE']) == -1 }"></th>
  300. </tr>
  301. </thead>
  302. </table>
  303. </div>
  304. <div data-bind="css: {'hide': !$root.design.results.empty()}" class="hide">
  305. <div class="card card-small scrollable">
  306. <div class="row-fluid">
  307. <div class="span10 offset1 center empty-wrapper">
  308. <i class="fa fa-frown-o"></i>
  309. <h1>${_('The server returned no results.')}</h1>
  310. <br/>
  311. </div>
  312. </div>
  313. </div>
  314. </div>
  315. </div>
  316. <div class="tab-pane" id="chart">
  317. <div class="alert hide">
  318. <strong>${_('Warning:')}</strong> ${_('the results on the chart have been limited to 1000 rows.')}
  319. </div>
  320. <div style="text-align: center">
  321. <form class="form-inline">
  322. ${_('Chart type')}&nbsp;
  323. <div class="btn-group" data-toggle="buttons-radio">
  324. <a rel="tooltip" data-placement="top" title="${_('Bars')}" id="blueprintBars" href="javascript:void(0)" class="btn"><i class="fa fa-bar-chart-o"></i></a>
  325. <a rel="tooltip" data-placement="top" title="${_('Lines')}" id="blueprintLines" href="javascript:void(0)" class="btn"><i class="fa fa-signal"></i></a>
  326. <a rel="tooltip" data-placement="top" title="${_('Map')}" id="blueprintMap" href="javascript:void(0)" class="btn"><i class="fa fa-map-marker"></i></a>
  327. </div>&nbsp;&nbsp;
  328. <span id="blueprintAxis" class="hide">
  329. <label>${_('X-Axis')}
  330. <select id="blueprintX" class="blueprintSelect"></select>
  331. </label>&nbsp;&nbsp;
  332. <label>${_('Y-Axis')}
  333. <select id="blueprintY" class="blueprintSelect"></select>
  334. </label>&nbsp;&nbsp;
  335. <a rel="tooltip" data-placement="top" title="${_('Download image')}" id="blueprintDownload" href="javascript:void(0)" class="btn hide"><i class="fa fa-download"></i></a>
  336. </span>
  337. <span id="blueprintLatLng" class="hide">
  338. <label>${_('Latitude')}
  339. <select id="blueprintLat" class="blueprintSelect"></select>
  340. </label>&nbsp;&nbsp;
  341. <label>${_('Longitude')}
  342. <select id="blueprintLng" class="blueprintSelect"></select>
  343. </label>&nbsp;&nbsp;
  344. <label>${_('Label')}
  345. <select id="blueprintDesc" class="blueprintSelect"></select>
  346. </label>
  347. </span>
  348. </form>
  349. </div>
  350. <div id="blueprint" class="empty">${_("Please select a chart type.")}</div>
  351. </div>
  352. <!-- /ko -->
  353. </div>
  354. </div>
  355. </div>
  356. </div>
  357. <div class="span2" id="navigator">
  358. <div class="card card-small">
  359. <a href="#" title="${_('Double click on a table name or field to insert it in the editor')}" rel="tooltip" data-placement="left" class="pull-right" style="margin:10px;margin-left: 0"><i class="fa fa-question-circle"></i></a>
  360. <a id="refreshNavigator" href="#" title="${_('Manually refresh the table list')}" rel="tooltip" data-placement="left" class="pull-right" style="margin:10px"><i class="fa fa-refresh"></i></a>
  361. <h1 class="card-heading simple"><i class="fa fa-compass"></i> ${_('Navigator')}</h1>
  362. <div class="card-body">
  363. <p>
  364. <input id="navigatorSearch" type="text" placeholder="${ _('Table name...') }" style="width:90%"/>
  365. <span id="navigatorNoTables">${_('The selected database has no tables.')}</span>
  366. <ul id="navigatorTables" class="unstyled"></ul>
  367. <div id="navigatorLoader">
  368. <!--[if !IE]><!--><i class="fa fa-spinner fa-spin" style="font-size: 20px; color: #DDD"></i><!--<![endif]-->
  369. <!--[if IE]><img src="/static/art/spinner.gif"/><![endif]-->
  370. </div>
  371. </p>
  372. </div>
  373. </div>
  374. </div>
  375. </div>
  376. </div>
  377. <div id="execute-parameter-selection" class="container-fluid hide section">
  378. <div class="row-fluid">
  379. <div class="card card-small">
  380. <h1 class="card-heading simple">${_('Please specify parameters for this query')}</h1>
  381. <div class="card-body">
  382. <p>
  383. <form method="POST" action="" class="form-horizontal">
  384. <fieldset>
  385. <!-- ko foreach: $root.design.parameters -->
  386. <div class="control-group">
  387. <label data-bind="text: name" class="control-label"></label>
  388. <div class="controls">
  389. <input data-bind="value: value, valueUpdate:'afterkeydown'" type="text"/>
  390. </div>
  391. </div>
  392. <!-- /ko -->
  393. <div class="form-actions" style="padding-left: 10px">
  394. <a class="btn" href="javascript:history.go(-1);">${_('Cancel')}</a>
  395. <button data-bind="enable: $root.hasParametersFilled, click: tryExecuteParameterizedQuery" type="button" class="btn btn-primary">${_('Execute query')}</button>
  396. </div>
  397. </fieldset>
  398. </form>
  399. </p>
  400. </div>
  401. </div>
  402. </div>
  403. </div>
  404. <div id="explain-parameter-selection" class="container-fluid hide section">
  405. <div class="row-fluid">
  406. <div class="card card-small">
  407. <h1 class="card-heading simple">${_('Please specify parameters for this query')}</h1>
  408. <div class="card-body">
  409. <p>
  410. <form method="POST" action="" class="form-horizontal">
  411. <fieldset>
  412. <!-- ko foreach: $root.design.parameters -->
  413. <div class="control-group">
  414. <label data-bind="text: name" class="control-label"></label>
  415. <div class="controls">
  416. <input data-bind="value: value, valueUpdate:'afterkeydown'" type="text"/>
  417. </div>
  418. </div>
  419. <!-- /ko -->
  420. <div class="form-actions" style="padding-left: 10px">
  421. <a class="btn" href="javascript:history.go(-1);">${_('Cancel')}</a>
  422. <button data-bind="enable: $root.hasParametersFilled, click: tryExplainParameterizedQuery" type="button" class="btn btn-primary">${_('Explain query')}</button>
  423. </div>
  424. </fieldset>
  425. </form>
  426. </p>
  427. </div>
  428. </div>
  429. </div>
  430. </div>
  431. <div id="chooseFile" class="modal hide fade">
  432. <div class="modal-header">
  433. <a href="#" class="close" data-dismiss="modal">&times;</a>
  434. <h3>${_('Choose a file')}</h3>
  435. </div>
  436. <div class="modal-body">
  437. <div id="filechooser">
  438. </div>
  439. </div>
  440. <div class="modal-footer">
  441. </div>
  442. </div>
  443. <div id="saveAs" class="modal hide fade">
  444. <div class="modal-header">
  445. <a href="#" class="close" data-dismiss="modal">&times;</a>
  446. <h3>${_('Choose a name')}</h3>
  447. </div>
  448. <form class="form-horizontal">
  449. <div class="control-group" id="saveas-query-name">
  450. <label class="control-label">${_('Name')}</label>
  451. <div class="controls">
  452. <input data-bind="value: $root.design.name" type="text" class="input-xlarge">
  453. </div>
  454. </div>
  455. <div class="control-group">
  456. <label class="control-label">${_('Description')}</label>
  457. <div class="controls">
  458. <input data-bind="value: $root.design.description" type="text" class="input-xlarge">
  459. </div>
  460. </div>
  461. </form>
  462. <div class="modal-footer">
  463. <button class="btn" data-dismiss="modal">${_('Cancel')}</button>
  464. <button data-bind="click: trySaveAsDesign" class="btn btn-primary">${_('Save')}</button>
  465. </div>
  466. </div>
  467. <div id="saveResultsModal" class="modal hide fade">
  468. <div class="modal-header">
  469. <a href="#" class="close" data-dismiss="modal">&times;</a>
  470. <h3>${_('Save Query Results')}</h3>
  471. </div>
  472. <div class="modal-body">
  473. <!-- ko if: $root.design.results.save.saveTargetError() -->
  474. <h4 data-bind="text: $root.design.results.save.saveTargetError()"></h4>
  475. <!-- /ko -->
  476. <!-- ko if: $root.design.results.save.targetTableError() -->
  477. <h4 data-bind="text: $root.design.results.save.targetTableError()"></h4>
  478. <!-- /ko -->
  479. <!-- ko if: $root.design.results.save.targetDirectoryError() -->
  480. <h4 data-bind="text: $root.design.results.save.targetDirectoryError()"></h4>
  481. <!-- /ko -->
  482. <form id="saveResultsForm" method="POST" class="form form-inline">
  483. <fieldset>
  484. <div data-bind="css: {'error': $root.design.results.save.targetTableError()}" class="control-group">
  485. <div class="controls">
  486. <label class="radio">
  487. <input data-bind="checked: $root.design.results.save.type" type="radio" name="save-results-type" value="hive-table">
  488. &nbsp;${ _('In a new table') }
  489. </label>
  490. <span data-bind="visible: $root.design.results.save.type() == 'hive-table'">
  491. <input data-bind="value: $root.design.results.save.path" type="text" name="target_table" placeholder="${_('Table name')}">
  492. </span>
  493. </div>
  494. </div>
  495. <div data-bind="css: {'error': $root.design.results.save.targetDirectoryError()}" class="control-group">
  496. <div class="controls">
  497. <label class="radio">
  498. <input data-bind="checked: $root.design.results.save.type" type="radio" name="save-results-type" value="hdfs">
  499. &nbsp;${ _('In an HDFS directory') }
  500. </label>
  501. <span data-bind="visible: $root.design.results.save.type() == 'hdfs'">
  502. <input data-bind="value: $root.design.results.save.path" type="text" name="target_dir" placeholder="${_('Results location')}" class="pathChooser">
  503. </span>
  504. </div>
  505. </div>
  506. </fieldset>
  507. </form>
  508. </div>
  509. <div class="modal-footer">
  510. <button class="btn" data-dismiss="modal">${_('Cancel')}</button>
  511. <button data-bind="click: trySaveResults" class="btn btn-primary">${_('Save')}</button>
  512. </div>
  513. </div>
  514. <div id="navigatorQuicklook" class="modal hide fade">
  515. <div class="modal-header">
  516. <a href="#" class="close" data-dismiss="modal">&times;</a>
  517. <a class="tableLink pull-right" href="#" target="_blank" style="margin-right: 20px;margin-top:6px"><i
  518. class="fa fa-external-link"></i> ${ _('View in Metastore Browser') }</a>
  519. <h3>${_('Data sample for')} <span class="tableName"></span></h3>
  520. </div>
  521. <div class="modal-body" style="min-height: 100px">
  522. <div class="loader">
  523. <!--[if !IE]><!--><i class="fa fa-spinner fa-spin" style="font-size: 30px; color: #DDD"></i><!--<![endif]-->
  524. <!--[if IE]><img src="/static/art/spinner.gif"/><![endif]-->
  525. </div>
  526. <div class="sample"></div>
  527. </div>
  528. <div class="modal-footer">
  529. <button class="btn btn-primary disable-feedback" data-dismiss="modal">${_('Ok')}</button>
  530. </div>
  531. </div>
  532. <script src="/static/ext/js/routie-0.3.0.min.js" type="text/javascript" charset="utf-8"></script>
  533. <script src="/static/ext/js/knockout-min.js" type="text/javascript" charset="utf-8"></script>
  534. <script src="/static/ext/js/knockout.mapping-2.3.2.js" type="text/javascript" charset="utf-8"></script>
  535. <script src="/beeswax/static/js/beeswax.vm.js"></script>
  536. <script src="/static/ext/js/codemirror-3.11.js"></script>
  537. <link rel="stylesheet" href="/static/ext/css/codemirror.css">
  538. <script src="/static/js/codemirror-hql.js"></script>
  539. % if app_name == 'impala':
  540. <script src="/static/js/codemirror-isql-hint.js"></script>
  541. % else:
  542. <script src="/static/js/codemirror-hql-hint.js"></script>
  543. % endif
  544. <script src="/static/js/codemirror-show-hint.js"></script>
  545. <link href="/static/ext/css/bootstrap-editable.css" rel="stylesheet">
  546. <script src="/static/ext/js/bootstrap-editable.min.js"></script>
  547. <script src="/static/ext/js/jquery/plugins/jquery.flot.min.js" type="text/javascript" charset="utf-8"></script>
  548. <script src="/static/ext/js/jquery/plugins/jquery.flot.categories.min.js" type="text/javascript" charset="utf-8"></script>
  549. <script src="/static/ext/js/leaflet/leaflet.js" type="text/javascript" charset="utf-8"></script>
  550. <script src="/static/js/jquery.blueprint.js" type="text/javascript" charset="utf-8"></script>
  551. <style type="text/css">
  552. h1 {
  553. margin-bottom: 5px;
  554. }
  555. #filechooser {
  556. min-height: 100px;
  557. overflow-y: auto;
  558. }
  559. .control-group {
  560. margin-bottom: 3px !important;
  561. }
  562. .control-group label {
  563. float: left;
  564. padding-top: 5px;
  565. text-align: left;
  566. width: 40px;
  567. }
  568. .control-group label.radio {
  569. float: none;
  570. width: auto;
  571. }
  572. .sidebar-nav {
  573. margin-bottom: 90px !important;
  574. }
  575. .paramContainer {
  576. padding-top: 3px!important;
  577. padding-left: 0px!important;
  578. padding-right: 0px!important;
  579. }
  580. .param {
  581. margin-bottom: 5px;
  582. padding:4px;
  583. padding-left:8px;
  584. border-bottom: 1px solid #F6F6F6;
  585. }
  586. .param:nth-child(even) {
  587. background-color: #F0F0F0;
  588. }
  589. .paramAdd {
  590. margin-left: 18px;
  591. }
  592. .remove {
  593. float: right;
  594. }
  595. .fileChooserBtn {
  596. border-radius: 0 3px 3px 0;
  597. }
  598. .CodeMirror {
  599. border: 1px solid #eee;
  600. margin-bottom: 20px;
  601. }
  602. .editorError {
  603. color: #B94A48;
  604. background-color: #F2DEDE;
  605. padding: 4px;
  606. font-size: 11px;
  607. }
  608. .editorError {
  609. color: #B94A48;
  610. background-color: #F2DEDE;
  611. padding: 4px;
  612. font-size: 11px;
  613. }
  614. .editable-empty, .editable-empty:hover {
  615. color: #666;
  616. font-style: normal;
  617. }
  618. #navigatorTables li {
  619. width: 95%;
  620. white-space: nowrap;
  621. overflow: hidden;
  622. text-overflow: ellipsis;
  623. }
  624. #navigatorSearch, #navigatorNoTables {
  625. display: none;
  626. }
  627. .tooltip.left {
  628. margin-left: -13px;
  629. }
  630. .fullscreen {
  631. position: absolute;
  632. top: 70px;
  633. left: 0;
  634. width: 100%;
  635. background-color: #FFFFFF;
  636. z-index: 32000;
  637. }
  638. .map {
  639. height: 200px;
  640. }
  641. .resultTable td, .resultTable th {
  642. white-space: nowrap;
  643. }
  644. .tab-content {
  645. min-height: 100px;
  646. }
  647. </style>
  648. <link href="/static/ext/css/leaflet.css" rel="stylesheet">
  649. <script src="/static/ext/js/jquery/plugins/jquery-fieldselection.js" type="text/javascript"></script>
  650. <script src="/beeswax/static/js/autocomplete.utils.js" type="text/javascript" charset="utf-8"></script>
  651. <link rel="stylesheet" href="/static/ext/chosen/chosen.min.css">
  652. <script src="/static/ext/chosen/chosen.jquery.min.js" type="text/javascript" charset="utf-8"></script>
  653. <script type="text/javascript" charset="utf-8">
  654. var codeMirror, renderNavigator, resetNavigator, dataTable;
  655. var HIVE_AUTOCOMPLETE_BASE_URL = "${ autocomplete_base_url | n,unicode }";
  656. var HIVE_AUTOCOMPLETE_FAILS_SILENTLY_ON = [500]; // error codes from beeswax/views.py - autocomplete
  657. var HIVE_AUTOCOMPLETE_GLOBAL_CALLBACK = function (data) {
  658. if (data != null && data.error) {
  659. resetNavigator();
  660. }
  661. };
  662. // Navigator.
  663. $(document).ready(function () {
  664. $("#navigatorQuicklook").modal({
  665. show: false
  666. });
  667. var navigatorSearchTimeout = -1;
  668. $("#navigatorSearch").on("keyup", function () {
  669. window.clearTimeout(navigatorSearchTimeout);
  670. navigatorSearchTimeout = window.setTimeout(function () {
  671. $("#navigatorTables li").removeClass("hide");
  672. $("#navigatorTables li").each(function () {
  673. if ($(this).text().toLowerCase().indexOf($("#navigatorSearch").val().toLowerCase()) == -1) {
  674. $(this).addClass("hide");
  675. }
  676. });
  677. }, 300);
  678. });
  679. resetNavigator = function () {
  680. var _db = viewModel.database();
  681. if (_db != null) {
  682. $.totalStorage('tables_' + _db, null);
  683. $.totalStorage('timestamp_tables_' + _db, null);
  684. renderNavigator();
  685. }
  686. }
  687. renderNavigator = function () {
  688. $("#navigatorTables").empty();
  689. $("#navigatorLoader").show();
  690. hac_getTables(viewModel.database(), function (data) { //preload tables for the default db
  691. $(data.split(" ")).each(function (cnt, table) {
  692. if ($.trim(table) != "") {
  693. var _table = $("<li>");
  694. _table.html("<a href='#' class='pull-right'><i class='fa fa-list' title='" + "${ _('Preview Sample data') }" + "' style='margin-left:5px'></i></a><a href='/metastore/table/" + viewModel.database() + "/" + table + "' target='_blank' class='pull-right hide'><i class='fa fa-eye' title='" + "${ _('View in Metastore Browser') }" + "'></i></a><a href='#' title='" + table + "'><i class='fa fa-table'></i> " + table + "</a><ul class='unstyled'></ul>");
  695. _table.data("table", table).attr("id", "navigatorTables_" + table);
  696. _table.find("a:eq(2)").on("click", function () {
  697. _table.find(".fa-table").removeClass("fa-table").addClass("fa-spin").addClass("fa-spinner");
  698. hac_getTableColumns(viewModel.database(), table, "", function (plain_columns, extended_columns) {
  699. _table.find("a:eq(1)").removeClass("hide");
  700. _table.find("ul").empty();
  701. _table.find(".fa-spinner").removeClass("fa-spinner").removeClass("fa-spin").addClass("fa-table");
  702. $(extended_columns).each(function (iCnt, col) {
  703. var _column = $("<li>");
  704. _column.html("<a href='#' style='padding-left:10px'" + (col.comment != null && col.comment != "" ? " title='" + col.comment + "'" : "") + "><i class='fa fa-columns'></i> " + col.name + " (" + col.type + ")</a>");
  705. _column.appendTo(_table.find("ul"));
  706. _column.on("dblclick", function () {
  707. codeMirror.replaceSelection($.trim(col.name) + ', ');
  708. codeMirror.setSelection(codeMirror.getCursor());
  709. codeMirror.focus();
  710. });
  711. });
  712. });
  713. });
  714. _table.find("a:eq(2)").on("dblclick", function () {
  715. codeMirror.replaceSelection($.trim(table) + ' ');
  716. codeMirror.setSelection(codeMirror.getCursor());
  717. codeMirror.focus();
  718. });
  719. _table.find("a:eq(0)").on("click", function () {
  720. $("#navigatorQuicklook").find(".tableName").text(table);
  721. $("#navigatorQuicklook").find(".tableLink").attr("href", "/metastore/table/" + viewModel.database() + "/" + _table.data("table"));
  722. $("#navigatorQuicklook").find(".sample").empty("");
  723. $("#navigatorQuicklook").attr("style", "width: " + ($(window).width() - 120) + "px;margin-left:-" + (($(window).width() - 80) / 2) + "px!important;");
  724. $.ajax({
  725. url: "/metastore/table/" + viewModel.database() + "/" + _table.data("table"),
  726. data: {"sample": true},
  727. beforeSend: function (xhr) {
  728. xhr.setRequestHeader("X-Requested-With", "Hue");
  729. },
  730. dataType: "html",
  731. success: function (data) {
  732. $("#navigatorQuicklook").find(".loader").hide();
  733. $("#navigatorQuicklook").find(".sample").html(data);
  734. },
  735. error: function (e) {
  736. if (e.status == 500) {
  737. resetNavigator();
  738. $(document).trigger("error", "${ _('There was a problem loading the table preview.') }");
  739. $("#navigatorQuicklook").modal("hide");
  740. }
  741. }
  742. });
  743. $("#navigatorQuicklook").modal("show");
  744. });
  745. _table.appendTo($("#navigatorTables"));
  746. }
  747. });
  748. $("#navigatorLoader").hide();
  749. if ($("#navigatorTables li").length > 0) {
  750. $("#navigatorSearch").show();
  751. $("#navigatorNoTables").hide();
  752. }
  753. else {
  754. $("#navigatorSearch").hide();
  755. $("#navigatorNoTables").show();
  756. }
  757. });
  758. }
  759. $("#expandResults").on("click", function(){
  760. if ($(this).find("i").hasClass("fa-expand")){
  761. $(this).find("i").removeClass("fa-expand").addClass("fa-compress");
  762. $(this).parent().addClass("fullscreen");
  763. }
  764. else {
  765. $(this).find("i").addClass("fa-expand").removeClass("fa-compress");
  766. $(this).parent().removeClass("fullscreen");
  767. }
  768. reinitializeTable();
  769. });
  770. renderNavigator();
  771. $("#refreshNavigator").on("click", function () {
  772. resetNavigator();
  773. });
  774. $("#navigator .card").css("min-height", ($(window).height() - 130) + "px");
  775. $("#navigatorTables").css("max-height", ($(window).height() - 260) + "px").css("overflow-y", "auto");
  776. viewModel.databases.subscribe(function () {
  777. if ($.totalStorage("${app_name}_last_database") != null && $.inArray($.totalStorage("${app_name}_last_database"), viewModel.databases())) {
  778. viewModel.database($.totalStorage("${app_name}_last_database"));
  779. }
  780. });
  781. viewModel.database.subscribe(function (value) {
  782. $(".chosen-select").trigger("chosen:updated");
  783. renderNavigator();
  784. });
  785. $(".chosen-select").chosen({
  786. disable_search_threshold: 5,
  787. width: "100%",
  788. no_results_text: "${_('Oops, no database found!')}"
  789. });
  790. $(".chosen-select").chosen().change(function () {
  791. $.totalStorage("${app_name}_last_database", viewModel.database());
  792. });
  793. $(document).on("click", ".column-selector", function () {
  794. var _t = $(".resultTable");
  795. var _col = _t.find("th:econtains(" + $(this).text() + ")");
  796. _t.find(".columnSelected").removeClass("columnSelected");
  797. _t.find("tr td:nth-child(" + (_col.index() + 1) + ")").addClass("columnSelected");
  798. $("a[href='#results']").click();
  799. });
  800. $(document).on("shown", "a[data-toggle='tab']", function (e) {
  801. if ($(e.target).attr("href") == "#log") {
  802. logsAtEnd = true;
  803. window.setTimeout(resizeLogs, 150);
  804. }
  805. if ($(e.target).attr("href") == "#results" && $(e.relatedTarget).attr("href") == "#columns") {
  806. if ($(".resultTable .columnSelected").length > 0) {
  807. var _t = $(".resultTable");
  808. var _col = _t.find("th:nth-child(" + ($(".resultTable .columnSelected").index() + 1) + ")");
  809. _t.parent().animate({
  810. scrollLeft: _col.position().left + _t.parent().scrollLeft() - _t.parent().offset().left - 30
  811. }, 300);
  812. }
  813. }
  814. });
  815. });
  816. // Codemirror query field
  817. function getHighlightedQuery() {
  818. var selection = codeMirror.getSelection();
  819. if (selection != "") {
  820. return selection;
  821. }
  822. return null;
  823. }
  824. function reinitializeTable () {
  825. window.setTimeout(function(){
  826. $(".dataTables_wrapper").jHueTableScroller({
  827. minHeight: $(window).height() - 190,
  828. heightAfterCorrection: 0
  829. });
  830. $(".resultTable").jHueTableExtender({
  831. hintElement: "#jumpToColumnAlert",
  832. fixedHeader: true,
  833. firstColumnTooltip: true
  834. });
  835. $($("a[data-toggle='tab']").parent(".active").find("a").attr("href")).height($(".dataTables_wrapper").height());
  836. $(".dataTables_wrapper").jHueScrollUp({
  837. secondClickScrollToTop: true
  838. });
  839. }, 400)
  840. }
  841. $(document).ready(function () {
  842. var queryPlaceholder = "${_('Example: SELECT * FROM tablename, or press CTRL + space')}";
  843. $("#executeQuery").tooltip({
  844. title: '${_("Press \"tab\", then \"enter\".")}'
  845. });
  846. $("#executeQuery").keyup(function (event) {
  847. if (event.keyCode == 13) {
  848. tryExecuteQuery();
  849. }
  850. });
  851. initQueryField();
  852. var resizeTimeout = -1;
  853. var winWidth = $(window).width();
  854. var winHeight = $(window).height();
  855. $(window).on("resize", function () {
  856. window.clearTimeout(resizeTimeout);
  857. resizeTimeout = window.setTimeout(function () {
  858. // prevents endless loop in IE8
  859. if (winWidth != $(window).width() || winHeight != $(window).height()) {
  860. $("#navigator .card").css("min-height", ($(window).height() - 130) + "px");
  861. $("#navigatorTables").css("max-height", ($(window).height() - 260) + "px").css("overflow-y", "auto");
  862. winWidth = $(window).width();
  863. winHeight = $(window).height();
  864. }
  865. }, 200);
  866. });
  867. function initQueryField() {
  868. if ($("#queryField").val() == "") {
  869. $("#queryField").val(queryPlaceholder);
  870. }
  871. }
  872. var queryEditor = $("#queryField")[0];
  873. % if app_name == 'impala':
  874. var AUTOCOMPLETE_SET = CodeMirror.impalaSQLHint;
  875. % else:
  876. var AUTOCOMPLETE_SET = CodeMirror.hiveQLHint;
  877. % endif
  878. CodeMirror.onAutocomplete = function (data, from, to) {
  879. if (CodeMirror.tableFieldMagic) {
  880. codeMirror.replaceRange(" ", from, from);
  881. codeMirror.setCursor(from);
  882. codeMirror.execCommand("autocomplete");
  883. }
  884. };
  885. CodeMirror.commands.autocomplete = function (cm) {
  886. $(document.body).on("contextmenu", function (e) {
  887. e.preventDefault(); // prevents native menu on FF for Mac from being shown
  888. });
  889. var pos = cm.cursorCoords();
  890. $("<i class='fa fa-spinner fa-spin CodeMirror-spinner'></i>").css("top", pos.top + "px").css("left", (pos.left - 4) + "px").appendTo($("body"));
  891. if ($.totalStorage('tables_' + viewModel.database()) == null) {
  892. CodeMirror.showHint(cm, AUTOCOMPLETE_SET);
  893. hac_getTables(viewModel.database(), function () {
  894. }); // if preload didn't work, tries again
  895. }
  896. else {
  897. hac_getTables(viewModel.database(), function (tables) {
  898. CodeMirror.catalogTables = tables;
  899. var _before = codeMirror.getRange({line: 0, ch: 0}, {line: codeMirror.getCursor().line, ch: codeMirror.getCursor().ch}).replace(/(\r\n|\n|\r)/gm, " ");
  900. CodeMirror.possibleTable = false;
  901. CodeMirror.tableFieldMagic = false;
  902. if (_before.toUpperCase().indexOf(" FROM ") > -1 && _before.toUpperCase().indexOf(" ON ") == -1 && _before.toUpperCase().indexOf(" WHERE ") == -1 ||
  903. _before.toUpperCase().indexOf("REFRESH") > -1 || _before.toUpperCase().indexOf("METADATA") > -1) {
  904. CodeMirror.possibleTable = true;
  905. }
  906. CodeMirror.possibleSoloField = false;
  907. if (_before.toUpperCase().indexOf("SELECT ") > -1 && _before.toUpperCase().indexOf(" FROM ") == -1 && !CodeMirror.fromDot) {
  908. if (codeMirror.getValue().toUpperCase().indexOf("FROM ") > -1) {
  909. fieldsAutocomplete(cm);
  910. }
  911. else {
  912. CodeMirror.tableFieldMagic = true;
  913. CodeMirror.showHint(cm, AUTOCOMPLETE_SET);
  914. }
  915. }
  916. else {
  917. if (_before.toUpperCase().indexOf("WHERE ") > -1 && !CodeMirror.fromDot && _before.match(/ON|GROUP|SORT/) == null) {
  918. fieldsAutocomplete(cm);
  919. }
  920. else {
  921. CodeMirror.showHint(cm, AUTOCOMPLETE_SET);
  922. }
  923. }
  924. });
  925. }
  926. }
  927. function fieldsAutocomplete(cm) {
  928. CodeMirror.possibleSoloField = true;
  929. try {
  930. var _possibleTables = $.trim(codeMirror.getValue(" ").substr(codeMirror.getValue().toUpperCase().indexOf("FROM ") + 4)).split(" ");
  931. var _foundTable = "";
  932. for (var i = 0; i < _possibleTables.length; i++) {
  933. if ($.trim(_possibleTables[i]) != "" && _foundTable == "") {
  934. _foundTable = _possibleTables[i];
  935. }
  936. }
  937. if (_foundTable != "") {
  938. if (hac_tableHasAlias(_foundTable, codeMirror.getValue())) {
  939. CodeMirror.possibleSoloField = false;
  940. CodeMirror.showHint(cm, AUTOCOMPLETE_SET);
  941. }
  942. else {
  943. hac_getTableColumns(viewModel.database(), _foundTable, codeMirror.getValue(),
  944. function (columns) {
  945. CodeMirror.catalogFields = columns;
  946. CodeMirror.showHint(cm, AUTOCOMPLETE_SET);
  947. });
  948. }
  949. }
  950. }
  951. catch (e) {
  952. }
  953. }
  954. CodeMirror.fromDot = false;
  955. codeMirror = CodeMirror(function (elt) {
  956. queryEditor.parentNode.replaceChild(elt, queryEditor);
  957. }, {
  958. value: queryEditor.value,
  959. readOnly: false,
  960. lineNumbers: true,
  961. mode: "text/x-hiveql",
  962. extraKeys: {
  963. "Ctrl-Space": function () {
  964. CodeMirror.fromDot = false;
  965. codeMirror.execCommand("autocomplete");
  966. },
  967. Tab: function (cm) {
  968. $("#executeQuery").focus();
  969. }
  970. },
  971. onKeyEvent: function (e, s) {
  972. if (s.type == "keyup") {
  973. if (s.keyCode == 190) {
  974. var _line = codeMirror.getLine(codeMirror.getCursor().line);
  975. var _partial = _line.substring(0, codeMirror.getCursor().ch);
  976. var _table = _partial.substring(_partial.lastIndexOf(" ") + 1, _partial.length - 1);
  977. if (codeMirror.getValue().toUpperCase().indexOf("FROM") > -1) {
  978. hac_getTableColumns(viewModel.database(), _table, codeMirror.getValue(), function (columns) {
  979. var _cols = columns.split(" ");
  980. for (var col in _cols) {
  981. _cols[col] = "." + _cols[col];
  982. }
  983. CodeMirror.catalogFields = _cols.join(" ");
  984. CodeMirror.fromDot = true;
  985. window.setTimeout(function () {
  986. codeMirror.execCommand("autocomplete");
  987. }, 100); // timeout for IE8
  988. });
  989. }
  990. }
  991. }
  992. }
  993. });
  994. codeMirror.on("focus", function () {
  995. if (codeMirror.getValue() == queryPlaceholder) {
  996. codeMirror.setValue("");
  997. }
  998. if (errorWidgets) {
  999. $.each(errorWidgets, function(index, errorWidget) {
  1000. errorWidget.clear();
  1001. });
  1002. errorWidgets = [];
  1003. }
  1004. $("#validationResults").empty();
  1005. });
  1006. % if design and not design.id:
  1007. if ($.totalStorage("${app_name}_temp_query") != null && $.totalStorage("${app_name}_temp_query") != "") {
  1008. codeMirror.setValue($.totalStorage("${app_name}_temp_query"));
  1009. }
  1010. % endif
  1011. codeMirror.on("blur", function () {
  1012. $(document.body).off("contextmenu");
  1013. });
  1014. codeMirror.on("change", function () {
  1015. $(".query").val(codeMirror.getValue());
  1016. $.totalStorage("${app_name}_temp_query", codeMirror.getValue());
  1017. });
  1018. });
  1019. $(document).one('fetched.design', function () {
  1020. // Edit query name and description.
  1021. $("#query-name").editable({
  1022. validate: function (value) {
  1023. if ($.trim(value) == '') {
  1024. return "${ _('This field is required.') }";
  1025. }
  1026. },
  1027. success: function (response, newValue) {
  1028. viewModel.design.name(newValue);
  1029. },
  1030. emptytext: "${ _('Query name') }"
  1031. });
  1032. $("#query-description").editable({
  1033. success: function (response, newValue) {
  1034. viewModel.design.description(newValue);
  1035. },
  1036. emptytext: "${ _('Empty description') }"
  1037. });
  1038. });
  1039. var graphHasBeenPredicted = false;
  1040. // Logs
  1041. var logsAtEnd = true;
  1042. $(document).ready(function () {
  1043. var labels = {
  1044. MRJOB: "${_('MR Job')}",
  1045. MRJOBS: "${_('MR Jobs')}"
  1046. };
  1047. $(window).resize(function () {
  1048. resizeLogs();
  1049. });
  1050. $("a[href='#log']").on("shown", function () {
  1051. resizeLogs();
  1052. });
  1053. $(document).on("shown", "a[data-toggle='tab']", function (e) {
  1054. if ($(e.target).attr("href") != "#results"){
  1055. $($(e.target).attr("href")).css('height', 'auto');
  1056. if ($(e.target).attr("href") == "#chart") {
  1057. predictGraph();
  1058. }
  1059. } else {
  1060. reinitializeTable();
  1061. }
  1062. return e;
  1063. });
  1064. function getMapBounds(lats, lngs) {
  1065. lats = lats.sort();
  1066. lngs = lngs.sort();
  1067. return [
  1068. [lats[lats.length - 1], lngs[lngs.length - 1]], // north-east
  1069. [lats[0], lngs[0]] // south-west
  1070. ]
  1071. }
  1072. var map;
  1073. function generateGraph(graphType) {
  1074. $("#chart .alert").addClass("hide");
  1075. if (graphType != "") {
  1076. if (map != null) {
  1077. try {
  1078. map.remove();
  1079. }
  1080. catch (err) { // do nothing
  1081. }
  1082. }
  1083. $("#blueprintDownload").addClass("hide");
  1084. $("#blueprint").attr("class", "").attr("style", "").empty();
  1085. $("#blueprint").data("plugin_jHueBlueprint", null);
  1086. if (graphType == $.jHueBlueprint.TYPES.MAP) {
  1087. if ($("#blueprintLat").val() != "-1" && $("#blueprintLng").val() != "-1") {
  1088. var _latCol = $("#blueprintLat").val() * 1;
  1089. var _lngCol = $("#blueprintLng").val() * 1;
  1090. var _descCol = $("#blueprintDesc").val() * 1;
  1091. var _lats = [];
  1092. var _lngs = [];
  1093. $(".resultTable>tbody>tr>td:nth-child(" + _latCol + ")").each(function (cnt) {
  1094. _lats.push($.trim($(this).text()) * 1);
  1095. });
  1096. $(".resultTable>tbody>tr>td:nth-child(" + _lngCol + ")").each(function (cnt) {
  1097. _lngs.push($.trim($(this).text()) * 1);
  1098. });
  1099. //$("#blueprint").addClass("map");
  1100. $("#blueprint").height($("#blueprint").parent().height() - 100);
  1101. map = L.map("blueprint").fitBounds(getMapBounds(_lats, _lngs));
  1102. L.tileLayer("http://{s}.tile.osm.org/{z}/{x}/{y}.png", {
  1103. attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
  1104. }).addTo(map);
  1105. $(".resultTable>tbody>tr>td:nth-child(" + _latCol + ")").each(function (cnt) {
  1106. if (cnt < 1000) {
  1107. if (_descCol != "-1") {
  1108. L.marker([$.trim($(this).text()) * 1, $.trim($(".resultTable>tbody>tr:nth-child(" + (cnt + 1) + ")>td:nth-child(" + _lngCol + ")").text()) * 1]).addTo(map).bindPopup($.trim($(".resultTable>tbody>tr:nth-child(" + (cnt + 1) + ")>td:nth-child(" + _descCol + ")").text()));
  1109. }
  1110. else {
  1111. L.marker([$.trim($(this).text()) * 1, $.trim($(".resultTable>tbody>tr:nth-child(" + (cnt + 1) + ")>td:nth-child(" + _lngCol + ")").text()) * 1]).addTo(map);
  1112. }
  1113. }
  1114. });
  1115. if ($(".resultTable>tbody>tr>td:nth-child(" + _latCol + ")").length > 1000){
  1116. $("#chart .alert").removeClass("hide");
  1117. }
  1118. }
  1119. else {
  1120. $("#blueprint").addClass("empty").text("${_("Please select the latitude and longitude columns.")}");
  1121. }
  1122. }
  1123. else {
  1124. if ($("#blueprintX").val() != "-1" && $("#blueprintY").val() != "-1") {
  1125. var _x = $("#blueprintX").val() * 1;
  1126. var _y = $("#blueprintY").val() * 1;
  1127. var _data = [];
  1128. $(".resultTable>tbody>tr>td:nth-child(" + _x + ")").each(function (cnt) {
  1129. if (cnt < 1000) {
  1130. _data.push([$.trim($(this).text()), $.trim($(".resultTable>tbody>tr:nth-child(" + (cnt + 1) + ")>td:nth-child(" + _y + ")").text()) * 1]);
  1131. }
  1132. });
  1133. if ($(".resultTable>tbody>tr>td:nth-child(" + _x + ")").length > 1000){
  1134. $("#chart .alert").removeClass("hide");
  1135. }
  1136. $("#blueprint").jHueBlueprint({
  1137. data: _data,
  1138. label: $(".resultTable>thead>tr>th:nth-child(" + _y + ")").text(),
  1139. type: graphType,
  1140. color: $.jHueBlueprint.COLORS.BLUE,
  1141. isCategories: true,
  1142. fill: true,
  1143. enableSelection: false,
  1144. height: 250
  1145. });
  1146. if (_data.length > 30){
  1147. $(".flot-x-axis .flot-tick-label").hide();
  1148. }
  1149. $("#blueprintDownload").removeClass("hide");
  1150. }
  1151. else {
  1152. $("#blueprint").addClass("empty").text("${_("Please select the columns you would like to see in this chart.")}");
  1153. }
  1154. }
  1155. }
  1156. }
  1157. $("#blueprintDownload").on("click", function(){
  1158. window.open($(".flot-base")[0].toDataURL());
  1159. });
  1160. function getGraphType() {
  1161. var _type = "";
  1162. if ($("#blueprintBars").hasClass("active")) {
  1163. _type = $.jHueBlueprint.TYPES.BARCHART;
  1164. }
  1165. if ($("#blueprintLines").hasClass("active")) {
  1166. _type = $.jHueBlueprint.TYPES.LINECHART;
  1167. }
  1168. if ($("#blueprintMap").hasClass("active")) {
  1169. _type = $.jHueBlueprint.TYPES.MAP;
  1170. }
  1171. return _type;
  1172. }
  1173. function predictGraph() {
  1174. if (!graphHasBeenPredicted) {
  1175. graphHasBeenPredicted = true;
  1176. var _firstAllString, _firstAllNumeric;
  1177. for (var i = 1; i < $(".resultTable>thead>tr>th").length; i++) {
  1178. var _isNumeric = true;
  1179. $(".resultTable>tbody>tr>td:nth-child(" + (i + 1) + ")").each(function (cnt) {
  1180. if (!$.isNumeric($.trim($(this).text()))) {
  1181. _isNumeric = false;
  1182. }
  1183. });
  1184. if (_firstAllString == null && !_isNumeric) {
  1185. _firstAllString = i + 1;
  1186. }
  1187. if (_firstAllNumeric == null && _isNumeric) {
  1188. _firstAllNumeric = i + 1;
  1189. }
  1190. }
  1191. if (_firstAllString != null && _firstAllNumeric != null) {
  1192. $("#blueprintBars").addClass("active");
  1193. $("#blueprintAxis").removeClass("hide");
  1194. $("#blueprintLatLng").addClass("hide");
  1195. $("#blueprintX").val(_firstAllString);
  1196. $("#blueprintY").val(_firstAllNumeric);
  1197. }
  1198. }
  1199. generateGraph(getGraphType());
  1200. }
  1201. $(".blueprintSelect").on("change", function () {
  1202. generateGraph(getGraphType())
  1203. });
  1204. $("#blueprintBars").on("click", function () {
  1205. $("#blueprintAxis").removeClass("hide");
  1206. $("#blueprintLatLng").addClass("hide");
  1207. generateGraph($.jHueBlueprint.TYPES.BARCHART)
  1208. });
  1209. $("#blueprintLines").on("click", function () {
  1210. $("#blueprintAxis").removeClass("hide");
  1211. $("#blueprintLatLng").addClass("hide");
  1212. generateGraph($.jHueBlueprint.TYPES.LINECHART)
  1213. });
  1214. $("#blueprintMap").on("click", function () {
  1215. $("#blueprintAxis").addClass("hide");
  1216. $("#blueprintLatLng").removeClass("hide");
  1217. generateGraph($.jHueBlueprint.TYPES.MAP)
  1218. });
  1219. $("#log pre").scroll(function () {
  1220. if ($(this).scrollTop() + $(this).height() + 20 >= $(this)[0].scrollHeight) {
  1221. logsAtEnd = true;
  1222. }
  1223. else {
  1224. logsAtEnd = false;
  1225. }
  1226. });
  1227. viewModel.design.watch.logs.subscribe(function(val){
  1228. var _logsEl = $("#log pre");
  1229. if (logsAtEnd && _logsEl[0]) {
  1230. _logsEl.scrollTop(_logsEl[0].scrollHeight - _logsEl.height());
  1231. }
  1232. });
  1233. });
  1234. function resizeLogs() {
  1235. // Use fixed subtraction since logs aren't always visible.
  1236. $("#log").height($(window).height() - $("#log pre").offset().top - 10);
  1237. $("#log pre").css("overflow", "auto").height($(window).height() - $("#log pre").offset().top - 50);
  1238. }
  1239. // Result Datatable
  1240. function cleanResultsTable() {
  1241. if (dataTable) {
  1242. dataTable.fnClearTable();
  1243. dataTable.fnDestroy();
  1244. viewModel.design.results.columns.valueHasMutated();
  1245. viewModel.design.results.rows.valueHasMutated();
  1246. dataTable = null;
  1247. }
  1248. }
  1249. function addResults(viewModel, dataTable, index, pageSize) {
  1250. if (viewModel.hasMoreResults() && index + pageSize > viewModel.design.results.rows().length) {
  1251. $(document).one('fetched.results', function () {
  1252. $.totalStorage("${app_name}_temp_query", null);
  1253. dataTable.fnAddData(viewModel.design.results.rows.slice(index, index + pageSize));
  1254. });
  1255. viewModel.fetchResults();
  1256. } else {
  1257. dataTable.fnAddData(viewModel.design.results.rows.slice(index, index + pageSize));
  1258. }
  1259. }
  1260. function resultsTable(e, data) {
  1261. if (!dataTable && viewModel.design.results.columns().length > 0) {
  1262. dataTable = $(".resultTable").dataTable({
  1263. "bPaginate": false,
  1264. "bLengthChange": false,
  1265. "bInfo": false,
  1266. "bDestroy": true,
  1267. "bAutoWidth": false,
  1268. "oLanguage": {
  1269. "sEmptyTable": "${_('No data available')}",
  1270. "sZeroRecords": "${_('No matching records')}"
  1271. },
  1272. "fnDrawCallback": function (oSettings) {
  1273. reinitializeTable();
  1274. },
  1275. "fnRowCallback": function (nRow, aData, iDisplayIndex, iDisplayIndexFull) {
  1276. // Make sure null values are seen as NULL.
  1277. for (var j = 0; j < aData.length; ++j) {
  1278. if (aData[j] == null) {
  1279. $(nRow).find('td:eq(' + j + ')').html("NULL");
  1280. }
  1281. }
  1282. return nRow;
  1283. },
  1284. "aoColumnDefs": [
  1285. {
  1286. "sType": "numeric",
  1287. "aTargets": [ "sort-numeric" ]
  1288. },
  1289. {
  1290. "sType": "string",
  1291. "aTargets": [ "sort-string" ]
  1292. },
  1293. {
  1294. "sType": "date",
  1295. "aTargets": [ "sort-date" ]
  1296. }
  1297. ]
  1298. });
  1299. $(".dataTables_filter").hide();
  1300. reinitializeTable();
  1301. var _options = '<option value="-1">${ _("Please select a column")}</option>';
  1302. $(viewModel.design.results.columns()).each(function(cnt, item){
  1303. _options += '<option value="'+(cnt + 1)+'">'+ item.name +'</option>';
  1304. });
  1305. $(".blueprintSelect").html(_options);
  1306. // Automatic results grower
  1307. var dataTableEl = $(".dataTables_wrapper");
  1308. var index = 0;
  1309. var pageSize = 100;
  1310. dataTableEl.on("scroll", function (e) {
  1311. if (dataTableEl.scrollTop() + dataTableEl.outerHeight() + 20 > dataTableEl[0].scrollHeight && dataTable) {
  1312. dataTableEl.animate({opacity: '0.55'}, 200);
  1313. $(".spinner").show();
  1314. addResults(viewModel, dataTable, index, pageSize);
  1315. index += pageSize;
  1316. $(".spinner").hide();
  1317. dataTableEl.animate({opacity: '1'}, 50);
  1318. }
  1319. });
  1320. addResults(viewModel, dataTable, index, pageSize);
  1321. index += pageSize;
  1322. dataTableEl.jHueScrollUp({
  1323. secondClickScrollToTop: true
  1324. });
  1325. }
  1326. }
  1327. $(document).on('execute.query', cleanResultsTable);
  1328. $(document).on('explain.query', cleanResultsTable);
  1329. $(document).on('fetched.results', resultsTable);
  1330. var selectedLine = -1;
  1331. var errorWidgets = [];
  1332. $(document).on('error.query', function () {
  1333. $.each(errorWidgets, function(index, el) {
  1334. $(el).remove();
  1335. errorWidgets = [];
  1336. });
  1337. // Move error to codeMirror if we konw the line number
  1338. $.each($(".queryErrorMessage"), function(index, el) {
  1339. var err = $(el).text().toLowerCase();
  1340. var firstPos = err.indexOf("line");
  1341. if (firstPos > -1) {
  1342. selectedLine = $.trim(err.substring(err.indexOf(" ", firstPos), err.indexOf(":", firstPos))) * 1;
  1343. errorWidgets.push(
  1344. codeMirror.addLineWidget(
  1345. selectedLine - 1,
  1346. $("<div>").addClass("editorError").html("<i class='fa fa-exclamation-circle'></i> " + err)[0], {
  1347. coverGutter: true,
  1348. noHScroll: true
  1349. }
  1350. )
  1351. );
  1352. $(el).hide();
  1353. }
  1354. });
  1355. if ($(".queryErrorMessage:hidden").length == $(".queryErrorMessage").length) {
  1356. $(".queryErrorMessage").parent().parent().hide();
  1357. }
  1358. });
  1359. // Save
  1360. function trySaveDesign() {
  1361. var query = getHighlightedQuery() || codeMirror.getValue();
  1362. viewModel.design.query(query);
  1363. if (viewModel.design.id() && viewModel.design.id() != -1) {
  1364. viewModel.saveDesign();
  1365. }
  1366. }
  1367. function saveAsModal() {
  1368. var query = getHighlightedQuery() || codeMirror.getValue();
  1369. viewModel.design.query(query);
  1370. $('#saveAs').modal('show');
  1371. }
  1372. function trySaveAsDesign() {
  1373. if (viewModel.design.query() && viewModel.design.name()) {
  1374. viewModel.design.id(-1);
  1375. viewModel.saveDesign();
  1376. $('#saveas-query-name').removeClass('error');
  1377. $('#saveAs').modal('hide');
  1378. } else if (viewModel.design.name()) {
  1379. $.jHueNotify.error("${_('No query provided to save.')}");
  1380. $('#saveAs').modal('hide');
  1381. } else {
  1382. $('#saveas-query-name').addClass('error');
  1383. }
  1384. }
  1385. function saveResultsModal() {
  1386. $('#saveResultsModal').modal('show');
  1387. }
  1388. function trySaveResults() {
  1389. viewModel.saveResults();
  1390. }
  1391. $(document).on('saved.results', function() {
  1392. $('#saveResultsModal').modal('hide');
  1393. });
  1394. // Querying and click events.
  1395. function tryExecuteQuery() {
  1396. $(".tooltip").remove();
  1397. var query = getHighlightedQuery() || codeMirror.getValue();
  1398. viewModel.design.query(query);
  1399. if ($(".dataTables_wrapper").length > 0) { // forces results to be up
  1400. $(".dataTables_wrapper").scrollTop(0);
  1401. }
  1402. graphHasBeenPredicted = false;
  1403. if (viewModel.design.isParameterized()) {
  1404. viewModel.fetchParameters();
  1405. } else {
  1406. viewModel.executeQuery();
  1407. }
  1408. }
  1409. function tryExecuteParameterizedQuery() {
  1410. $(".tooltip").remove();
  1411. viewModel.executeQuery();
  1412. routie('query');
  1413. }
  1414. ;
  1415. function tryExplainQuery() {
  1416. $(".tooltip").remove();
  1417. var query = getHighlightedQuery() || codeMirror.getValue();
  1418. viewModel.design.query(query);
  1419. viewModel.explainQuery();
  1420. }
  1421. function tryExplainParameterizedQuery() {
  1422. $(".tooltip").remove();
  1423. viewModel.explainQuery();
  1424. routie('query');
  1425. }
  1426. ;
  1427. function tryCancelQuery() {
  1428. $(".tooltip").remove();
  1429. viewModel.cancelQuery();
  1430. }
  1431. function createNewQuery() {
  1432. $.totalStorage("${app_name}_temp_query", null);
  1433. location.href="${ url('beeswax:execute_query') }";
  1434. }
  1435. function checkLastDatabase(server, database) {
  1436. var key = "hueBeeswaxLastDatabase-" + server;
  1437. if (database != $.totalStorage(key)) {
  1438. $.totalStorage(key, database);
  1439. }
  1440. }
  1441. function getLastDatabase(server) {
  1442. var key = "hueBeeswaxLastDatabase-" + server;
  1443. return $.totalStorage(key);
  1444. }
  1445. // Server error handling.
  1446. $(document).on('server.error', function (e, data) {
  1447. $(document).trigger('error', "${_('Server error occured: ')}" + data.message ? data.message : data.error);
  1448. });
  1449. $(document).on('server.unmanageable_error', function (e, responseText) {
  1450. $(document).trigger('error', "${_('Unmanageable server error occured: ')}" + responseText);
  1451. });
  1452. // Other
  1453. $(document).on('saved.design', function (e, id) {
  1454. $(document).trigger('info', "${'Query saved.'}");
  1455. window.location.href = "/beeswax/execute/design/" + id;
  1456. });
  1457. $(document).on('error_cancel.query', function (e, message) {
  1458. $(document).trigger("error", "${ _('Problem: ') }" + message);
  1459. });
  1460. $(document).on('cancelled.query', function (e) {
  1461. $(document).trigger("info", "${ _('Query canceled!') }")
  1462. });
  1463. function updateSidebarTooltips(selector) {
  1464. $(selector).each(function(){
  1465. $(this).tooltip({
  1466. placement: "right",
  1467. title: $(this).val()
  1468. }).attr('data-original-title', $(this).val()).tooltip('fixTitle');
  1469. });
  1470. }
  1471. $(document).ready(function () {
  1472. $(".pathChooser:not(:has(~ button))").after(getFileBrowseButton($(".pathChooser:not(:has(~ button))")));
  1473. $("*[rel=tooltip]").tooltip({
  1474. placement: 'bottom'
  1475. });
  1476. // hack for select default rendered fields
  1477. $("select").addClass("input-medium");
  1478. // Type ahead for settings.
  1479. $.getJSON("${ url(app_name + ':configuration') }", function (data) {
  1480. $(".settingsField").typeahead({
  1481. source: $.map(data.config_values, function (value, key) {
  1482. return value.key;
  1483. })
  1484. });
  1485. });
  1486. // Help.
  1487. $("#help").popover({
  1488. 'title': "${_('Did you know?')}",
  1489. 'content': $("#help-content").html(),
  1490. 'trigger': 'hover',
  1491. 'html': true
  1492. });
  1493. $(document).on("change", ".settingsField", function(){
  1494. updateSidebarTooltips(".settingsField");
  1495. });
  1496. $(document).on("change", ".settingValuesField", function(){
  1497. updateSidebarTooltips(".settingValuesField");
  1498. });
  1499. $(document).on("change", ".filesField", function(){
  1500. updateSidebarTooltips(".filesField");
  1501. });
  1502. $(document).on("change", ".functionsField", function(){
  1503. updateSidebarTooltips(".functionsField");
  1504. });
  1505. $(document).on("change", ".classNamesField", function(){
  1506. updateSidebarTooltips(".classNamesField");
  1507. });
  1508. // loads default
  1509. updateSidebarTooltips(".settingsField");
  1510. updateSidebarTooltips(".settingValuesField");
  1511. updateSidebarTooltips(".filesField");
  1512. updateSidebarTooltips(".functionsField");
  1513. updateSidebarTooltips(".classNamesField");
  1514. % if app_name == 'impala':
  1515. $("#downloadQuery").click(function () {
  1516. $("<input>").attr("type", "hidden").attr("name", "button-submit").attr("value", "Execute").appendTo($("#advancedSettingsForm"));
  1517. $("<input>").attr("type", "hidden").attr("name", "download").attr("value", "true").appendTo($("#advancedSettingsForm"));
  1518. tryExecuteQuery();
  1519. });
  1520. % endif
  1521. % if app_name == 'impala':
  1522. $("#refresh-dyk").popover({
  1523. 'title': "${_('Missing some tables? In order to update the list of tables/metadata seen by Impala, execute one of these queries:')}",
  1524. 'content': $("#refresh-content").html(),
  1525. 'trigger': 'hover',
  1526. 'html': true
  1527. });
  1528. $("#refresh-tip").popover({
  1529. 'title': "${_('Missing some tables? In order to update the list of tables/metadata seen by Impala, execute one of these queries:')}",
  1530. 'content': $("#refresh-content").html(),
  1531. 'trigger': 'hover',
  1532. 'html': true
  1533. });
  1534. window.onbeforeunload = function(e) {
  1535. viewModel.closeQuery();
  1536. };
  1537. $(document).on('explain.query', function() {
  1538. viewModel.closeQuery();
  1539. });
  1540. $(document).on('execute.query', function() {
  1541. viewModel.closeQuery();
  1542. });
  1543. % endif
  1544. });
  1545. // Routie
  1546. $(document).ready(function () {
  1547. function queryPageComponents() {
  1548. $('#advanced-settings').show();
  1549. $('#navigator').show();
  1550. $('#queryContainer').show();
  1551. $('a[href="#query"]').parent().show();
  1552. if (!$('#querySide').hasClass('span8')) {
  1553. $('#querySide').addClass('span8');
  1554. }
  1555. }
  1556. function watchPageComponents() {
  1557. $('#advanced-settings').hide();
  1558. $('#navigator').hide();
  1559. $('#queryContainer').hide();
  1560. $('a[href="#query"]').parent().hide();
  1561. if ($('#querySide').hasClass('span8')) {
  1562. $('#querySide').removeClass('span8');
  1563. }
  1564. }
  1565. function queryPage() {
  1566. queryPageComponents();
  1567. $('.resultsContainer').hide();
  1568. $('.resultsContainer .watch-query').hide();
  1569. $('.resultsContainer .view-query-results').hide();
  1570. }
  1571. function queryLogPage() {
  1572. queryPageComponents();
  1573. $('.resultsContainer').show();
  1574. $('.resultsContainer .watch-query').show();
  1575. $('.resultsContainer .view-query-results').hide();
  1576. }
  1577. function queryResultsPage() {
  1578. queryPageComponents();
  1579. $('.resultsContainer').show();
  1580. $('.resultsContainer .watch-query').hide();
  1581. $('.resultsContainer .view-query-results').show();
  1582. }
  1583. function parametersPage() {
  1584. queryPageComponents();
  1585. $('.resultsContainer').hide();
  1586. $('.resultsContainer .watch-query').hide();
  1587. $('.resultsContainer .view-query-results').hide();
  1588. }
  1589. function watchLogsPage() {
  1590. watchPageComponents();
  1591. $('.resultsContainer').show();
  1592. $('.resultsContainer .watch-query').show();
  1593. $('.resultsContainer .view-query-results').hide();
  1594. }
  1595. function watchResultsPage() {
  1596. watchPageComponents();
  1597. $('.resultsContainer').show();
  1598. $('.resultsContainer .watch-query').hide();
  1599. $('.resultsContainer .view-query-results').show();
  1600. }
  1601. routie({
  1602. 'query': function () {
  1603. showSection('query-editor');
  1604. queryPage();
  1605. codeMirror.setSize("99%", $(window).height() - 270 - $("#queryPane .alert-error").outerHeight() - $(".nav-tabs").outerHeight());
  1606. },
  1607. 'query/execute/params': function () {
  1608. if (viewModel.design.parameters().length == 0) {
  1609. routie('query');
  1610. }
  1611. showSection('execute-parameter-selection');
  1612. parametersPage();
  1613. },
  1614. 'query/explain/params': function () {
  1615. if (viewModel.design.parameters().length == 0) {
  1616. routie('query');
  1617. }
  1618. showSection('explain-parameter-selection');
  1619. parametersPage();
  1620. },
  1621. 'query/logs': function () {
  1622. if (viewModel.design.watch.logs().length == 0 && viewModel.design.watch.errors().length == 0) {
  1623. routie('query');
  1624. }
  1625. showSection('query-editor');
  1626. queryLogPage();
  1627. clickHard('.resultsContainer .nav-tabs a[href="#log"]');
  1628. codeMirror.setSize("99%", 100);
  1629. },
  1630. 'query/results': function () {
  1631. showSection('query-editor');
  1632. queryResultsPage();
  1633. $("html, body").animate({ scrollTop: ($(".resultsContainer").position().top - 80) + "px" });
  1634. codeMirror.setSize("99%", 100);
  1635. clickHard('.resultsContainer .nav-tabs a[href="#results"]');
  1636. },
  1637. 'query/explanation': function () {
  1638. if (! viewModel.design.results.explanation()) {
  1639. routie('query');
  1640. }
  1641. showSection('query-editor');
  1642. queryResultsPage();
  1643. clickHard('.resultsContainer .nav-tabs a[href="#explanation"]');
  1644. codeMirror.setSize("99%", 100);
  1645. },
  1646. 'watch/logs': function() {
  1647. showSection('query-editor');
  1648. watchLogsPage();
  1649. clickHard('.resultsContainer .nav-tabs a[href="#log"]');
  1650. },
  1651. 'watch/results': function() {
  1652. showSection('query-editor');
  1653. watchResultsPage();
  1654. clickHard('.resultsContainer .nav-tabs a[href="#results"]');
  1655. },
  1656. '*': function () {
  1657. routie('query');
  1658. }
  1659. });
  1660. });
  1661. // Event setup
  1662. function queryEvents() {
  1663. $(document).on('fetched.parameters', function () {
  1664. if (viewModel.design.parameters().length > 0) {
  1665. routie('query/execute/params');
  1666. } else {
  1667. viewModel.executeQuery();
  1668. }
  1669. });
  1670. $(document).on('explained.query', function () {
  1671. routie('query/explanation');
  1672. });
  1673. $(document).on('watched.query', function (e, data) {
  1674. if (data.status && data.status && data.status != 0) {
  1675. viewModel.design.watch.errors.push(data.error || data.message);
  1676. }
  1677. routie('query/logs');
  1678. });
  1679. $(document).on('error_watch.query', function () {
  1680. routie('query/logs');
  1681. });
  1682. $(document).on('fetched.results', function () {
  1683. routie('query/results');
  1684. });
  1685. $(document).on('execute.query', function() {
  1686. routie('query');
  1687. });
  1688. $(document).ready(function() {
  1689. routie('query');
  1690. });
  1691. }
  1692. function watchEvents() {
  1693. $(document).ready(function() {
  1694. routie('watch/logs');
  1695. });
  1696. $(document).on('error_watch.query', function () {
  1697. routie('watch/logs');
  1698. });
  1699. $(document).on('fetched.results', function () {
  1700. routie('watch/results');
  1701. });
  1702. }
  1703. // Knockout
  1704. viewModel = new BeeswaxViewModel("${app_name}");
  1705. % if query:
  1706. viewModel.design.history.id(${query.id});
  1707. viewModel.fetchQueryHistory();
  1708. $(document).on('fetched.query', function(e) {
  1709. viewModel.watchQueryLoop();
  1710. });
  1711. % elif design.id:
  1712. viewModel.design.id(${design.id});
  1713. viewModel.fetchDesign();
  1714. % endif
  1715. if (viewModel.design.id() > 0 || viewModel.design.history.id() > 0) {
  1716. // Code mirror and ko.
  1717. var codeMirrorSubscription = viewModel.design.query.subscribe(function(value) {
  1718. codeMirror.setValue(value);
  1719. codeMirrorSubscription.dispose();
  1720. });
  1721. }
  1722. viewModel.design.fileResources.subscribe(function() {
  1723. // File chooser button for file resources.
  1724. $(".pathChooser:not(:has(~ button))").after(getFileBrowseButton($(".pathChooser:not(:has(~ button))")));
  1725. });
  1726. viewModel.fetchDatabases();
  1727. ko.applyBindings(viewModel);
  1728. % if action == 'watch-results':
  1729. watchEvents();
  1730. $(document).one('fetched.query', function(e) {
  1731. viewModel.watchQueryLoop();
  1732. });
  1733. % elif action == 'watch-redirect':
  1734. watchEvents();
  1735. $(document).one('fetched.query', function(e) {
  1736. viewModel.watchQueryLoop();
  1737. });
  1738. $(document).on('stop_watch.query', function(e) {
  1739. if (viewModel.design.results.errors().length == 0) {
  1740. window.location.href = "${request.GET['on_success_url']}";
  1741. }
  1742. });
  1743. % elif action == 'editor-results':
  1744. queryEvents();
  1745. $(document).one('fetched.query', function(e) {
  1746. viewModel.watchQueryLoop();
  1747. });
  1748. % else:
  1749. queryEvents();
  1750. % endif
  1751. // @TODO: Stop operation
  1752. // @TODO: Re-add download query for impala
  1753. </script>
  1754. ${ commonfooter(messages) | n,unicode }