editor.mako 71 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580
  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.views import commonheader, commonfooter
  18. from django.utils.translation import ugettext as _
  19. %>
  20. ${ commonheader(_('Query'), app_name, user, "68px") | n,unicode }
  21. <script type="text/javascript">
  22. if (window.location.hash != "") {
  23. if (window.location.hash.indexOf("notebook") > -1) {
  24. location.href = "/spark/editor?" + window.location.hash.substr(1);
  25. }
  26. }
  27. </script>
  28. <link rel="stylesheet" href="/static/css/common_dashboard.css">
  29. <link rel="stylesheet" href="/static/ext/css/codemirror.css">
  30. <link rel="stylesheet" href="/spark/static/css/spark.css">
  31. <link rel="stylesheet" href="/static/ext/css/bootstrap-editable.css">
  32. <link rel="stylesheet" href="/static/ext/chosen/chosen.min.css">
  33. <link rel="stylesheet" href="/static/ext/css/hue-charts.css">
  34. <link rel="stylesheet" href="/static/ext/css/leaflet.css">
  35. <link rel="stylesheet" href="/static/ext/css/nv.d3.min.css">
  36. <link rel="stylesheet" href="/static/css/nv.d3.css">
  37. <link rel="stylesheet" href="/static/ext/select2/select2.css">
  38. <script src="/static/ext/js/codemirror-3.11.js"></script>
  39. <script src="/static/js/codemirror-pig.js"></script>
  40. <script src="/static/js/codemirror-hql.js"></script>
  41. <script src="/static/js/codemirror-python.js"></script>
  42. <script src="/static/js/codemirror-clike.js"></script>
  43. <script src="/static/js/codemirror-show-hint.js"></script>
  44. <script src="/static/js/codemirror-isql-hint.js"></script>
  45. <script src="/static/js/codemirror-hql-hint.js"></script>
  46. <script src="/static/js/codemirror-pig-hint.js"></script>
  47. <script src="/static/js/codemirror-python-hint.js"></script>
  48. <script src="/static/js/codemirror-clike-hint.js"></script>
  49. <script src="/static/ext/js/markdown.min.js"></script>
  50. <script src="/static/ext/js/jquery/plugins/jquery.hotkeys.js"></script>
  51. <script src="/static/js/bootstrap-wysiwyg.js"></script>
  52. <script src="/static/ext/js/bootstrap-editable.min.js" type="text/javascript" charset="utf-8"></script>
  53. <script src="/static/ext/js/jquery/plugins/jquery-ui-1.10.4.draggable-droppable-sortable.min.js" type="text/javascript" charset="utf-8"></script>
  54. <script src="/static/ext/js/knockout-min.js" type="text/javascript" charset="utf-8"></script>
  55. <script src="/static/ext/js/knockout.mapping-2.3.2.js" type="text/javascript" charset="utf-8"></script>
  56. <script src="/static/ext/js/knockout-sortable.min.js" type="text/javascript" charset="utf-8"></script>
  57. <script src="/static/js/ko.editable.js" type="text/javascript" charset="utf-8"></script>
  58. <script src="/static/js/hue.utils.js"></script>
  59. <script src="/static/js/ko.hue-bindings.js" type="text/javascript" charset="utf-8"></script>
  60. <script src="/spark/static/js/assist.js" type="text/javascript" charset="utf-8"></script>
  61. <script src="/spark/static/js/spark.ko.js" type="text/javascript" charset="utf-8"></script>
  62. <script src="/static/ext/chosen/chosen.jquery.min.js" type="text/javascript" charset="utf-8"></script>
  63. <script src="/static/js/hue.geo.js" type="text/javascript" charset="utf-8"></script>
  64. <script src="/static/js/hue.colors.js" type="text/javascript" charset="utf-8"></script>
  65. <script src="/static/ext/js/leaflet/leaflet.js" type="text/javascript" charset="utf-8"></script>
  66. <script src="/static/ext/js/d3.v3.js" type="text/javascript" charset="utf-8"></script>
  67. <script src="/static/js/nv.d3.js" type="text/javascript" charset="utf-8"></script>
  68. <script src="/static/ext/js/topojson.v1.min.js" type="text/javascript" charset="utf-8"></script>
  69. <script src="/static/ext/js/topo/world.topo.js" type="text/javascript" charset="utf-8"></script>
  70. <script src="/static/ext/js/topo/usa.topo.js" type="text/javascript" charset="utf-8"></script>
  71. <script src="/static/js/nv.d3.datamaps.js" type="text/javascript" charset="utf-8"></script>
  72. <script src="/static/js/nv.d3.legend.js" type="text/javascript" charset="utf-8"></script>
  73. <script src="/static/js/nv.d3.multiBarWithBrushChart.js" type="text/javascript" charset="utf-8"></script>
  74. <script src="/static/js/nv.d3.lineWithBrushChart.js" type="text/javascript" charset="utf-8"></script>
  75. <script src="/static/js/nv.d3.growingDiscreteBar.js" type="text/javascript" charset="utf-8"></script>
  76. <script src="/static/js/nv.d3.growingDiscreteBarChart.js" type="text/javascript" charset="utf-8"></script>
  77. <script src="/static/js/nv.d3.growingMultiBar.js" type="text/javascript" charset="utf-8"></script>
  78. <script src="/static/js/nv.d3.growingMultiBarChart.js" type="text/javascript" charset="utf-8"></script>
  79. <script src="/static/js/nv.d3.growingPie.js" type="text/javascript" charset="utf-8"></script>
  80. <script src="/static/js/nv.d3.growingPieChart.js" type="text/javascript" charset="utf-8"></script>
  81. <script src="/static/js/nv.d3.scatter.js" type="text/javascript" charset="utf-8"></script>
  82. <script src="/static/js/nv.d3.scatterChart.js" type="text/javascript" charset="utf-8"></script>
  83. <script src="/static/js/ko.charts.js" type="text/javascript" charset="utf-8"></script>
  84. <script src="/static/ext/select2/select2.min.js" type="text/javascript" charset="utf-8"></script>
  85. <div class="search-bar">
  86. <div class="pull-right" style="padding-right:50px">
  87. <a title="${ _('Execute all') }" rel="tooltip" data-placement="bottom" data-bind="click: true, css: {'btn': true}">
  88. <i class="fa fa-play"></i>
  89. </a>
  90. <a title="${ _('Edit') }" rel="tooltip" data-placement="bottom" data-bind="click: toggleEditing, css: {'btn': true, 'btn-inverse': isEditing}">
  91. <i class="fa fa-pencil"></i>
  92. </a>
  93. &nbsp;&nbsp;&nbsp;
  94. % if user.is_superuser:
  95. <button type="button" title="${ _('Save') }" rel="tooltip" data-placement="bottom" data-loading-text="${ _("Saving...") }"
  96. data-bind="click: saveNotebook, css: {'btn': true}">
  97. <i class="fa fa-save"></i>
  98. </button>
  99. &nbsp;&nbsp;&nbsp;
  100. <button type="button" title="${ _('New') }" rel="tooltip" data-placement="bottom" data-loading-text="${ _("New...") }"
  101. data-bind="click: newNotebook, css: {'btn': true}">
  102. <i class="fa fa-file-o"></i>
  103. </button>
  104. <a class="btn" href="${ url('spark:new') }" title="${ _('Brand New') }" rel="tooltip" data-placement="bottom" data-bind="css: {'btn': true}">
  105. <i class="fa fa-file-o"></i>
  106. </a>
  107. <button type="button" title="${ _('Open') }" rel="tooltip" data-placement="bottom" data-loading-text="${ _("New...") }"
  108. data-bind="click: newNotebook, css: {'btn': true}">
  109. <i class="fa fa-folder-open-o"></i>
  110. </button>
  111. <a class="btn" href="${ url('spark:notebooks') }" title="${ _('Notebooks') }" rel="tooltip" data-placement="bottom" data-bind="css: {'btn': true}">
  112. <i class="fa fa-terminal"></i>
  113. </a>
  114. % endif
  115. </div>
  116. <ul class="nav nav-tabs">
  117. <!-- ko foreach: notebooks -->
  118. <li data-bind="css: { active: $parent.selectedNotebook() === $data }">
  119. <a href="javascript:void(0)" data-bind="text: name, click: $parent.selectedNotebook.bind(null, $data)"></a>
  120. </li>
  121. <!-- /ko -->
  122. <li>
  123. <a href="javascript:void(0)" data-bind="click: newNotebook"><i class="fa fa-plus" title="${ _('Add a new notebook') }"></i></a>
  124. </li>
  125. </ul>
  126. </div>
  127. <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isAssistVisible(), click: $root.toggleAssist">
  128. <i class="fa fa-chevron-right"></i>
  129. </a>
  130. <div class="container-fluid">
  131. <div class="row-fluid">
  132. <div class="span12">
  133. <div class="tab-content" data-bind="foreach: notebooks">
  134. <div class="tab-pane" data-bind="css: { active: $parent.selectedNotebook() === $data }, template: { name: 'notebook'}">
  135. </div>
  136. </div>
  137. </div>
  138. </div>
  139. </div>
  140. <div id="assistQuickLook" class="modal hide fade">
  141. <div class="modal-header">
  142. <a href="#" class="close" data-dismiss="modal">&times;</a>
  143. <h3>${_('Data sample for')} <span class="tableName"></span></h3>
  144. </div>
  145. <div class="modal-body" style="min-height: 100px">
  146. <div class="loader">
  147. <!--[if !IE]><!--><i class="fa fa-spinner fa-spin" style="font-size: 30px; color: #DDD"></i><!--<![endif]-->
  148. <!--[if IE]><img src="/static/art/spinner.gif"/><![endif]-->
  149. </div>
  150. <div class="sample"></div>
  151. </div>
  152. <div class="modal-footer">
  153. <button class="btn btn-primary disable-feedback" data-dismiss="modal">${_('Ok')}</button>
  154. </div>
  155. </div>
  156. <script type="text/html" id="notebook">
  157. <div class="row-fluid">
  158. <div class="span2" data-bind="visible: $root.isAssistVisible, css:{'span2': $root.isAssistVisible, 'hidden': !$root.isAssistVisible()}">
  159. <div class="assist">
  160. <a title="${_('Toggle Assist')}" class="pull-right pointer" style="margin:3px; margin-top:9px" data-bind="click: $root.toggleAssist">
  161. <i class="fa fa-chevron-left"></i>
  162. </a>
  163. <a title="${_('Manually refresh the table list')}" rel="tooltip" data-placement="top" class="pointer pull-right" style="margin:3px; margin-top:9px" data-bind="click: reloadAssist">
  164. <i class="fa fa-refresh"></i>
  165. </a>
  166. <ul class="nav nav-list" style="border: none; padding: 0; background-color: #FFF">
  167. <li class="nav-header">${_('database')}</li>
  168. </ul>
  169. <!-- ko if: $root.assistContent && $root.assistContent().mainObjects().length > 0 -->
  170. <select data-bind="options: $root.assistContent().mainObjects, select2: { width: '100%', placeholder: '${ _("Choose a database...") }', update: $root.assistSelectedMainObject}" class="input-medium" data-placeholder="${_('Choose a database...')}"></select>
  171. <input type="text" placeholder="${ _('Table name...') }" style="width:90%; margin-top: 20px"/>
  172. <div data-bind="visible: Object.keys($root.assistContent().firstLevelObjects()).length == 0">${_('The selected database has no tables.')}</div>
  173. <ul data-bind="visible: Object.keys($root.assistContent().firstLevelObjects()).length > 0, foreach: Object.keys($root.assistContent().firstLevelObjects())" class="unstyled assist-main">
  174. <li data-bind="event: { mouseover: function(){ $('#assistHover_' + $data).show(); }, mouseout: function(){ $('#assistHover_' + $data).hide(); } }">
  175. <a href="javascript:void(0)" class="pull-right" data-bind="attr: {'id': 'assistHover_' + $data}, click: showTablePreview" style="padding-right:5px; display: none"><i class="fa fa-list" title="${'Preview Sample data'}" style="margin-left:5px"></i></a>
  176. <a href="javascript:void(0)" data-bind="click: loadAssistSecondLevel"><span data-bind="text: $data"></span></a>
  177. <div data-bind="visible: $root.assistContent().firstLevelObjects()[$data].loaded() && $root.assistContent().firstLevelObjects()[$data].open()">
  178. <ul data-bind="visible: $root.assistContent().firstLevelObjects()[$data].items().length > 0, foreach: $root.assistContent().firstLevelObjects()[$data].items()" class="unstyled">
  179. <li><a data-bind="attr: {'title': secondLevelTitle($data)}" style="padding-left:10px" href="javascript:void(0)"><span data-bind="html: truncateSecondLevel($data)"></span></a></li>
  180. </ul>
  181. </div>
  182. </li>
  183. </ul>
  184. <!-- /ko -->
  185. <div id="navigatorLoader" class="center" data-bind="visible: $root.assistContent().isLoading">
  186. <!--[if !IE]><!--><i class="fa fa-spinner fa-spin" style="font-size: 20px; color: #BBB"></i><!--<![endif]-->
  187. <!--[if IE]><img src="/static/art/spinner.gif"/><![endif]-->
  188. </div>
  189. <div class="center" data-bind="visible: $root.assistContent().hasErrors">
  190. ${ _('The database list cannot be loaded.') }
  191. </div>
  192. </div>
  193. </div>
  194. <div data-bind="css:{'span10': $root.isAssistVisible, 'span12 nomargin': !$root.isAssistVisible()}">
  195. <div data-bind="css: {'row-fluid': true, 'row-container':true, 'is-editing': $root.isEditing},
  196. sortable: { template: 'snippet', data: snippets, isEnabled: $root.isEditing,
  197. options: {'handle': '.move-widget', 'opacity': 0.7, 'placeholder': 'row-highlight', 'greedy': true,
  198. 'stop': function(event, ui){$('.card-body').slideDown('fast', function(){$(window).scrollTop(lastWindowScrollPosition)});},
  199. 'helper': function(event){lastWindowScrollPosition = $(window).scrollTop(); $('.card-body').slideUp('fast'); var _par = $('<div>');_par.addClass('card card-widget');var _title = $('<h2>');_title.addClass('card-heading simple');_title.text($(event.toElement).text());_title.appendTo(_par);_par.height(80);_par.width(180);return _par;}},
  200. dragged: function(widget){$('.card-body').slideDown('fast', function(){$(window).scrollTop(lastWindowScrollPosition)});}}">
  201. </div>
  202. <h1 class="empty" data-bind="visible: snippets().length == 0">${ _('Add a snippet to start your new notebook') }</h1>
  203. <div class="add-snippet pointer">
  204. <div class="overlay pointer" data-bind="click: function(notebook, e){ if (!($(e.target).is('select'))){ newSnippet(); } }">
  205. <select data-bind="options: $root.availableSnippets, value: selectedSnippet, optionsText: 'name', optionsValue: 'type'" style="width: 115px"></select>
  206. <i class="fa fa-plus-circle fa-5x" title="${ _('Add a new snippet') }"></i>
  207. </div>
  208. </div>
  209. </div>
  210. </div>
  211. </script>
  212. <script type="text/html" id="snippet">
  213. <div class="row-fluid">
  214. <div data-bind="css: klass, attr: {'id': 'snippet_' + id()}">
  215. <h2 class="card-heading simple" data-bind="visible: $root.isEditing() || (! $root.isEditing() && type() != 'text')">
  216. <span data-bind="visible: $root.isEditing">
  217. <a href="javascript:void(0)" class="move-widget"><i class="fa fa-arrows"></i></a>
  218. <a href="javascript:void(0)" data-bind="click: compress, visible: size() > 1"><i class="fa fa-step-backward"></i></a>
  219. <a href="javascript:void(0)" data-bind="click: expand, visible: size() < 12"><i class="fa fa-step-forward"></i></a>
  220. &nbsp;
  221. </span>
  222. <!-- ko if: type() == 'text' -->
  223. <i class="fa fa-header snippet-icon"></i><sup style="color: #338bb8; margin-left: -2px">${ _('Text') }</sup>
  224. <!-- /ko -->
  225. <!-- ko if: type() == 'hive' -->
  226. <img src="/beeswax/static/art/icon_beeswax_48.png" class="snippet-icon">
  227. <!-- /ko -->
  228. <!-- ko if: type() == 'impala' -->
  229. <img src="/impala/static/art/icon_impala_48.png" class="snippet-icon">
  230. <!-- /ko -->
  231. <!-- ko if: type() == 'scala' -->
  232. <img src="/spark/static/art/icon_spark_48.png" class="snippet-icon"><sup style="color: #338bb8; margin-left: -2px">scala</sup>
  233. <!-- /ko -->
  234. <!-- ko if: type() == 'python' -->
  235. <img src="/spark/static/art/icon_spark_48.png" class="snippet-icon"><sup style="color: #338bb8; margin-left: -2px">python</sup>
  236. <!-- /ko -->
  237. <!-- ko if: type() == 'sql' -->
  238. <img src="/spark/static/art/icon_spark_48.png" class="snippet-icon"><sup style="color: #338bb8; margin-left: -2px">sql</sup>
  239. <!-- /ko -->
  240. <!-- ko if: type() == 'pig' -->
  241. <img src="/pig/static/art/icon_pig_48.png" class="snippet-icon">
  242. <!-- /ko -->
  243. <span data-bind="editable: name, editableOptions: {enabled: $root.isEditing(), placement: 'right'}"></span>
  244. <div class="inline pull-right">
  245. <a href="javascript:void(0)" data-bind="visible: $root.isEditing, click: function(){ remove($parent, $data); window.setTimeout(redrawFixedHeaders, 100);}"><i class="fa fa-times"></i></a>
  246. </div>
  247. </h2>
  248. <div data-bind="visible: type() != 'text'">
  249. <div class="row-fluid">
  250. <div data-bind="css: editorKlass">
  251. <div data-bind="foreach: variables">
  252. <div>
  253. <span data-bind="text: name"></span>
  254. <input type="text" data-bind="value: value" />
  255. </div>
  256. </div>
  257. <textarea data-bind="value: statement_raw, codemirror: { 'id': id(), 'viewportMargin': Infinity, 'lineNumbers': true, 'matchBrackets': true, 'mode': editorMode(), 'enter': execute }"></textarea>
  258. <a href="javascript:void(0)" title="${ _('CTRL + ENTER') }" data-bind="click: execute, visible: status() != 'running' && status() != 'loading'" class="btn codeMirror-overlaybtn">
  259. ${ _('Go!') }
  260. </a>
  261. <span title="${ _('Creating the session') }" data-bind="visible: status() == 'loading'" class="codeMirror-overlaybtn">
  262. <i class="fa fa-spinner fa-spin fa-2x"></i>
  263. </span>
  264. <a href="javascript:void(0)" data-bind="click: cancel, visible: status() == 'running'" class="btn codeMirror-overlaybtn">${ _('Cancel') }</a>
  265. <div class="progress" data-bind="css: {'progress-neutral': progress() == 0, 'progress-warning': progress() > 0 && progress() < 100, 'progress-success': progress() == 100}" style="height: 1px">
  266. <div class="bar" data-bind="style: {'width': progress() + '%'}"></div>
  267. </div>
  268. </div>
  269. </div>
  270. <div style="padding-top: 10px;">
  271. <a data-bind="visible: result.hasSomeResults(), click: function() { $data.showGrid(true); }, css: {'active': $data.showGrid}" href="javascript:void(0)" class="btn" title="${ _('Grid') }">
  272. <i class="fa fa-th"></i>
  273. </a>
  274. <div class="btn-group" data-bind="visible: type() != 'scala' && type() != 'python' && result.hasSomeResults()">
  275. <button class="btn dropdown-toggle" style="height: 31px" data-bind="css: {'active': $data.showChart}" data-toggle="dropdown">
  276. <i class="hcha hcha-bar-chart" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.BARCHART"></i>
  277. <i class="hcha hcha-line-chart" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.LINECHART"></i>
  278. <i class="hcha hcha-pie-chart" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.PIECHART"></i>
  279. <i class="fa fa-fw fa-dot-circle-o" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART"></i>
  280. <i class="fa fa-fw fa-map-marker" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.MAP"></i>
  281. <i class="hcha hcha-map-chart" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP"></i>
  282. <i class="fa fa-caret-down"></i>
  283. </button>
  284. <ul class="dropdown-menu">
  285. <li>
  286. <a href="javascript:void(0)" data-bind="css: {'active': chartType() == ko.HUE_CHARTS.TYPES.BARCHART}, click: function(){ $data.showChart(true); chartType(ko.HUE_CHARTS.TYPES.BARCHART); }">
  287. <i class="hcha hcha-bar-chart"></i> ${_('Bars')}
  288. </a>
  289. </li>
  290. <li>
  291. <a href="javascript:void(0)" data-bind="css: {'active': chartType() == ko.HUE_CHARTS.TYPES.LINECHART}, click: function(){ $data.showChart(true); chartType(ko.HUE_CHARTS.TYPES.LINECHART); }">
  292. <i class="hcha hcha-line-chart"></i> ${_('Lines')}
  293. </a>
  294. </li>
  295. <li>
  296. <a href="javascript:void(0)" data-bind="css: {'active': chartType() == ko.HUE_CHARTS.TYPES.PIECHART}, click: function(){ $data.showChart(true); chartType(ko.HUE_CHARTS.TYPES.PIECHART); }">
  297. <i class="hcha hcha-pie-chart"></i> ${_('Pie')}
  298. </a>
  299. </li>
  300. <li>
  301. <a href="javascript:void(0)" data-bind="css: {'active': chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART}, click: function(){ $data.showChart(true); chartType(ko.HUE_CHARTS.TYPES.SCATTERCHART); }">
  302. <i class="fa fa-fw fa-dot-circle-o chart-icon"></i> ${_('Scatter')}
  303. </a>
  304. </li>
  305. <li>
  306. <a href="javascript:void(0)" data-bind="css: {'active': chartType() == ko.HUE_CHARTS.TYPES.MAP}, click: function(){ $data.showChart(true); chartType(ko.HUE_CHARTS.TYPES.MAP); }">
  307. <i class="fa fa-fw fa-map-marker chart-icon"></i> ${_('Marker Map')}
  308. </a>
  309. </li>
  310. <li>
  311. <a href="javascript:void(0)" data-bind="css: {'active': chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP}, click: function(){ $data.showChart(true); chartType(ko.HUE_CHARTS.TYPES.GRADIENTMAP); }">
  312. <i class="hcha hcha-map-chart"></i> ${_('Gradient Map')}
  313. </a>
  314. </li>
  315. </ul>
  316. </div>
  317. <div class="pull-right">
  318. <strong class="muted" data-bind="visible: type() != 'text' && status() == 'available'">Took 1s</strong>
  319. &nbsp;
  320. <a data-bind="visible: status() != 'ready' && status() != 'loading', click: function() { $data.showLogs(! $data.showLogs()); window.setTimeout(redrawFixedHeaders, 100); }, css: {'active': $data.showLogs}" href="javascript:void(0)" class="btn" title="${ _('Show Logs') }">
  321. <i class="fa fa-file-text-o"></i>
  322. </a>
  323. &nbsp;
  324. <form method="POST" action="${ url('spark:download') }" class="download-form" style="display: inline">
  325. ${ csrf_token(request) | n,unicode }
  326. <input type="hidden" name="notebook" data-bind="value: ko.mapping.toJSON($root.selectedNotebook)"/>
  327. <input type="hidden" name="snippet" data-bind="value: ko.mapping.toJSON($data)"/>
  328. <input type="hidden" name="format" class="download-format"/>
  329. <div class="btn-group" data-bind="visible: status() == 'available' && result.hasSomeResults()">
  330. <button class="btn dropdown-toggle" data-toggle="dropdown">
  331. <i class="fa fa-download"></i>
  332. <i class="fa fa-caret-down"></i>
  333. </button>
  334. <ul class="dropdown-menu pull-right">
  335. <li>
  336. <a href="javascript:void(0)" data-bind="click: function() { $('#snippet_' + $data.id()).find('.download-format').val('csv'); $('#snippet_' + $data.id()).find('.download-form').submit(); }" title="${ _('Download first rows as CSV') }">
  337. <i class="fa fa-file-o"></i> ${ _('CSV') }
  338. </a>
  339. </li>
  340. <li>
  341. <a href="javascript:void(0)" data-bind="click: function() { $('#snippet_' + $data.id()).find('.download-format').val('xls'); $('#snippet_' + $data.id()).find('.download-form').submit(); }" title="${ _('Download first rows as XLS') }">
  342. <i class="fa fa-file-excel-o"></i> ${ _('Excel') }
  343. </a>
  344. </li>
  345. </ul>
  346. </div>
  347. </form>
  348. </div>
  349. </div>
  350. <div data-bind="visible: showLogs, css: resultsKlass" style="margin-top: 5px">
  351. <pre data-bind="visible: result.logs().length == 0" class="logs">${ _('Loading...') }</pre>
  352. <pre data-bind="visible: result.logs().length > 0, text: result.logs" class="logs"></pre>
  353. </div>
  354. <div data-bind="visible: result.errors().length > 0, css: resultsKlass">
  355. <span data-bind="text: result.errors"></span>
  356. </div>
  357. <div data-bind="visible: ! result.hasResultset() && status() == 'available', css: resultsKlass">
  358. ${ _('Success.') }
  359. </div>
  360. <div data-bind="visible: result.hasResultset() && status() == 'available' && result.data().length == 0 && result.meta().length > 0, css: resultsKlass">
  361. ${ _('Success but empty results.') }
  362. </div>
  363. <div class="row-fluid" data-bind="visible: result.hasSomeResults() && showGrid()" style="max-height: 400px; margin-top: 4px">
  364. <div data-bind="visible: isLeftPanelVisible, css:{'span2': isLeftPanelVisible, 'hidden': !isLeftPanelVisible()}">
  365. <ul class="nav nav-list" style="border: none; background-color: #FFF">
  366. <li class="nav-header pointer" data-bind="click: toggleLeftPanel" title="${_('Hide columns')}">${_('columns')}</li>
  367. </a>
  368. </ul>
  369. <ul class="unstyled" data-bind="foreach: result.meta">
  370. <li data-bind="visible: name != ''"><input type="checkbox" checked="checked" data-bind="event: { change: function(){toggleColumn($element, $index());}}" /> <a class="pointer" data-bind="text: $data.name, click: function(){ scrollToColumn($element, $index()); }"></a></li>
  371. </ul>
  372. </div>
  373. <div data-bind="css:{'span10': isLeftPanelVisible, 'span12 nomargin': !isLeftPanelVisible()}">
  374. <div class="toggle-left-panel" data-bind="click: toggleLeftPanel">
  375. <a title="${_('Show columns')}" class="pointer" data-bind="visible: !isLeftPanelVisible()">
  376. <i class="fa fa-chevron-right"></i>
  377. </a>
  378. <a title="${_('Hide')}" class="pointer" data-bind="visible: isLeftPanelVisible()">
  379. <i class="fa fa-chevron-left"></i>
  380. </a>
  381. </div>
  382. <div data-bind="css: resultsKlass">
  383. <table class="table table-condensed resultTable" data-tablescroller-fixed-height="360">
  384. <thead>
  385. <tr data-bind="foreach: result.meta">
  386. <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)}, attr: {'width': $index() == 0 ? '1%' : ''}"></th>
  387. </tr>
  388. </thead>
  389. <tbody>
  390. </tbody>
  391. </table>
  392. </div>
  393. </div>
  394. </div>
  395. <div class="row-fluid" data-bind="visible: result.meta().length > 0 && showChart()" style="max-height: 400px; margin-top: 4px">
  396. <div data-bind="visible: isLeftPanelVisible, css:{'span2': isLeftPanelVisible, 'hidden': ! isLeftPanelVisible()}">
  397. <div class="toggle-left-panel" style="float: right; margin-right: -30px; height: 400px; line-height: 400px; margin-top:0" data-bind="click: toggleLeftPanel">
  398. <a title="${_('Hide settings')}" class="pointer">
  399. <i class="fa fa-chevron-left"></i>
  400. </a>
  401. </div>
  402. <div>
  403. <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() != ''">
  404. <li data-bind="visible: chartType() != ko.HUE_CHARTS.TYPES.MAP && chartType() != ko.HUE_CHARTS.TYPES.GRADIENTMAP" class="nav-header">${_('x-axis')}</li>
  405. <li data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP" class="nav-header">${_('region')}</li>
  406. <li data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.MAP" class="nav-header">${_('latitude')}</li>
  407. </ul>
  408. <div data-bind="visible: chartType() != ''">
  409. <select data-bind="options: (chartType() == ko.HUE_CHARTS.TYPES.BARCHART || chartType() == ko.HUE_CHARTS.TYPES.PIECHART || chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP) ? result.cleanedMeta : result.cleanedNumericMeta, value: chartX, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_('Choose a column...')}', select2: { width: '100%', placeholder: '${ _("Choose a column...") }', update: chartX}" class="input-medium"></select>
  410. </div>
  411. <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() != ''">
  412. <li data-bind="visible: chartType() != ko.HUE_CHARTS.TYPES.MAP && chartType() != ko.HUE_CHARTS.TYPES.GRADIENTMAP" class="nav-header">${_('y-axis')}</li>
  413. <li data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP" class="nav-header">${_('value')}</li>
  414. <li data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.MAP" class="nav-header">${_('longitude')}</li>
  415. </ul>
  416. <div style="overflow-y: scroll; max-height: 220px" data-bind="visible: chartType() != '' && (chartType() == ko.HUE_CHARTS.TYPES.BARCHART || chartType() == ko.HUE_CHARTS.TYPES.LINECHART)">
  417. <ul class="unstyled" data-bind="foreach: result.cleanedNumericMeta">
  418. <li><input type="checkbox" data-bind="checkedValue: name, checked: $parent.chartYMulti" /> <span data-bind="text: $data.name"></span></li>
  419. </ul>
  420. </div>
  421. <div data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.PIECHART || chartType() == ko.HUE_CHARTS.TYPES.MAP || chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP || chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART">
  422. <select data-bind="options: chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP ? result.cleanedMeta : result.cleanedNumericMeta, value: chartYSingle, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_('Choose a column...')}', select2: { width: '100%', placeholder: '${ _("Choose a column...") }', update: chartYSingle}" class="input-medium"></select>
  423. </div>
  424. <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() != '' && chartType() == ko.HUE_CHARTS.TYPES.MAP">
  425. <li class="nav-header">${_('label')}</li>
  426. </ul>
  427. <div data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.MAP">
  428. <select data-bind="options: result.cleanedMeta, value: chartMapLabel, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_('Choose a column...')}', select2: { width: '100%', placeholder: '${ _("Choose a column...") }', update: chartMapLabel}" class="input-medium"></select>
  429. </div>
  430. <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() != '' && chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART">
  431. <li class="nav-header">${_('scatter group')}</li>
  432. </ul>
  433. <div data-bind="visible: chartType() != '' && chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART">
  434. <select data-bind="options: result.cleanedMeta, value: chartScatterGroup, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_('Choose a column...')}', select2: { width: '100%', placeholder: '${ _("Choose a column...") }', update: chartScatterGroup}" class="input-medium"></select>
  435. </div>
  436. <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART">
  437. <li class="nav-header">${_('scatter size')}</li>
  438. </ul>
  439. <div data-bind="visible: chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART">
  440. <select data-bind="options: result.cleanedMeta, value: chartScatterSize, optionsText: 'name', optionsValue: 'name', optionsCaption: '${_('Choose a column...')}', select2: { width: '100%', placeholder: '${ _("Choose a column...") }', update: chartScatterSize}" class="input-medium"></select>
  441. </div>
  442. <ul class="nav nav-list" style="border: none; background-color: #FFF" data-bind="visible: chartType() != '' && chartType() != ko.HUE_CHARTS.TYPES.MAP && chartType() != ko.HUE_CHARTS.TYPES.GRADIENTMAP && chartType() != ko.HUE_CHARTS.TYPES.SCATTERCHART">
  443. <li class="nav-header">${_('sorting')}</li>
  444. </ul>
  445. <div class="btn-group" data-toggle="buttons-radio" data-bind="visible: chartType() != '' && chartType() != ko.HUE_CHARTS.TYPES.MAP && chartType() != ko.HUE_CHARTS.TYPES.GRADIENTMAP && chartType() != ko.HUE_CHARTS.TYPES.SCATTERCHART">
  446. <a rel="tooltip" data-placement="top" title="${_('No sorting')}" href="javascript:void(0)" class="btn" data-bind="css: {'active': chartSorting() == 'none'}, click: function(){ chartSorting('none'); }"><i class="fa fa-align-left fa-rotate-270"></i></a>
  447. <a rel="tooltip" data-placement="top" title="${_('Sort ascending')}" href="javascript:void(0)" class="btn" data-bind="css: {'active': chartSorting() == 'asc'}, click: function(){ chartSorting('asc'); }"><i class="fa fa-sort-amount-asc fa-rotate-270"></i></a>
  448. <a rel="tooltip" data-placement="top" title="${_('Sort descending')}" href="javascript:void(0)" class="btn" data-bind="css: {'active': chartSorting() == 'desc'}, click: function(){ chartSorting('desc'); }"><i class="fa fa-sort-amount-desc fa-rotate-270"></i></a>
  449. </div>
  450. </div>
  451. </div>
  452. <div data-bind="css:{'span10': isLeftPanelVisible, 'span12 nomargin': !isLeftPanelVisible()}">
  453. <div class="toggle-left-panel" style="margin-right: -30px; height: 400px; line-height: 400px; margin-top:0" data-bind="visible: !isLeftPanelVisible(), click: toggleLeftPanel">
  454. <a title="${_('Show settings')}" class="pointer">
  455. <i class="fa fa-chevron-right"></i>
  456. </a>
  457. </div>
  458. <div data-bind="attr:{'id': 'pieChart_'+id()}, pieChart: {data: {counts: result.data, sorting: chartSorting(), snippet: $data}, fqs: ko.observableArray([]),
  459. transformer: pieChartDataTransformer, maxWidth: 350 }, visible: chartType() == ko.HUE_CHARTS.TYPES.PIECHART" class="chart"></div>
  460. <div data-bind="attr:{'id': 'barChart_'+id()}, barChart: {datum: {counts: result.data, sorting: chartSorting(), snippet: $data}, fqs: ko.observableArray([]), hideSelection: true,
  461. transformer: multiSerieDataTransformer, stacked: false, showLegend: true}, stacked: true, showLegend: true, visible: chartType() == ko.HUE_CHARTS.TYPES.BARCHART" class="chart"></div>
  462. <div data-bind="attr:{'id': 'lineChart_'+id()}, lineChart: {datum: {counts: result.data, sorting: chartSorting(), snippet: $data},
  463. transformer: multiSerieDataTransformer, showControls: false }, visible: chartType() == ko.HUE_CHARTS.TYPES.LINECHART" class="chart"></div>
  464. <div data-bind="attr:{'id': 'leafletMapChart_'+id()}, leafletMapChart: {datum: {counts: result.data, sorting: chartSorting(), snippet: $data},
  465. transformer: leafletMapChartDataTransformer, showControls: false, height: 380, visible: chartType() == ko.HUE_CHARTS.TYPES.MAP}" class="chart"></div>
  466. <div data-bind="attr:{'id': 'gradientMapChart_'+id()}, mapChart: {data: {counts: result.data, sorting: chartSorting(), snippet: $data},
  467. transformer: mapChartDataTransformer, isScale: true, showControls: false, height: 380, visible: chartType() == ko.HUE_CHARTS.TYPES.GRADIENTMAP}" class="chart"></div>
  468. <div data-bind="attr:{'id': 'scatterChart_'+id()}, scatterChart: {datum: {counts: result.data, sorting: chartSorting(), snippet: $data},
  469. transformer: scatterChartDataTransformer, maxWidth: 350 }, visible: chartType() == ko.HUE_CHARTS.TYPES.SCATTERCHART" class="chart"></div>
  470. </div>
  471. </div>
  472. </div>
  473. <div data-bind="visible: type() == 'text'">
  474. <div data-bind="html: statement_raw, visible: ! $root.isEditing()"></div>
  475. <div class="btn-toolbar" data-role="editor-toolbar" data-bind="attr:{'data-target': '#editor_'+id()}, visible: $root.isEditing()">
  476. <div class="btn-group">
  477. <a class="btn dropdown-toggle" data-toggle="dropdown" title="Font Size"><i class="fa fa-text-height"></i>&nbsp;<b class="caret"></b></a>
  478. <ul class="dropdown-menu">
  479. <li><a data-edit="fontSize 5"><font size="5">${ _("Huge") }</font></a></li>
  480. <li><a data-edit="fontSize 3"><font size="3">${ _("Normal") }</font></a></li>
  481. <li><a data-edit="fontSize 1"><font size="1">${ _("Small") }</font></a></li>
  482. </ul>
  483. </div>
  484. <div class="btn-group">
  485. <a class="btn" data-edit="bold" title="Bold (Ctrl/Cmd+B)"><i class="fa fa-bold"></i></a>
  486. <a class="btn" data-edit="italic" title="Italic (Ctrl/Cmd+I)"><i class="fa fa-italic"></i></a>
  487. <a class="btn" data-edit="strikethrough" title="Strikethrough"><i class="fa fa-strikethrough"></i></a>
  488. <a class="btn" data-edit="underline" title="Underline (Ctrl/Cmd+U)"><i class="fa fa-underline"></i></a>
  489. </div>
  490. <div class="btn-group">
  491. <a class="btn" data-edit="insertunorderedlist" title="Bullet list"><i class="fa fa-list-ul"></i></a>
  492. <a class="btn" data-edit="insertorderedlist" title="Number list"><i class="fa fa-list-ol"></i></a>
  493. <a class="btn" data-edit="outdent" title="Reduce indent (Shift+Tab)"><i class="fa fa-indent"></i></a>
  494. <a class="btn" data-edit="indent" title="Indent (Tab)"><i class="fa fa-outdent"></i></a>
  495. </div>
  496. <div class="btn-group">
  497. <a class="btn" data-edit="justifyleft" title="Align Left (Ctrl/Cmd+L)"><i class="fa fa-align-left"></i></a>
  498. <a class="btn" data-edit="justifycenter" title="Center (Ctrl/Cmd+E)"><i class="fa fa-align-center"></i></a>
  499. <a class="btn" data-edit="justifyright" title="Align Right (Ctrl/Cmd+R)"><i class="fa fa-align-right"></i></a>
  500. <a class="btn" data-edit="justifyfull" title="Justify (Ctrl/Cmd+J)"><i class="fa fa-align-justify"></i></a>
  501. </div>
  502. <div class="btn-group">
  503. <a class="btn dropdown-toggle" data-toggle="dropdown" title="Hyperlink"><i class="fa fa-link"></i></a>
  504. <div class="dropdown-menu input-append">
  505. <input class="span2" placeholder="URL" type="text" data-edit="createLink"/>
  506. <button class="btn" type="button">Add</button>
  507. </div>
  508. <a class="btn" data-edit="unlink" title="Remove Hyperlink"><i class="fa fa-cut"></i></a>
  509. </div>
  510. <div class="btn-group">
  511. <a class="btn" data-edit="undo" title="Undo (Ctrl/Cmd+Z)"><i class="fa fa-undo"></i></a>
  512. <a class="btn" data-edit="redo" title="Redo (Ctrl/Cmd+Y)"><i class="fa fa-repeat"></i></a>
  513. </div>
  514. </div>
  515. <div data-bind="attr:{'id': 'editor_'+id()}, html: statement_raw, value: statement_raw, wysiwyg: {}, visible: $root.isEditing()"></div>
  516. </div>
  517. </div>
  518. </div>
  519. </script>
  520. <script type="text/javascript" charset="utf-8">
  521. var assist = new Assist({
  522. app: "beeswax",
  523. user: "${user}",
  524. failsSilentlyOn: [500], // error codes from beeswax/views.py - autocomplete
  525. baseURL: "${url('beeswax:api_autocomplete_databases')}"
  526. });
  527. ko.bindingHandlers.wysiwyg = {
  528. init: function (element, valueAccessor, allBindings) {
  529. $(element).wysiwyg();
  530. $(element).on("paste", function () {
  531. window.setTimeout(function () {
  532. if (markdown.toHTML($(element).text().trim()) != "<p>" + $(element).text().trim() + "</p>") {
  533. allBindings().html(markdown.toHTML($(element).text().trim()));
  534. }
  535. }, 200);
  536. });
  537. $(element).on("blur", function () {
  538. allBindings().html($(element).cleanHtml());
  539. });
  540. }
  541. };
  542. ko.bindingHandlers.codemirror = {
  543. init: function (element, valueAccessor, allBindingsAccessor, snippet) {
  544. $(document).on("error.autocomplete", function () {
  545. $(".CodeMirror-spinner").remove();
  546. });
  547. function hiveImpalaAutocomplete(cm, autocompleteSet, comingFromKeyEvent) {
  548. CodeMirror.fromDot = false;
  549. CodeMirror.onAutocomplete = function (data, from, to) {
  550. if (data.indexOf("(") > -1) {
  551. cm.setCursor({line: from.line, ch: from.ch + data.length - 1});
  552. hiveImpalaAutocomplete(cm, autocompleteSet);
  553. }
  554. if (CodeMirror.tableFieldMagic) {
  555. cm.replaceRange(" ", from, from);
  556. cm.setCursor(from);
  557. hiveImpalaAutocomplete(cm, autocompleteSet);
  558. }
  559. };
  560. function splitStatements(hql) {
  561. var statements = [];
  562. var current = "";
  563. var betweenQuotes = null;
  564. for (var i = 0, len = hql.length; i < len; i++) {
  565. var c = hql[i];
  566. current += c;
  567. if ($.inArray(c, ['"', "'"]) > -1) {
  568. if (betweenQuotes == c) {
  569. betweenQuotes = null;
  570. }
  571. else if (betweenQuotes == null) {
  572. betweenQuotes = c;
  573. }
  574. }
  575. else if (c == ";") {
  576. if (betweenQuotes == null) {
  577. statements.push(current);
  578. current = "";
  579. }
  580. }
  581. }
  582. if (current != "" && current != ";") {
  583. statements.push(current);
  584. }
  585. return statements;
  586. }
  587. function getStatementAtCursor(cm) {
  588. var _pos = cm.indexFromPos(cm.getCursor());
  589. var _statements = splitStatements(cm.getValue());
  590. var _cumulativePos = 0;
  591. var _statementAtCursor = "";
  592. var _relativePos = 0;
  593. for (var i = 0; i < _statements.length; i++) {
  594. if (_cumulativePos + _statements[i].length >= _pos && _statementAtCursor == "") {
  595. _statementAtCursor = _statements[i].split("\n").join(" ");
  596. _relativePos = _pos - _cumulativePos;
  597. }
  598. _cumulativePos += _statements[i].length;
  599. }
  600. return {
  601. statement: _statementAtCursor,
  602. relativeIndex: _relativePos
  603. };
  604. }
  605. function getTableAliases(textScanned) {
  606. var _aliases = {};
  607. var _val = textScanned.split("\n").join(" ");
  608. var _from = _val.toUpperCase().indexOf("FROM ");
  609. if (_from > -1) {
  610. var _match = _val.toUpperCase().substring(_from).match(/ ON| LIMIT| WHERE| GROUP| SORT| ORDER BY|;/);
  611. var _to = _val.length;
  612. if (_match) {
  613. _to = _match.index;
  614. }
  615. var _found = _val.substr(_from, _to).replace(/(\r\n|\n|\r)/gm, "").replace(/from/gi, "").replace(/join/gi, ",").split(",");
  616. for (var i = 0; i < _found.length; i++) {
  617. var _tablealias = $.trim(_found[i]).split(" ");
  618. if (_tablealias.length > 1) {
  619. _aliases[_tablealias[1]] = _tablealias[0];
  620. }
  621. }
  622. }
  623. return _aliases;
  624. }
  625. function tableHasAlias(tableName, textScanned) {
  626. var _aliases = getTableAliases(textScanned);
  627. for (var alias in _aliases) {
  628. if (_aliases[alias] == tableName) {
  629. return true;
  630. }
  631. }
  632. return false;
  633. }
  634. function fieldsAutocomplete(cm) {
  635. CodeMirror.possibleSoloField = true;
  636. try {
  637. var _statement = getStatementAtCursor(cm).statement;
  638. var _from = _statement.toUpperCase().indexOf("FROM");
  639. if (_from > -1) {
  640. var _match = _statement.toUpperCase().substring(_from).match(/ ON| LIMIT| WHERE| GROUP| SORT| ORDER BY|;/);
  641. var _to = _statement.length;
  642. if (_match) {
  643. _to = _match.index;
  644. }
  645. var _found = _statement.substr(_from, _to).replace(/(\r\n|\n|\r)/gm, "").replace(/from/gi, "").replace(/join/gi, ",").split(",");
  646. }
  647. var _foundTable = "";
  648. for (var i = 0; i < _found.length; i++) {
  649. if ($.trim(_found[i]) != "" && _foundTable == "") {
  650. _foundTable = $.trim(_found[i]).split(" ")[0];
  651. }
  652. }
  653. if (_foundTable != "") {
  654. if (tableHasAlias(_foundTable, _statement)) {
  655. CodeMirror.possibleSoloField = false;
  656. CodeMirror.showHint(cm, autocompleteSet);
  657. }
  658. else {
  659. assist.options.onDataReceived = function (data) {
  660. if (data.columns) {
  661. CodeMirror.catalogFields = "* " + data.columns.join(" ");
  662. CodeMirror.showHint(cm, autocompleteSet);
  663. }
  664. }
  665. if (_foundTable.indexOf("(") > -1) {
  666. _foundTable = _foundTable.substr(_foundTable.indexOf("(") + 1);
  667. }
  668. var _aliases = getTableAliases(_statement);
  669. if (_aliases[_foundTable]) {
  670. _foundTable = _aliases[_foundTable];
  671. }
  672. assist.getData(viewModel.assistContent().selectedMainObject() + "/" + _foundTable);
  673. }
  674. }
  675. }
  676. catch (e) {
  677. }
  678. }
  679. var pos = cm.cursorCoords();
  680. if ($(".CodeMirror-spinner").length == 0) {
  681. $("<i class='fa fa-spinner fa-spin CodeMirror-spinner'></i>").appendTo($("body"));
  682. }
  683. $(".CodeMirror-spinner").css("top", pos.top + "px").css("left", (pos.left - 4) + "px").show();
  684. if (comingFromKeyEvent) {
  685. var _statement = getStatementAtCursor(cm).statement;
  686. var _line = cm.getLine(cm.getCursor().line);
  687. var _partial = _line.substring(0, cm.getCursor().ch);
  688. var _table = _partial.substring(_partial.lastIndexOf(" ") + 1, _partial.length - 1);
  689. if (_statement.indexOf("FROM") > -1) {
  690. assist.options.onDataReceived = function (data) {
  691. if (data.columns) {
  692. var _cols = data.columns;
  693. for (var col in _cols) {
  694. _cols[col] = "." + _cols[col];
  695. }
  696. CodeMirror.catalogFields = "* " + _cols.join(" ");
  697. CodeMirror.fromDot = true;
  698. CodeMirror.showHint(cm, autocompleteSet);
  699. }
  700. }
  701. if (_table.indexOf("(") > -1) {
  702. _table = _table.substr(_table.indexOf("(") + 1);
  703. }
  704. var _aliases = getTableAliases(_statement);
  705. if (_aliases[_table]) {
  706. _table = _aliases[_table];
  707. }
  708. assist.getData(viewModel.assistContent().selectedMainObject() + "/" + _table);
  709. }
  710. }
  711. else {
  712. assist.options.onDataReceived = function (data) {
  713. if (data.tables) {
  714. CodeMirror.catalogTables = data.tables.join(" ");
  715. var _statementAtCursor = getStatementAtCursor(cm);
  716. var _before = _statementAtCursor.statement.substr(0, _statementAtCursor.relativeIndex).replace(/;+$/, "");
  717. var _after = _statementAtCursor.statement.substr(_statementAtCursor.relativeIndex).replace(/;+$/, "");
  718. if ($.trim(_before).substr(-1) == ".") {
  719. var _statement = _statementAtCursor.statement;
  720. var _line = cm.getLine(cm.getCursor().line);
  721. var _partial = _line.substring(0, cm.getCursor().ch);
  722. var _table = _partial.substring(_partial.lastIndexOf(" ") + 1, _partial.length - 1);
  723. if (_statement.indexOf("FROM") > -1) {
  724. assist.options.onDataReceived = function (data) {
  725. if (data.columns) {
  726. var _cols = data.columns;
  727. for (var col in _cols) {
  728. _cols[col] = "." + _cols[col];
  729. }
  730. CodeMirror.catalogFields = "* " + _cols.join(" ");
  731. CodeMirror.showHint(cm, autocompleteSet);
  732. }
  733. }
  734. if (_table.indexOf("(") > -1) {
  735. _table = _table.substr(_table.indexOf("(") + 1);
  736. }
  737. var _aliases = getTableAliases(_statement);
  738. if (_aliases[_table]) {
  739. _table = _aliases[_table];
  740. }
  741. assist.getData(viewModel.assistContent().selectedMainObject() + "/" + _table);
  742. }
  743. }
  744. else {
  745. CodeMirror.possibleTable = false;
  746. CodeMirror.tableFieldMagic = false;
  747. if ((_before.toUpperCase().indexOf(" FROM ") > -1 || _before.toUpperCase().indexOf(" TABLE ") > -1 || _before.toUpperCase().indexOf(" STATS ") > -1) && _before.toUpperCase().indexOf(" ON ") == -1 && _before.toUpperCase().indexOf(" ORDER BY ") == -1 && _before.toUpperCase().indexOf(" WHERE ") == -1 ||
  748. _before.toUpperCase().indexOf("REFRESH") > -1 || _before.toUpperCase().indexOf("METADATA") > -1 || _before.toUpperCase().indexOf("DESCRIBE") > -1) {
  749. CodeMirror.possibleTable = true;
  750. }
  751. CodeMirror.possibleSoloField = false;
  752. if (_before.toUpperCase().indexOf("SELECT ") > -1 && _before.toUpperCase().indexOf(" FROM ") == -1 && !CodeMirror.fromDot) {
  753. if (_after.toUpperCase().indexOf("FROM ") > -1 || $.trim(_before).substr(-1) == "(") {
  754. fieldsAutocomplete(cm);
  755. }
  756. else {
  757. CodeMirror.tableFieldMagic = true;
  758. CodeMirror.showHint(cm, autocompleteSet);
  759. }
  760. }
  761. else {
  762. if ((_before.toUpperCase().indexOf("WHERE ") > -1 || _before.toUpperCase().indexOf("ORDER BY ") > -1) && !CodeMirror.fromDot && _before.toUpperCase().match(/ ON| LIMIT| GROUP| SORT/) == null) {
  763. fieldsAutocomplete(cm);
  764. }
  765. else {
  766. CodeMirror.showHint(cm, autocompleteSet);
  767. }
  768. }
  769. }
  770. }
  771. }
  772. assist.getData(viewModel.assistContent().selectedMainObject());
  773. }
  774. }
  775. var options = $.extend(valueAccessor(), {
  776. extraKeys: {
  777. "Ctrl-Space": function (cm) {
  778. $(document.body).on("contextmenu", function (e) {
  779. e.preventDefault(); // prevents native menu on FF for Mac from being shown
  780. });
  781. switch (valueAccessor().mode) {
  782. case "text/x-pig":
  783. CodeMirror.availableVariables = [];
  784. CodeMirror.showHint(cm, CodeMirror.pigHint);
  785. break;
  786. case "text/x-python":
  787. CodeMirror.showHint(cm, CodeMirror.pythonHint);
  788. break;
  789. case "text/x-scala":
  790. CodeMirror.showHint(cm, CodeMirror.scalaHint);
  791. break;
  792. case "text/x-hiveql":
  793. hiveImpalaAutocomplete(cm, CodeMirror.hiveQLHint);
  794. break;
  795. case "text/x-impalaql":
  796. hiveImpalaAutocomplete(cm, CodeMirror.impalaSQLHint);
  797. break;
  798. default:
  799. break;
  800. }
  801. },
  802. "Ctrl-Enter": function () {
  803. allBindingsAccessor().value(editor.getValue());
  804. valueAccessor().enter();
  805. }
  806. },
  807. onKeyEvent: function (cm, e) {
  808. switch (valueAccessor().mode) {
  809. case "text/x-hiveql":
  810. if (e.type == "keyup" && e.keyCode == 190) {
  811. hiveImpalaAutocomplete(cm, CodeMirror.hiveQLHint, true);
  812. }
  813. break;
  814. case "text/x-impalaql":
  815. if (e.type == "keyup" && e.keyCode == 190) {
  816. hiveImpalaAutocomplete(cm, CodeMirror.impalaSQLHint, true);
  817. }
  818. break;
  819. default:
  820. break;
  821. }
  822. }
  823. });
  824. var editor = CodeMirror.fromTextArea(element, options);
  825. element.editor = editor;
  826. $("#snippet_" + options.id).data("editor", editor);
  827. editor.setValue(allBindingsAccessor().value());
  828. editor.setSize("100%", "100px");
  829. var wrapperElement = $(editor.getWrapperElement());
  830. var _changeTimeout = -1;
  831. var _previousLineCount = 7;
  832. editor.on("change", function () {
  833. var _redraw = false;
  834. if (editor.lineCount() <= 7 && _previousLineCount > 7) {
  835. editor.setSize("100%", "100px");
  836. }
  837. else if (editor.lineCount() > 7 && editor.lineCount() < 21 && (_previousLineCount <=7 || _previousLineCount >= 20)) {
  838. editor.setSize("100%", "auto");
  839. }
  840. else if (_previousLineCount >= 20) {
  841. editor.setSize("100%", "270px");
  842. }
  843. if (_previousLineCount != editor.lineCount()){
  844. $("#snippet_" + snippet.id()).find(".resultTable").jHueTableExtender({
  845. fixedHeader: true,
  846. includeNavigator: false,
  847. parentId: snippet.id()
  848. });
  849. }
  850. _previousLineCount = editor.lineCount();
  851. window.clearTimeout(_changeTimeout);
  852. _changeTimeout = window.setTimeout(function(){
  853. allBindingsAccessor().value(editor.getValue());
  854. }, 600);
  855. });
  856. ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
  857. wrapperElement.remove();
  858. });
  859. }
  860. };
  861. var options = ${ options_json | n,unicode };
  862. $.extend(options, {
  863. assistVisible: $.totalStorage("sparkAssistVisible") != null ? $.totalStorage("sparkAssistVisible") : true
  864. });
  865. viewModel = new EditorViewModel(${ notebooks_json | n,unicode }, options);
  866. viewModel.assistContent(assist);
  867. ko.applyBindings(viewModel);
  868. viewModel.init();
  869. viewModel.assistSelectedMainObject.subscribe(function(newVal) {
  870. viewModel.assistContent().selectedMainObject(newVal);
  871. loadAssistFirstLevel();
  872. });
  873. function loadAssistSecondLevel(first) {
  874. if (!viewModel.assistContent().firstLevelObjects()[first].loaded()) {
  875. viewModel.assistContent().isLoading(true);
  876. assist.options.onDataReceived = function (data) {
  877. if (data.columns) {
  878. var _cols = data.extended_columns ? data.extended_columns : data.columns;
  879. viewModel.assistContent().firstLevelObjects()[first].items(_cols);
  880. viewModel.assistContent().firstLevelObjects()[first].loaded(true);
  881. }
  882. viewModel.assistContent().isLoading(false);
  883. }
  884. assist.getData(viewModel.assistContent().selectedMainObject() + "/" + first);
  885. }
  886. viewModel.assistContent().firstLevelObjects()[first].open(!viewModel.assistContent().firstLevelObjects()[first].open());
  887. window.setTimeout(resizeAssist, 100);
  888. }
  889. function loadAssistFirstLevel() {
  890. assist.options.onDataReceived = function (data) {
  891. if (data.tables) {
  892. var _obj = {};
  893. data.tables.forEach(function (item) {
  894. _obj[item] = {
  895. items: ko.observableArray([]),
  896. open: ko.observable(false),
  897. loaded: ko.observable(false)
  898. }
  899. });
  900. viewModel.assistContent().firstLevelObjects(_obj);
  901. }
  902. viewModel.assistContent().isLoading(false);
  903. }
  904. assist.getData(viewModel.assistContent().selectedMainObject());
  905. }
  906. function loadAssistMain(force) {
  907. assist.options.onDataReceived = function (data) {
  908. if (data.databases) {
  909. viewModel.assistContent().mainObjects(data.databases);
  910. if (viewModel.assistContent().mainObjects().length > 0 && !viewModel.assistContent().selectedMainObject()) {
  911. viewModel.assistContent().selectedMainObject(viewModel.assistContent().mainObjects()[0]);
  912. viewModel.assistSelectedMainObject(viewModel.assistContent().selectedMainObject());
  913. loadAssistFirstLevel();
  914. }
  915. }
  916. }
  917. assist.options.onError = function (error) {
  918. viewModel.assistContent().isLoading(false);
  919. }
  920. assist.getData(null, force);
  921. }
  922. loadAssistMain();
  923. function reloadAssist() {
  924. loadAssistMain(true);
  925. }
  926. function needsTruncation(level) {
  927. return (level.name.length + level.type.length) > 20;
  928. }
  929. function secondLevelTitle(level) {
  930. var _title = "";
  931. if (level.comment && needsTruncation(level)) {
  932. _title = level.name + " (" + level.type + "): " + level.comment;
  933. } else if (needsTruncation(level)) {
  934. _title = level.name + " (" + level.type + ")";
  935. } else if (level.comment) {
  936. _title = level.comment;
  937. }
  938. return _title;
  939. }
  940. function truncateSecondLevel(level) {
  941. var escapeString = function (str) {
  942. return $("<span>").text(str).html().trim()
  943. }
  944. if (needsTruncation(level)) {
  945. return escapeString(level.name + " (" + level.type + ")").substr(0, 20) + "&hellip;";
  946. }
  947. return escapeString(level.name + " (" + level.type + ")");
  948. }
  949. function resizeAssist() {
  950. $(".assist").width($(".assist").parents(".span2").width());
  951. $(".assist").parents(".span2").height($(".assist").height() + 100);
  952. $(".assist-main").height($(window).height() - 230);
  953. }
  954. function createDatatable(el, snippet) {
  955. $(el).addClass("dt");
  956. var _dt = $(el).dataTable({
  957. "bPaginate": false,
  958. "bLengthChange": false,
  959. "bInfo": false,
  960. "bDestroy": true,
  961. "bAutoWidth": false,
  962. "oLanguage": {
  963. "sEmptyTable": "${_('No data available')}",
  964. "sZeroRecords": "${_('No matching records')}"
  965. },
  966. "fnDrawCallback": function (oSettings) {
  967. $(el).parents(".dataTables_wrapper").jHueTableScroller({
  968. minHeight: $(window).height() - 400,
  969. heightAfterCorrection: 0
  970. });
  971. $(el).jHueTableExtender({
  972. fixedHeader: true,
  973. includeNavigator: false,
  974. parentId: snippet.id()
  975. });
  976. },
  977. "aoColumnDefs": [
  978. {
  979. "sType": "numeric",
  980. "aTargets": [ "sort-numeric" ]
  981. },
  982. {
  983. "sType": "string",
  984. "aTargets": [ "sort-string" ]
  985. },
  986. {
  987. "sType": "date",
  988. "aTargets": [ "sort-date" ]
  989. }
  990. ]
  991. });
  992. $(el).parents(".dataTables_wrapper").jHueTableScroller({
  993. minHeight: $(window).height() - 400,
  994. heightAfterCorrection: 0
  995. });
  996. $(el).jHueTableExtender({
  997. fixedHeader: true,
  998. includeNavigator: false,
  999. parentId: snippet.id()
  1000. });
  1001. $(".dataTables_filter").hide();
  1002. var dataTableEl = $(el).parents(".dataTables_wrapper");
  1003. dataTableEl.bind('mousewheel DOMMouseScroll wheel', function (e) {
  1004. var _e = e.originalEvent,
  1005. _deltaX = _e.wheelDeltaX || -_e.deltaX,
  1006. _deltaY = _e.wheelDeltaY || -_e.deltaY;
  1007. this.scrollTop += -_deltaY / 2;
  1008. this.scrollLeft += -_deltaX / 2;
  1009. if (this.scrollTop == 0){
  1010. $("body")[0].scrollTop += -_deltaY / 3;
  1011. $("html")[0].scrollTop += -_deltaY / 3; // for firefox
  1012. }
  1013. e.preventDefault();
  1014. });
  1015. var _scrollTimeout = -1;
  1016. dataTableEl.on("scroll", function () {
  1017. var _lastScrollPosition = dataTableEl.data("scrollPosition") != null ? dataTableEl.data("scrollPosition") : 0;
  1018. window.clearTimeout(_scrollTimeout);
  1019. _scrollTimeout = window.setTimeout(function () {
  1020. dataTableEl.data("scrollPosition", dataTableEl.scrollTop());
  1021. if (_lastScrollPosition != dataTableEl.scrollTop() && dataTableEl.scrollTop() + dataTableEl.outerHeight() + 20 > dataTableEl[0].scrollHeight && _dt) {
  1022. dataTableEl.animate({opacity: '0.55'}, 200);
  1023. snippet.fetchResult(100, false);
  1024. }
  1025. }, 100);
  1026. });
  1027. return _dt;
  1028. }
  1029. function toggleColumn(linkElement, index) {
  1030. var _dt = $(linkElement).parents(".snippet").find("table:eq(1)").dataTable();
  1031. _dt.fnSetColumnVis(index, !_dt.fnSettings().aoColumns[index].bVisible);
  1032. }
  1033. function scrollToColumn(linkElement) {
  1034. var _t = $(linkElement).parents(".snippet").find("table:eq(1)");
  1035. var _text = $.trim($(linkElement).text().split("(")[0]);
  1036. var _col = _t.find("th").filter(function () {
  1037. return $.trim($(this).text()) == _text;
  1038. });
  1039. _t.find(".columnSelected").removeClass("columnSelected");
  1040. var _colSel = _t.find("tr td:nth-child(" + (_col.index() + 1) + ")");
  1041. if (_colSel.length > 0) {
  1042. _colSel.addClass("columnSelected");
  1043. _t.parent().animate({
  1044. scrollLeft: _colSel.position().left + _t.parent().scrollLeft() - _t.parent().offset().left - 30
  1045. }, 300);
  1046. }
  1047. }
  1048. function isNumericColumn(type) {
  1049. return $.inArray(type, ['TINYINT_TYPE', 'SMALLINT_TYPE', 'INT_TYPE', 'BIGINT_TYPE', 'FLOAT_TYPE', 'DOUBLE_TYPE', 'DECIMAL_TYPE', 'TIMESTAMP_TYPE', 'DATE_TYPE']) > -1;
  1050. }
  1051. function isDateTimeColumn(type) {
  1052. return $.inArray(type, ['TIMESTAMP_TYPE', 'DATE_TYPE']) > -1;
  1053. }
  1054. function isStringColumn(type) {
  1055. return !isNumericColumn(type) && !isDateTimeColumn(type);
  1056. }
  1057. function pieChartDataTransformer(rawDatum) {
  1058. var _data = [];
  1059. if (rawDatum.snippet.chartX() != null && rawDatum.snippet.chartYSingle() != null) {
  1060. var _idxValue = -1;
  1061. var _idxLabel = -1;
  1062. rawDatum.snippet.result.meta().forEach(function (col, idx) {
  1063. if (col.name == rawDatum.snippet.chartX()) {
  1064. _idxLabel = idx;
  1065. }
  1066. if (col.name == rawDatum.snippet.chartYSingle()) {
  1067. _idxValue = idx;
  1068. }
  1069. });
  1070. $(rawDatum.counts()).each(function (cnt, item) {
  1071. _data.push({
  1072. label: item[_idxLabel],
  1073. value: item[_idxValue],
  1074. obj: item
  1075. });
  1076. });
  1077. }
  1078. if (rawDatum.sorting == "asc") {
  1079. _data.sort(function (a, b) {
  1080. return a.value > b.value
  1081. });
  1082. }
  1083. if (rawDatum.sorting == "desc") {
  1084. _data.sort(function (a, b) {
  1085. return b.value > a.value
  1086. });
  1087. }
  1088. return _data;
  1089. }
  1090. function mapChartDataTransformer(rawDatum) {
  1091. var _data = [];
  1092. if (rawDatum.snippet.chartX() != null && rawDatum.snippet.chartYSingle() != null) {
  1093. var _idxRegion = -1;
  1094. var _idxValue = -1;
  1095. rawDatum.snippet.result.meta().forEach(function (col, idx) {
  1096. if (col.name == rawDatum.snippet.chartX()) {
  1097. _idxRegion = idx;
  1098. }
  1099. if (col.name == rawDatum.snippet.chartYSingle()) {
  1100. _idxValue = idx;
  1101. }
  1102. });
  1103. $(rawDatum.counts()).each(function (cnt, item) {
  1104. _data.push({
  1105. label: item[_idxRegion],
  1106. value: item[_idxValue],
  1107. obj: item
  1108. });
  1109. });
  1110. }
  1111. return _data;
  1112. }
  1113. function leafletMapChartDataTransformer(rawDatum) {
  1114. var _data = [];
  1115. if (rawDatum.snippet.chartX() != null && rawDatum.snippet.chartYSingle() != null) {
  1116. var _idxLat = -1;
  1117. var _idxLng = -1;
  1118. var _idxLabel = -1;
  1119. rawDatum.snippet.result.meta().forEach(function (col, idx) {
  1120. if (col.name == rawDatum.snippet.chartX()) {
  1121. _idxLat = idx;
  1122. }
  1123. if (col.name == rawDatum.snippet.chartYSingle()) {
  1124. _idxLng = idx;
  1125. }
  1126. if (col.name == rawDatum.snippet.chartMapLabel()) {
  1127. _idxLabel = idx;
  1128. }
  1129. });
  1130. if (rawDatum.snippet.chartMapLabel() != null) {
  1131. $(rawDatum.counts()).each(function (cnt, item) {
  1132. _data.push({
  1133. lat: item[_idxLat],
  1134. lng: item[_idxLng],
  1135. label: item[_idxLabel],
  1136. obj: item
  1137. });
  1138. });
  1139. }
  1140. else {
  1141. $(rawDatum.counts()).each(function (cnt, item) {
  1142. _data.push({
  1143. lat: item[_idxLat],
  1144. lng: item[_idxLng],
  1145. obj: item
  1146. });
  1147. });
  1148. }
  1149. }
  1150. return _data;
  1151. }
  1152. function multiSerieDataTransformer(rawDatum) {
  1153. var _datum = [];
  1154. if (rawDatum.snippet.chartX() != null && rawDatum.snippet.chartYMulti().length > 0) {
  1155. var _plottedSerie = 0;
  1156. rawDatum.snippet.chartYMulti().forEach(function (col) {
  1157. var _idxValue = -1;
  1158. var _idxLabel = -1;
  1159. rawDatum.snippet.result.meta().forEach(function (icol, idx) {
  1160. if (icol.name == rawDatum.snippet.chartX()) {
  1161. _idxLabel = idx;
  1162. }
  1163. if (icol.name == col) {
  1164. _idxValue = idx;
  1165. }
  1166. });
  1167. if (_idxValue > -1) {
  1168. var _data = [];
  1169. $(rawDatum.counts()).each(function (cnt, item) {
  1170. _data.push({
  1171. series: _plottedSerie,
  1172. x: item[_idxLabel],
  1173. y: item[_idxValue],
  1174. obj: item
  1175. });
  1176. });
  1177. if (rawDatum.sorting == "asc") {
  1178. _data.sort(function (a, b) {
  1179. return a.y > b.y
  1180. });
  1181. }
  1182. if (rawDatum.sorting == "desc") {
  1183. _data.sort(function (a, b) {
  1184. return b.y > a.y
  1185. });
  1186. }
  1187. _datum.push({
  1188. key: col,
  1189. values: _data
  1190. });
  1191. _plottedSerie++;
  1192. }
  1193. });
  1194. }
  1195. return _datum;
  1196. }
  1197. function scatterChartDataTransformer(rawDatum) {
  1198. var _datum = [];
  1199. if (rawDatum.snippet.chartX() != null && rawDatum.snippet.chartYSingle() != null) {
  1200. function addToDatum(col) {
  1201. var _idxX = -1;
  1202. var _idxY = -1;
  1203. var _idxSize = -1;
  1204. var _idxGroup = -1;
  1205. rawDatum.snippet.result.meta().forEach(function (icol, idx) {
  1206. if (icol.name == rawDatum.snippet.chartX()) {
  1207. _idxX = idx;
  1208. }
  1209. if (icol.name == rawDatum.snippet.chartYSingle()) {
  1210. _idxY = idx;
  1211. }
  1212. if (icol.name == rawDatum.snippet.chartScatterSize()) {
  1213. _idxSize = idx;
  1214. }
  1215. if (icol.name == rawDatum.snippet.chartScatterGroup()) {
  1216. _idxGroup = idx;
  1217. }
  1218. });
  1219. if (_idxX > -1 && _idxY > -1) {
  1220. var _data = [];
  1221. $(rawDatum.counts()).each(function (cnt, item) {
  1222. if (_idxGroup == -1 || item[_idxGroup] == col){
  1223. _data.push({
  1224. x: item[_idxX],
  1225. y: item[_idxY],
  1226. shape: 'circle',
  1227. size: _idxSize > -1 ? item[_idxSize] : 100,
  1228. obj: item
  1229. });
  1230. }
  1231. });
  1232. _datum.push({
  1233. key: col,
  1234. values: _data
  1235. });
  1236. }
  1237. }
  1238. if (rawDatum.snippet.chartScatterGroup() != null){
  1239. var _idxGroup = -1;
  1240. rawDatum.snippet.result.meta().forEach(function (icol, idx) {
  1241. if (icol.name == rawDatum.snippet.chartScatterGroup()) {
  1242. _idxGroup = idx;
  1243. }
  1244. });
  1245. if (_idxGroup > -1) {
  1246. $(rawDatum.counts()).each(function (cnt, item) {
  1247. addToDatum(item[_idxGroup]);
  1248. });
  1249. }
  1250. }
  1251. else {
  1252. addToDatum('${ _('Distribution') }');
  1253. }
  1254. }
  1255. return _datum;
  1256. }
  1257. function showTablePreview(table) {
  1258. var tableUrl = "/beeswax/api/table/" + viewModel.assistContent().selectedMainObject() + "/" + table;
  1259. $("#assistQuickLook").find(".tableName").text(table);
  1260. $("#assistQuickLook").find(".tableLink").attr("href", "/metastore/table/" + viewModel.assistContent().selectedMainObject() + "/" + table);
  1261. $("#assistQuickLook").find(".sample").empty("");
  1262. $("#assistQuickLook").attr("style", "width: " + ($(window).width() - 120) + "px;margin-left:-" + (($(window).width() - 80) / 2) + "px!important;");
  1263. $.ajax({
  1264. url: tableUrl,
  1265. data: {"sample": true},
  1266. beforeSend: function (xhr) {
  1267. xhr.setRequestHeader("X-Requested-With", "Hue");
  1268. },
  1269. dataType: "html",
  1270. success: function (data) {
  1271. $("#assistQuickLook").find(".loader").hide();
  1272. $("#assistQuickLook").find(".sample").html(data);
  1273. },
  1274. error: function (e) {
  1275. if (e.status == 500) {
  1276. $(document).trigger("error", "${ _('There was a problem loading the table preview.') }");
  1277. $("#assistQuickLook").modal("hide");
  1278. }
  1279. }
  1280. });
  1281. $("#assistQuickLook").modal("show");
  1282. }
  1283. function redrawFixedHeaders() {
  1284. viewModel.notebooks().forEach(function (notebook) {
  1285. notebook.snippets().forEach(function (snippet) {
  1286. var _el = $("#snippet_" + snippet.id()).find(".resultTable");
  1287. _el.jHueTableExtender({
  1288. fixedHeader: true,
  1289. includeNavigator: false,
  1290. parentId: snippet.id()
  1291. });
  1292. });
  1293. });
  1294. }
  1295. $(document).ready(function () {
  1296. resizeAssist();
  1297. $(document).on("toggleAssist", function(){
  1298. $.totalStorage("sparkAssistVisible", viewModel.isAssistVisible());
  1299. resizeAssist();
  1300. });
  1301. $(document).on("toggleLeftPanel", function(e, snippet){
  1302. $("#snippet_" + snippet.id()).find(".chart").trigger("forceUpdate");
  1303. redrawFixedHeaders();
  1304. });
  1305. $(document).on("executeStarted", function (e, snippet) {
  1306. var _el = $("#snippet_" + snippet.id()).find(".resultTable");
  1307. $("#snippet_" + snippet.id()).find(".progress").animate({
  1308. height: "4px"
  1309. }, 100);
  1310. if (_el.hasClass("dt")) {
  1311. _el.removeClass("dt");
  1312. $("#eT" + snippet.id() + "jHueTableExtenderClonedContainer").remove();
  1313. _el.dataTable().fnClearTable();
  1314. _el.dataTable().fnDestroy();
  1315. _el.find("thead tr").empty();
  1316. }
  1317. snippet.tempChartOptions = {
  1318. x: snippet.chartX(),
  1319. yS: snippet.chartYSingle(),
  1320. yM: snippet.chartYMulti(),
  1321. label: snippet.chartMapLabel()
  1322. }
  1323. });
  1324. $(document).on("renderData", function (e, options) {
  1325. var _el = $("#snippet_" + options.snippet.id()).find(".resultTable");
  1326. if (options.data.length > 0) {
  1327. window.setTimeout(function () {
  1328. var _dt;
  1329. if (options.initial) {
  1330. options.snippet.result.meta.notifySubscribers();
  1331. $("#snippet_" + options.snippet.id()).find("select").trigger("chosen:updated");
  1332. _dt = createDatatable(_el, options.snippet);
  1333. }
  1334. else {
  1335. _dt = _el.dataTable();
  1336. }
  1337. _dt.fnAddData(options.data);
  1338. var _dtElement = $("#snippet_" + options.snippet.id()).find(".dataTables_wrapper");
  1339. _dtElement.animate({opacity: '1'}, 50);
  1340. _dtElement.scrollTop(_dtElement.data("scrollPosition"));
  1341. redrawFixedHeaders();
  1342. _dtElement.parent().siblings(".toggle-left-panel").height(_dtElement.height());
  1343. }, 100);
  1344. }
  1345. else {
  1346. var _dtElement = $("#snippet_" + options.snippet.id()).find(".dataTables_wrapper");
  1347. _dtElement.animate({opacity: '1'}, 50);
  1348. _dtElement.off("scroll");
  1349. }
  1350. options.snippet.chartX(options.snippet.tempChartOptions.x);
  1351. options.snippet.chartX(options.snippet.tempChartOptions.x);
  1352. options.snippet.chartYSingle(options.snippet.tempChartOptions.yS);
  1353. options.snippet.chartMapLabel(options.snippet.tempChartOptions.label);
  1354. $("#snippet_" + options.snippet.id()).find("select").trigger('chosen:updated');
  1355. });
  1356. $(document).on("progress", function (e, options) {
  1357. if (options.data == 100) {
  1358. window.setTimeout(function () {
  1359. $("#snippet_" + options.snippet.id()).find(".progress").animate({
  1360. height: "1px"
  1361. }, 100, function () {
  1362. options.snippet.progress(0);
  1363. redrawFixedHeaders();
  1364. });
  1365. }, 2000);
  1366. }
  1367. });
  1368. $(document).on("forceChartDraw", function (e, snippet) {
  1369. window.setTimeout(function () {
  1370. snippet.chartX.notifySubscribers();
  1371. }, 100);
  1372. });
  1373. viewModel.notebooks().forEach(function (notebook) {
  1374. notebook.snippets().forEach(function (snippet) {
  1375. if (snippet.result.data().length > 0) {
  1376. var _el = $("#snippet_" + snippet.id()).find(".resultTable");
  1377. window.setTimeout(function () {
  1378. var _dt = createDatatable(_el, snippet);
  1379. _dt.fnAddData(snippet.result.data());
  1380. var _dtElement = $("#snippet_" + snippet.id()).find(".dataTables_wrapper");
  1381. _dtElement.parent().siblings(".toggle-left-panel").css({
  1382. "height": (_dtElement.height() - 30) + "px",
  1383. "line-height": (_dtElement.height() - 30) + "px"
  1384. });
  1385. $(document).trigger("forceChartDraw", snippet);
  1386. }, 100);
  1387. }
  1388. });
  1389. });
  1390. $(".CodeMirror").each(function () {
  1391. $(this)[0].CodeMirror.refresh();
  1392. });
  1393. var _resizeTimeout = -1;
  1394. $(window).on("resize", function(){
  1395. window.clearTimeout(_resizeTimeout);
  1396. _resizeTimeout = window.setTimeout(resizeAssist, 200);
  1397. });
  1398. });
  1399. </script>
  1400. ${ commonfooter(messages) | n,unicode }