hue.mako 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202
  1. ## Licensed to Cloudera, Inc. under one
  2. ## or more contributor license agreements. See the NOTICE file
  3. ## distributed with this work for additional information
  4. ## regarding copyright ownership. Cloudera, Inc. licenses this file
  5. ## to you under the Apache License, Version 2.0 (the
  6. ## "License"); you may not use this file except in compliance
  7. ## with the License. You may obtain a copy of the License at
  8. ##
  9. ## http://www.apache.org/licenses/LICENSE-2.0
  10. ##
  11. ## Unless required by applicable law or agreed to in writing, software
  12. ## distributed under the License is distributed on an "AS IS" BASIS,
  13. ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ## See the License for the specific language governing permissions and
  15. ## limitations under the License.
  16. <%!
  17. from django.utils.translation import ugettext as _
  18. from desktop import conf
  19. from desktop.views import _ko
  20. from desktop.lib.i18n import smart_unicode
  21. from desktop.views import login_modal
  22. from dashboard.conf import IS_ENABLED as IS_DASHBOARD_ENABLED
  23. from metadata.conf import has_optimizer, OPTIMIZER
  24. from notebook.conf import SHOW_NOTEBOOKS
  25. %>
  26. <%namespace name="koComponents" file="/ko_components.mako" />
  27. <%namespace name="assist" file="/assist.mako" />
  28. <%namespace name="hueIcons" file="/hue_icons.mako" />
  29. <%namespace name="commonHeaderFooterComponents" file="/common_header_footer_components.mako" />
  30. <!DOCTYPE html>
  31. <html lang="en" dir="ltr">
  32. <head>
  33. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  34. <meta charset="utf-8">
  35. <title>Hue</title>
  36. <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  37. <link rel="icon" type="image/x-icon" href="${ static('desktop/art/favicon.ico') }"/>
  38. <meta name="description" content="">
  39. <meta name="author" content="">
  40. <link href="${ static('desktop/ext/css/cui/cui.css') }" rel="stylesheet">
  41. <link href="${ static('desktop/ext/css/cui/bootstrap2.css') }" rel="stylesheet">
  42. <link href="${ static('desktop/ext/css/cui/bootstrap-responsive2.css') }" rel="stylesheet">
  43. <link href="${ static('desktop/ext/css/font-awesome.min.css') }" rel="stylesheet">
  44. <link href="${ static('desktop/css/hue.css') }" rel="stylesheet">
  45. <link href="${ static('desktop/css/jquery-ui.css') }" rel="stylesheet">
  46. ${ commonHeaderFooterComponents.header_i18n_redirection(user, is_s3_enabled, apps) }
  47. <script type="text/javascript">
  48. var IS_HUE_4 = true;
  49. </script>
  50. <script src="${ static('desktop/js/hue4.utils.js') }"></script>
  51. </head>
  52. <body>
  53. % if is_demo:
  54. <ul class="side-labels unstyled">
  55. <li class="feedback"><a href="javascript:showClassicWidget()"><i class="fa fa-envelope-o"></i> ${_('Feedback')}</a></li>
  56. </ul>
  57. <!-- UserVoice JavaScript SDK -->
  58. <script>(function(){var uv=document.createElement('script');uv.type='text/javascript';uv.async=true;uv.src='//widget.uservoice.com/8YpsDfIl1Y2sNdONoLXhrg.js';var s=document.getElementsByTagName('script')[0];s.parentNode.insertBefore(uv,s)})()</script>
  59. <script>
  60. UserVoice = window.UserVoice || [];
  61. function showClassicWidget() {
  62. UserVoice.push(['showLightbox', 'classic_widget', {
  63. mode: 'feedback',
  64. primary_color: '#338cb8',
  65. link_color: '#338cb8',
  66. forum_id: 247008
  67. }]);
  68. }
  69. </script>
  70. % endif
  71. <div id="jHueNotify" class="alert hide">
  72. <button class="close">&times;</button>
  73. <div class="message"></div>
  74. </div>
  75. ${ hueIcons.symbols() }
  76. % if conf.CUSTOM.BANNER_TOP_HTML.get():
  77. <div class="banner">
  78. ${ conf.CUSTOM.BANNER_TOP_HTML.get() | n,unicode }
  79. </div>
  80. % endif
  81. <div class="main-page">
  82. <nav class="navbar">
  83. <div class="navbar-inner top-nav">
  84. <div class="top-nav-left">
  85. <a class="hamburger hamburger-hue pull-left" type="button" data-bind="toggle: leftNavVisible, css: { 'is-active': leftNavVisible }">
  86. <span class="hamburger-box"><span class="hamburger-inner"></span></span>
  87. </a>
  88. <a class="brand" data-bind="click: function () { page('/home') }" href="javascript: void(0);" title="${_('Documents')}">
  89. <svg style="height: 24px; width: 120px;"><use xlink:href="#hi-logo"></use></svg>
  90. </a>
  91. <div class="compose-action btn-group">
  92. <button class="btn" data-bind="click: function(){ page('/editor'); onePageViewModel.changeEditorType('hive', true); }" title="${ _('Hive editor') }">${ _('Compose') }</button>
  93. <button class="btn dropdown-toggle" data-toggle="dropdown">
  94. <span class="caret"></span>
  95. </button>
  96. <ul class="dropdown-menu">
  97. % if 'beeswax' in apps or 'impala' in apps or SHOW_NOTEBOOKS.get() or interpreters:
  98. <li class="dropdown-submenu">
  99. <a data-rel="navigator-tooltip" href="javascript: void(0)" data-bind="click: function(){ page('/editor'); onePageViewModel.changeEditorType('hive', true); }"><i class="fa fa-fw fa-edit inline-block"></i> ${ _('Editor') }</a>
  100. <ul class="dropdown-menu">
  101. % if 'impala' in apps:
  102. <li><a href="javascript: void(0)" data-bind="click: function(){ page('/editor'); onePageViewModel.changeEditorType('impala', true); }"><svg style="display: inline-block;"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#hi-impala"></use></svg> ${_('Impala Query')}</a></li>
  103. % endif
  104. % if 'beeswax' in apps:
  105. <li><a href="javascript: void(0)" data-bind="click: function(){ page('/editor'); onePageViewModel.changeEditorType('hive', true); }"><svg><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#hi-hive"></use></svg> ${_('Hive Query')}</a></li>
  106. % endif
  107. % if SHOW_NOTEBOOKS.get():
  108. <li><a href="javascript: void(0)" data-bind="click: function(){ page('/notebook'); }"><i class="fa fa-fw fa-file-text-o inline-block"></i> ${ _('Notebook') }</a></li>
  109. % endif
  110. % if interpreters:
  111. <li class="divider"></li>
  112. <li class="dropdown-submenu">
  113. <a data-rel="navigator-tooltip" href="#"><span class="dropdown-no-icon">${ _('More') }</span></a>
  114. <ul class="dropdown-menu">
  115. % for interpreter in interpreters:
  116. % if interpreter['name'] != 'Hive' and interpreter['name'] != 'Impala':
  117. <li><a href="javascript: void(0)" data-bind="click: function(){ page('/editor'); onePageViewModel.changeEditorType('${ interpreter['type'] }', true); }"><span class="dropdown-no-icon">${ interpreter['name'] }</span></a></li>
  118. % endif
  119. % endfor
  120. % if user.is_superuser:
  121. <li class="divider"></li>
  122. <li><a href="http://gethue.com/sql-editor/" target="_blank"><span class="dropdown-no-icon">${ _('Add more...') }</span></a></li>
  123. % endif
  124. </ul>
  125. </li>
  126. % endif
  127. </ul>
  128. </li>
  129. % endif
  130. % if IS_DASHBOARD_ENABLED.get():
  131. <li><a href="javascript: void(0)" data-bind="click: function(){ page('/dashboard/new_search') }"><i class="fa fa-fw fa-area-chart"></i> ${ _('Dashboard') }</a></li>
  132. % endif
  133. % if 'oozie' in apps:
  134. % if not user.has_hue_permission(action="disable_editor_access", app="oozie") or user.is_superuser:
  135. <li class="dropdown-submenu">
  136. <a data-rel="navigator-tooltip" href="#"><img src="${ static('oozie/art/icon_oozie_editor_48.png') }" class="app-icon" alt="${ _('Oozie editor icon') }"/> ${ _('Workflow') }</a>
  137. <ul class="dropdown-menu">
  138. <li><a href="javascript: void(0)" data-bind="click: function(){ page('/oozie/editor/workflow/new/') }"><img src="${ static('oozie/art/icon_oozie_workflow_48.png') }" class="app-icon" alt="${ _('Oozie workflow icon') }"/> ${_('Workflow')}</a></li>
  139. <li><a href="javascript: void(0)" data-bind="click: function(){ page('/oozie/editor/coordinator/new/') }"><img src="${ static('oozie/art/icon_oozie_coordinator_48.png') }" class="app-icon" alt="${ _('Oozie coordinator icon') }" /> ${_('Schedule')}</a></li>
  140. <li><a href="javascript: void(0)" data-bind="click: function(){ page('/oozie/editor/bundle/new/') }"><img src="${ static('oozie/art/icon_oozie_bundle_48.png') }" class="app-icon" alt="${ _('Oozie bundle icon') }" /> ${_('Bundle')}</a></li>
  141. </ul>
  142. </li>
  143. % endif
  144. % endif
  145. </ul>
  146. </div>
  147. </div>
  148. <div class="top-nav-middle">
  149. <div class="search-container">
  150. <input placeholder="${ _('Search all data and saved documents...') }" type="text"
  151. data-bind="autocomplete: {
  152. source: searchAutocompleteSource,
  153. itemTemplate: 'nav-search-autocomp-item',
  154. noMatchTemplate: 'nav-search-autocomp-no-match',
  155. classPrefix: 'nav-',
  156. showOnFocus: true,
  157. onEnter: performSearch,
  158. reopenPattern: /.*:$/
  159. },
  160. hasFocus: searchHasFocus,
  161. clearable: { value: searchInput, onClear: function () { searchActive(false); huePubSub.publish('autocomplete.close'); } },
  162. textInput: searchInput,
  163. valueUpdate: 'afterkeydown'">
  164. <a class="inactive-action" data-bind="click: performSearch"><i class="fa fa-search" data-bind="css: { 'blue': searchHasFocus() || searchActive() }"></i></a>
  165. </div>
  166. </div>
  167. <div class="top-nav-right">
  168. % if user.is_authenticated() and section != 'login':
  169. <div class="compose-action btn-group pull-right">
  170. <%
  171. view_profile = user.has_hue_permission(action="access_view:useradmin:edit_user", app="useradmin") or user.is_superuser
  172. %>
  173. <button class="btn"
  174. % if view_profile:
  175. data-bind="click: function(){ page('/useradmin/users/') }" title="${ _('View Profile') if is_ldap_setup else _('Edit Profile') }"
  176. % endif
  177. >
  178. ${ user.username }
  179. </button>
  180. <button class="btn dropdown-toggle" data-toggle="dropdown">
  181. <span class="caret"></span>
  182. </button>
  183. <ul class="dropdown-menu">
  184. % if view_profile:
  185. <li><a href="${ url('useradmin.views.edit_user', username=user.username) }"><i class="fa fa-key"></i> ${_('Profile')}</a></li>
  186. % endif
  187. % if user.is_superuser:
  188. <li data-bind="click: function () { page('/useradmin/users/') }"><a href="javascript: void(0);"><i class="fa fa-group"></i> ${_('Manage Users')}</a></li>
  189. % endif
  190. <li><a href="http://gethue.com" target="_blank"><span class="dropdown-no-icon">${_('Help')}</span></a></li>
  191. % if user.is_superuser:
  192. <li><a href="/about"><span class="dropdown-no-icon">${_('About Hue')}</span></a></li>
  193. % endif
  194. <li class="divider"></li>
  195. <li><a title="${_('Sign out')}" href="/accounts/logout/"><i class="fa fa-sign-out"></i> ${ _('Sign out') }</a></li>
  196. </ul>
  197. </div>
  198. % endif
  199. <!-- ko component: 'hue-history-panel' --><!-- /ko -->
  200. % if 'jobbrowser' in apps:
  201. <!-- ko component: { name: 'hue-job-browser-panel', params: { onePageViewModel: onePageViewModel }} --><!-- /ko -->
  202. % endif
  203. </div>
  204. </div>
  205. </nav>
  206. <div class="content-wrapper">
  207. <div class="left-nav" data-bind="css: { 'left-nav-visible': leftNavVisible }, niceScroll">
  208. <ul class="left-nav-menu">
  209. <li data-bind="click: function () { page('/home') }"><a href="javascript: void(0);">Documents</a></li>
  210. <li class="header">&nbsp;</li>
  211. <li class="header" style="padding-left: 4px; border-bottom: 1px solid #DDD; padding-bottom: 3px;">${ _('Analyse') }</li>
  212. % if interpreters:
  213. <li data-bind="click: function () { page('/editor'); onePageViewModel.changeEditorType('hive', true); }"><a href="javascript: void(0);">Editor</a></li>
  214. % endif
  215. % if IS_DASHBOARD_ENABLED.get():
  216. <li data-bind="click: function () { page('/dashboard/new_search') }"><a href="javascript: void(0);">Dashboard</a></li>
  217. % endif
  218. % if 'oozie' in apps:
  219. <li data-bind="click: function () { page('/oozie/editor/workflow/new/') }"><a href="javascript: void(0);">Workflows</a></li>
  220. % endif
  221. <li class="header">&nbsp;</li>
  222. <li class="header" style="padding-left: 4px; border-bottom: 1px solid #DDD; padding-bottom: 3px;">${ _('Browse') }</li>
  223. % if 'filebrowser' in apps:
  224. <li data-bind="click: function () { page('/filebrowser/') }"><a href="javascript: void(0);">Files</a></li>
  225. % endif
  226. % if is_s3_enabled:
  227. <li data-bind="click: function () { page('/filebrowser/view=S3A://') }"><a href="javascript: void(0);">S3</a></li>
  228. % endif
  229. % if 'metastore' in apps:
  230. <li data-bind="click: function () { page('/metastore/tables/') }"><a href="javascript: void(0);">Tables</a></li>
  231. % endif
  232. % if 'search' in apps:
  233. <li data-bind="click: function () { page('/indexer/') }"><a href="javascript: void(0);">Indexes</a></li>
  234. % endif
  235. % if 'jobbrowser' in apps:
  236. <li data-bind="click: function () { page('/jobbrowser/apps') }"><a href="javascript: void(0);">Jobs</a></li>
  237. % endif
  238. % if 'hbase' in apps:
  239. <li data-bind="click: function () { page('/hbase/') }"><a href="javascript: void(0);">HBase</a></li>
  240. % endif
  241. % if 'security' in apps:
  242. <li data-bind="click: function () { page('/security/hive') }"><a href="javascript: void(0);">Security</a></li>
  243. % endif
  244. % if 'sqoop' in apps:
  245. <li><a href="/${apps['sqoop'].display_name}">${_('Sqoop')}</a></li>
  246. % endif
  247. % if other_apps:
  248. <li class="header">&nbsp;</li>
  249. <li class="header" style="padding-left: 4px; border-bottom: 1px solid #DDD; padding-bottom: 3px;">${ _('Apps') }</li>
  250. % for other in other_apps:
  251. <li><a href="/${ other.display_name }">${ other.nice_name }</a></li>
  252. % endfor
  253. </li>
  254. % endif
  255. </ul>
  256. <div class="left-nav-drop">
  257. <div data-bind="dropzone: {
  258. clickable: false,
  259. url: '/filebrowser/upload/file?dest=' + DropzoneGlobals.homeDir,
  260. params: { dest: DropzoneGlobals.homeDir },
  261. paramName: 'hdfs_file',
  262. onError: onePageViewModel.dropzoneError,
  263. onComplete: onePageViewModel.dropzoneComplete },
  264. click: function(){ page('/indexer/importer/') }" class="pointer" title="${ _('Import data wizard') }">
  265. <div class="dz-message" data-dz-message><i class="fa fa-fw fa-cloud-upload"></i> ${ _('Drop files here') }</div>
  266. </div>
  267. </div>
  268. </div>
  269. <div class="left-panel" data-bind="css: { 'side-panel-closed': !leftAssistVisible() }, visibleOnHover: { selector: '.hide-left-side-panel' }">
  270. <a href="javascript:void(0);" style="z-index: 1000; display: none;" title="${_('Show Assist')}" class="pointer side-panel-toggle show-left-side-panel" data-bind="visible: ! leftAssistVisible(), toggle: leftAssistVisible"><i class="fa fa-chevron-right"></i></a>
  271. <a href="javascript:void(0);" style="display: none; opacity: 0;" title="${_('Hide Assist')}" class="pointer side-panel-toggle hide-left-side-panel" data-bind="visible: leftAssistVisible, toggle: leftAssistVisible"><i class="fa fa-chevron-left"></i></a>
  272. <!-- ko if: leftAssistVisible -->
  273. <div class="assist" data-bind="component: {
  274. name: 'assist-panel',
  275. params: {
  276. user: '${user.username}',
  277. sql: {
  278. navigationSettings: {
  279. openItem: false,
  280. showStats: true
  281. }
  282. },
  283. visibleAssistPanels: ['sql']
  284. }
  285. }"></div>
  286. <!-- /ko -->
  287. </div>
  288. <div id="leftResizer" class="resizer" data-bind="visible: leftAssistVisible(), splitFlexDraggable : {
  289. containerSelector: '.content-wrapper',
  290. sidePanelSelector: '.left-panel',
  291. sidePanelVisible: leftAssistVisible,
  292. orientation: 'left',
  293. onPosition: function() { huePubSub.publish('split.draggable.position') }
  294. }"><div class="resize-bar">&nbsp;</div></div>
  295. <div class="page-content" data-bind="niceScroll: {horizrailenabled: false}">
  296. <!-- ko hueSpinner: { spin: isLoadingEmbeddable, center: true, size: 'xlarge' } --><!-- /ko -->
  297. <div id="embeddable_editor" class="embeddable"></div>
  298. <div id="embeddable_notebook" class="embeddable"></div>
  299. <div id="embeddable_metastore" class="embeddable"></div>
  300. <div id="embeddable_dashboard" class="embeddable"></div>
  301. <div id="embeddable_oozie_workflow" class="embeddable"></div>
  302. <div id="embeddable_oozie_coordinator" class="embeddable"></div>
  303. <div id="embeddable_oozie_bundle" class="embeddable"></div>
  304. <div id="embeddable_jobbrowser" class="embeddable"></div>
  305. <div id="embeddable_filebrowser" class="embeddable"></div>
  306. <div id="embeddable_home" class="embeddable"></div>
  307. <div id="embeddable_indexer" class="embeddable"></div>
  308. <div id="embeddable_importer" class="embeddable"></div>
  309. <div id="embeddable_collections" class="embeddable"></div>
  310. <div id="embeddable_indexes" class="embeddable"></div>
  311. <div id="embeddable_useradmin_users" class="embeddable"></div>
  312. <div id="embeddable_useradmin_groups" class="embeddable"></div>
  313. <div id="embeddable_useradmin_permissions" class="embeddable"></div>
  314. <div id="embeddable_useradmin_configurations" class="embeddable"></div>
  315. <div id="embeddable_useradmin_newuser" class="embeddable"></div>
  316. <div id="embeddable_useradmin_addldap" class="embeddable"></div>
  317. <div id="embeddable_useradmin_edituser" class="embeddable"></div>
  318. <div id="embeddable_hbase" class="embeddable"></div>
  319. <div id="embeddable_security_hive" class="embeddable"></div>
  320. <div id="embeddable_security_hdfs" class="embeddable"></div>
  321. <div id="embeddable_security_hive2" class="embeddable"></div>
  322. <div id="embeddable_security_solr" class="embeddable"></div>
  323. <div id="embeddable_help" class="embeddable"></div>
  324. <div id="embeddable_admin_wizard" class="embeddable"></div>
  325. <div id="embeddable_logs" class="embeddable"></div>
  326. <div id="embeddable_dump_config" class="embeddable"></div>
  327. <div id="embeddable_404" class="embeddable"></div>
  328. <div id="embeddable_500" class="embeddable"></div>
  329. <div id="embeddable_sqoop" class="embeddable"></div>
  330. </div>
  331. <div id="rightResizer" class="resizer" data-bind="visible: rightAssistVisible() && rightAssistAvailable(), splitFlexDraggable : {
  332. containerSelector: '.content-wrapper',
  333. sidePanelSelector: '.right-panel',
  334. sidePanelVisible: rightAssistVisible,
  335. orientation: 'right',
  336. onPosition: function() { huePubSub.publish('split.draggable.position') }
  337. }"><div class="resize-bar" style="right: 0">&nbsp;</div></div>
  338. <div class="right-panel" data-bind="css: { 'side-panel-closed': !rightAssistVisible() || !rightAssistAvailable() }, visibleOnHover: { selector: '.hide-right-side-panel' }">
  339. <a href="javascript:void(0);" style="display: none;" title="${_('Show Assist')}" class="pointer side-panel-toggle show-right-side-panel" data-bind="visible: ! rightAssistVisible() && rightAssistAvailable(), toggle: rightAssistVisible"><i class="fa fa-chevron-left"></i></a>
  340. <a href="javascript:void(0);" style="display: none; opacity: 0;" title="${_('Hide Assist')}" class="pointer side-panel-toggle hide-right-side-panel" data-bind="visible: rightAssistVisible() && rightAssistAvailable(), toggle: rightAssistVisible"><i class="fa fa-chevron-right"></i></a>
  341. <div data-bind="visible: rightAssistVisible() && rightAssistAvailable()" style="display: none; height: 100%; width: 100%; position: relative;">
  342. <ul class="right-panel-tabs nav nav-tabs">
  343. <li data-bind="css: { 'active' : activeRightTab() === 'assistant' }, visible: assistantAvailable"><a href="javascript: void(0);" data-bind="click: function() { activeRightTab('assistant'); }">${ _('Assistant') }</a></li>
  344. <li data-bind="css: { 'active' : activeRightTab() === 'functions' }"><a href="javascript: void(0);" data-bind="click: function() { activeRightTab('functions'); }">${ _('Functions') }</a></li>
  345. <li data-bind="css: { 'active' : activeRightTab() === 'schedules' }"><a href="javascript: void(0);" data-bind="click: function() { activeRightTab('schedules'); }">${ _('Schedule') }</a></li>
  346. </ul>
  347. <div class="right-panel-tab-content tab-content">
  348. <!-- ko if: activeRightTab() === 'assistant' -->
  349. <div data-bind="component: { name: 'assistant-panel' }"></div>
  350. <!-- /ko -->
  351. <!-- ko if: activeRightTab() === 'functions' -->
  352. <div data-bind="component: { name: 'functions-panel' }"></div>
  353. <!-- /ko -->
  354. <!-- ko if: activeRightTab() === 'schedules' -->
  355. <div>Schedules</div>
  356. <!-- /ko -->
  357. </div>
  358. </div>
  359. </div>
  360. <div class="context-panel" data-bind="css: { 'visible': contextPanelVisible }">
  361. <ul class="nav nav-tabs">
  362. <!-- ko if: sessionsAvailable -->
  363. <li class="active"><a href="#sessionsTab" data-toggle="tab" data-bind="visible: sessionsAvailable">${_('Sessions')}</a></li>
  364. <!-- /ko -->
  365. </ul>
  366. <div class="tab-content">
  367. <!-- ko if: sessionsAvailable -->
  368. <div class="tab-pane active" id="sessionsTab">
  369. <div class="row-fluid">
  370. <div class="span12" data-bind="template: { name: 'notebook-session-config-template', data: activeAppViewModel }"></div>
  371. </div>
  372. </div>
  373. <!-- /ko -->
  374. </div>
  375. </div>
  376. </div>
  377. </div>
  378. <script src="${ static('desktop/js/hue-bundle.js') }"></script>
  379. <script src="${ static('desktop/js/jquery.migration.js') }"></script>
  380. <script src="${ static('desktop/js/hue.utils.js') }"></script>
  381. <script src="${ static('desktop/ext/js/bootstrap.min.js') }"></script>
  382. <script src="${ static('desktop/js/bootstrap-tooltip.js') }"></script>
  383. <script src="${ static('desktop/ext/js/bootstrap-better-typeahead.min.js') }"></script>
  384. <script src="${ static('desktop/ext/js/fileuploader.js') }"></script>
  385. <script src="${ static('desktop/ext/js/filesize.min.js') }"></script>
  386. <script src="${ static('desktop/ext/js/moment-with-locales.min.js') }"></script>
  387. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.total-storage.min.js') }"></script>
  388. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.cookie.js') }"></script>
  389. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.dataTables.1.8.2.min.js') }"></script>
  390. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.form.js') }"></script>
  391. <script src="${ static('desktop/js/jquery.datatables.sorting.js') }"></script>
  392. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.basictable.min.js') }"></script>
  393. <script src="${ static('desktop/ext/js/jquery/plugins/jquery-ui-1.10.4.custom.min.js') }"></script>
  394. <script src="${ static('desktop/js/jquery.nicescroll.js') }"></script>
  395. <script src="${ static('desktop/js/jquery.hiveautocomplete.js') }"></script>
  396. <script src="${ static('desktop/js/jquery.hdfsautocomplete.js') }"></script>
  397. <script src="${ static('desktop/js/jquery.filechooser.js') }"></script>
  398. <script src="${ static('desktop/js/jquery.selector.js') }"></script>
  399. <script src="${ static('desktop/js/jquery.delayedinput.js') }"></script>
  400. <script src="${ static('desktop/js/jquery.rowselector.js') }"></script>
  401. <script src="${ static('desktop/js/jquery.notify.js') }"></script>
  402. <script src="${ static('desktop/js/jquery.titleupdater.js') }"></script>
  403. <script src="${ static('desktop/js/jquery.horizontalscrollbar.js') }"></script>
  404. <script src="${ static('desktop/js/jquery.tablescroller.js') }"></script>
  405. <script src="${ static('desktop/js/jquery.tableextender.js') }"></script>
  406. <script src="${ static('desktop/js/jquery.tableextender2.js') }"></script>
  407. <script src="${ static('desktop/ext/js/d3.v3.js') }"></script>
  408. <script src="${ static('desktop/ext/js/d3.v4.js') }"></script>
  409. <script src="${ static('desktop/js/hue.colors.js') }"></script>
  410. <script src="${ static('desktop/js/apiHelper.js') }"></script>
  411. <script src="${ static('desktop/js/ko.charts.js') }"></script>
  412. <script src="${ static('desktop/ext/js/knockout-sortable.min.js') }"></script>
  413. <script src="${ static('desktop/ext/js/knockout.validation.min.js') }"></script>
  414. <script src="${ static('desktop/ext/js/bootstrap-editable.min.js') }"></script>
  415. <script src="${ static('desktop/js/ko.editable.js') }"></script>
  416. <script src="${ static('desktop/js/ko.switch-case.js') }"></script>
  417. <script src="${ static('desktop/js/ko.hue-bindings.js') }"></script>
  418. <script src="${ static('desktop/js/sqlUtils.js') }"></script>
  419. <script src="${ static('desktop/js/jquery.scrollleft.js') }"></script>
  420. <script src="${ static('desktop/js/jquery.scrollup.js') }"></script>
  421. <script src="${ static('desktop/js/jquery.tour.js') }"></script>
  422. <script src="${ static('desktop/js/jquery.huedatatable.js') }"></script>
  423. <script src="${ static('desktop/js/sqlFunctions.js') }"></script>
  424. <script src="${ static('desktop/ext/js/selectize.min.js') }"></script>
  425. <script src="${ static('desktop/js/ko.selectize.js') }"></script>
  426. <script src="${ static('desktop/js/ace/ace.js') }"></script>
  427. <script src="${ static('desktop/js/ace/mode-impala.js') }"></script>
  428. <script src="${ static('desktop/js/ace/mode-hive.js') }"></script>
  429. <script src="${ static('desktop/js/ace/ext-language_tools.js') }"></script>
  430. <script src="${ static('desktop/js/ace.extended.js') }"></script>
  431. <script src="${ static('desktop/ext/js/dropzone.min.js') }"></script>
  432. <script src="${ static('desktop/js/autocomplete/sqlParseSupport.js') }"></script>
  433. <script src="${ static('desktop/js/autocomplete/sql.js') }"></script>
  434. <script src="${ static('desktop/js/sqlAutocompleter.js') }"></script>
  435. <script src="${ static('desktop/js/sqlAutocompleter2.js') }"></script>
  436. <script src="${ static('desktop/js/hdfsAutocompleter.js') }"></script>
  437. <script src="${ static('desktop/js/autocompleter.js') }"></script>
  438. <script src="${ static('desktop/js/hue.json.js') }"></script>
  439. <script src="${ static('notebook/js/notebook.ko.js') }"></script>
  440. <script src="${ static('metastore/js/metastore.model.js') }"></script>
  441. <script type="text/javascript">
  442. (function () {
  443. var proxiedKoRegister = ko.components.register;
  444. var registeredComponents = [];
  445. ko.components.register = function () {
  446. // This guarantees a ko component is only registered once
  447. // Some currently get registered twice when switching between notebook and editor
  448. if (registeredComponents.indexOf(arguments[0]) === -1) {
  449. registeredComponents.push(arguments[0]);
  450. return proxiedKoRegister.apply(this, arguments);
  451. }
  452. };
  453. })();
  454. </script>
  455. ${ koComponents.all() }
  456. ${ commonHeaderFooterComponents.header_pollers(user, is_s3_enabled, apps) }
  457. ${ assist.assistJSModels() }
  458. ${ assist.assistPanel() }
  459. <iframe id="zoomDetectFrame" style="width: 250px; display: none" ></iframe>
  460. <script type="text/javascript">
  461. $(document).ready(function () {
  462. $(document).on('hideHistoryModal', function (e) {
  463. $('#clearNotificationHistoryModal').modal('hide');
  464. });
  465. var onePageViewModel = (function () {
  466. var EMBEDDABLE_PAGE_URLS = {
  467. 404: '/404',
  468. 500: '/500',
  469. editor: '/editor',
  470. notebook: '/notebook',
  471. metastore: '/metastore/*',
  472. dashboard: '/dashboard/*',
  473. oozie_workflow: '/oozie/editor/workflow/*',
  474. oozie_coordinator: '/oozie/editor/coordinator/*',
  475. oozie_bundle: '/oozie/editor/bundle/*',
  476. jobbrowser: '/jobbrowser/apps',
  477. filebrowser: '/filebrowser/view=*',
  478. home: '/home*',
  479. indexer: '/indexer/indexer/',
  480. collections: '/dashboard/admin/collections',
  481. indexes: '/indexer/',
  482. importer: '/indexer/importer/',
  483. useradmin_users: '/useradmin/users',
  484. useradmin_groups: '/useradmin/groups',
  485. useradmin_permissions: '/useradmin/permissions',
  486. useradmin_configurations: '/useradmin/configurations',
  487. useradmin_newuser: '/useradmin/users/new',
  488. useradmin_addldap: '/useradmin/users/add_ldap_users',
  489. useradmin_edituser: '/useradmin/users/edit/:user',
  490. hbase: '/hbase/',
  491. security_hive: '/security/hive',
  492. security_hdfs: '/security/hdfs',
  493. security_hive2: '/security/hive2',
  494. security_solr: '/security/solr',
  495. help: '/help/',
  496. admin_wizard: '/about/admin_wizard',
  497. logs: '/logs',
  498. dump_config: '/desktop/dump_config',
  499. sqoop: '/sqoop',
  500. };
  501. var SKIP_CACHE = ['home', 'oozie_workflow', 'oozie_coordinator', 'oozie_bundle', 'dashboard', 'filebrowser', 'useradmin_users', 'useradmin_groups', 'useradmin_permissions', 'useradmin_configurations', 'useradmin_newuser', 'useradmin_addldap', 'useradmin_edituser'];
  502. var OnePageViewModel = function () {
  503. var self = this;
  504. self.embeddable_cache = {};
  505. self.currentApp = ko.observable();
  506. self.currentContextParams = ko.observable(null);
  507. self.currentQueryString = ko.observable(null);
  508. self.isLoadingEmbeddable = ko.observable(false);
  509. self.extraEmbeddableURLParams = ko.observable('');
  510. self.getActiveAppViewModel = function (callback) {
  511. var checkInterval = window.setInterval(function () {
  512. var $koElement = $('#' + self.currentApp() + 'Components');
  513. if ($koElement.length > 0 && ko.dataFor($koElement[0])) {
  514. window.clearInterval(checkInterval);
  515. callback(ko.dataFor($koElement[0]));
  516. }
  517. }, 25);
  518. };
  519. self.changeEditorType = function (type, changeURL) {
  520. self.getActiveAppViewModel(function (viewModel) {
  521. if (viewModel && viewModel.selectedNotebook) {
  522. hueUtils.waitForObservable(viewModel.selectedNotebook, function(){
  523. viewModel.selectedNotebook().selectedSnippet(type);
  524. viewModel.editorType(type);
  525. viewModel.newNotebook(type);
  526. });
  527. }
  528. })
  529. };
  530. self.currentApp.subscribe(function (newApp) {
  531. huePubSub.publish('set.current.app.name', newApp);
  532. self.getActiveAppViewModel(function (viewModel) {
  533. huePubSub.publish('set.current.app.view.model', viewModel);
  534. })
  535. });
  536. huePubSub.subscribe('get.current.app.view.model', function () {
  537. self.getActiveAppViewModel(function (viewModel) {
  538. huePubSub.publish('set.current.app.view.model', viewModel);
  539. })
  540. });
  541. huePubSub.subscribe('get.current.app.name', function () {
  542. huePubSub.publish('set.current.app.name', self.currentApp());
  543. });
  544. huePubSub.subscribe('open.editor.query', function (uuid) {
  545. self.loadApp('editor');
  546. self.getActiveAppViewModel(function (viewModel) {
  547. viewModel.openNotebook(uuid);
  548. })
  549. });
  550. huePubSub.subscribe('open.editor.new.query', function (statementOptions) {
  551. self.loadApp('editor');
  552. self.getActiveAppViewModel(function (viewModel) {
  553. var editorType = statementOptions['type'] || 'hive'; // Next: use file extensions and default type of Editor for SQL
  554. viewModel.newNotebook(editorType, function() {
  555. if (statementOptions['statementType']) {
  556. viewModel.selectedNotebook().snippets()[0].statementType(statementOptions['statementType']);
  557. viewModel.selectedNotebook().snippets()[0].statementPath(statementOptions['statementPath']);
  558. }
  559. if (statementOptions['directoryUuid']) {
  560. viewModel.selectedNotebook().directoryUuid(statementOptions['directoryUuid']);
  561. }
  562. });
  563. })
  564. });
  565. huePubSub.subscribe('open.link', function (href) {
  566. if (href.startsWith('/') && !href.startsWith('/hue')){
  567. page('/hue' + href);
  568. }
  569. else {
  570. page(href);
  571. }
  572. });
  573. var loadedJs = [];
  574. var loadedCss = [];
  575. var loadedApps = [];
  576. $('script[src]').each(function(){
  577. loadedJs.push($(this).attr('src'));
  578. });
  579. $('link[href]').each(function(){
  580. loadedCss.push($(this).attr('href'));
  581. });
  582. // Only load CSS and JS files that are not loaded before
  583. self.processHeaders = function(response){
  584. var r = $('<span>').html(response);
  585. r.find('link').each(function () {
  586. $(this).attr('href', $(this).attr('href') + '?' + Math.random())
  587. });
  588. r.find('script[src]').each(function () {
  589. var jsFile = $(this).attr('src').split('?')[0];
  590. if (loadedJs.indexOf(jsFile) === -1) {
  591. loadedJs.push(jsFile);
  592. $(this).clone().appendTo($('head'));
  593. }
  594. $(this).remove();
  595. });
  596. r.find('link[href]').each(function () {
  597. var cssFile = $(this).attr('href').split('?')[0];
  598. if (loadedCss.indexOf(cssFile) === -1) {
  599. loadedCss.push(cssFile);
  600. $(this).clone().appendTo($('head'));
  601. }
  602. $(this).remove();
  603. });
  604. r.find('a[href]').each(function () {
  605. var link = $(this).attr('href');
  606. if (link.startsWith('/') && !link.startsWith('/hue')){
  607. link = '/hue' + link;
  608. }
  609. $(this).attr('href', link);
  610. });
  611. r.unwrap('<span>');
  612. return r;
  613. };
  614. self.loadApp = function(app){
  615. self.currentApp(app);
  616. self.isLoadingEmbeddable(true);
  617. loadedApps.forEach(function (loadedApp) {
  618. window.pauseAppIntervals(loadedApp);
  619. });
  620. if (typeof self.embeddable_cache[app] === 'undefined') {
  621. if (loadedApps.indexOf(app) == -1){
  622. loadedApps.push(app);
  623. }
  624. var baseURL = EMBEDDABLE_PAGE_URLS[app];
  625. if (self.currentContextParams() !== null) {
  626. var route = new page.Route(baseURL);
  627. route.keys.forEach(function (key) {
  628. if (key.name === 0){
  629. baseURL = baseURL.replace('*', self.currentContextParams()[key.name]);
  630. }
  631. else {
  632. baseURL = baseURL.replace(':' + key.name, self.currentContextParams()[key.name]);
  633. }
  634. });
  635. self.currentContextParams(null);
  636. }
  637. if (self.currentQueryString() !== null) {
  638. baseURL += (baseURL.indexOf('?') > -1 ? '&' : '?') + self.currentQueryString();
  639. self.currentQueryString(null);
  640. }
  641. $.ajax({
  642. url: baseURL + (baseURL.indexOf('?') > -1 ? '&' : '?') +'is_embeddable=true' + self.extraEmbeddableURLParams(),
  643. beforeSend: function (xhr) {
  644. xhr.setRequestHeader('X-Requested-With', 'Hue');
  645. },
  646. dataType: 'html',
  647. success: function (response) {
  648. self.extraEmbeddableURLParams('');
  649. var r = self.processHeaders(response);
  650. if (SKIP_CACHE.indexOf(app) === -1) {
  651. self.embeddable_cache[app] = r;
  652. }
  653. $('#embeddable_' + app).html(r);
  654. self.isLoadingEmbeddable(false);
  655. },
  656. error: function () {
  657. page('/500');
  658. }
  659. });
  660. } else {
  661. self.isLoadingEmbeddable(false);
  662. }
  663. window.resumeAppIntervals(app);
  664. $('.embeddable').hide();
  665. $('#embeddable_' + app).insertBefore($('.embeddable:first')).show();
  666. }
  667. self.dropzoneError = function (filename) {
  668. self.loadApp('importer');
  669. self.getActiveAppViewModel(function (vm) {
  670. vm.createWizard.source.path(DropzoneGlobals.homeDir + '/' + filename);
  671. });
  672. };
  673. self.dropzoneComplete = function (path) {
  674. self.loadApp('importer');
  675. self.getActiveAppViewModel(function (vm) {
  676. vm.createWizard.source.path(path);
  677. });
  678. };
  679. huePubSub.subscribe('switch.app', function (name) {
  680. self.currentApp(name);
  681. });
  682. // prepend /hue to all the link on this page
  683. $('a[href]').each(function () {
  684. var link = $(this).attr('href');
  685. if (link.startsWith('/') && !link.startsWith('/hue')){
  686. link = '/hue' + link;
  687. }
  688. $(this).attr('href', link);
  689. });
  690. page.base('/hue');
  691. page('/help', function(ctx){
  692. self.loadApp('help');
  693. });
  694. page('/about/admin_wizard', function(ctx){
  695. self.loadApp('admin_wizard');
  696. });
  697. page('/logs', function(ctx){
  698. self.loadApp('logs');
  699. });
  700. page('/desktop/dump_config', function(ctx){
  701. self.loadApp('dump_config');
  702. });
  703. page('/filebrowser/view=*', function(ctx){
  704. self.currentContextParams(ctx.params);
  705. self.loadApp('filebrowser');
  706. });
  707. page('/filebrowser/*', function(ctx){
  708. page('/filebrowser/view=' + DropzoneGlobals.homeDir);
  709. });
  710. page('/dashboard/admin/collections', function(ctx){
  711. self.loadApp('collections');
  712. });
  713. page('/useradmin/users/add_ldap_users', function(ctx){
  714. self.loadApp('useradmin_addldap');
  715. });
  716. page('/useradmin/users/new', function(ctx){
  717. self.loadApp('useradmin_newuser');
  718. });
  719. page('/useradmin/users/edit/:user', function(ctx){
  720. self.currentContextParams(ctx.params);
  721. self.loadApp('useradmin_edituser');
  722. });
  723. page('/useradmin/users/', function(ctx){
  724. self.loadApp('useradmin_users');
  725. });
  726. page('/useradmin/groups/', function(ctx){
  727. self.loadApp('useradmin_groups');
  728. });
  729. page('/useradmin/permissions/', function(ctx){
  730. self.loadApp('useradmin_permissions');
  731. });
  732. page('/useradmin/configurations/', function(ctx){
  733. self.loadApp('useradmin_configurations');
  734. });
  735. page('/editor', function (ctx) {
  736. self.loadApp('editor');
  737. if (window.location.getParameter('editor') !== '') {
  738. self.getActiveAppViewModel(function (viewModel) {
  739. viewModel.openNotebook(window.location.getParameter('editor'));
  740. });
  741. }
  742. else if (window.location.getParameter('type') !== '') {
  743. self.changeEditorType(window.location.getParameter('type'));
  744. }
  745. });
  746. page('/pig', function (ctx) {
  747. self.loadApp('editor');
  748. self.changeEditorType('pig');
  749. });
  750. page('/notebook', function(ctx){
  751. self.loadApp('notebook');
  752. if (window.location.getParameter('notebook') !== '') {
  753. self.getActiveAppViewModel(function (viewModel) {
  754. viewModel.openNotebook(window.location.getParameter('notebook'));
  755. });
  756. } else {
  757. self.getActiveAppViewModel(function (viewModel) {
  758. viewModel.newNotebook('notebook');
  759. });
  760. }
  761. });
  762. page('/home*', function(ctx){
  763. self.currentQueryString(ctx.querystring);
  764. self.currentContextParams(ctx.params);
  765. self.loadApp('home');
  766. });
  767. page('/dashboard/*', function(ctx){
  768. self.currentContextParams(ctx.params);
  769. self.currentQueryString(ctx.querystring);
  770. self.loadApp('dashboard');
  771. });
  772. page('/search/*', function(ctx){
  773. self.currentContextParams(ctx.params);
  774. self.currentQueryString(ctx.querystring);
  775. self.loadApp('dashboard');
  776. });
  777. page('/oozie/editor/workflow/*', function(ctx){
  778. self.currentContextParams(ctx.params);
  779. self.currentQueryString(ctx.querystring);
  780. self.loadApp('oozie_workflow');
  781. });
  782. page('/oozie/editor/coordinator/*', function(ctx){
  783. self.currentContextParams(ctx.params);
  784. self.currentQueryString(ctx.querystring);
  785. self.loadApp('oozie_coordinator');
  786. });
  787. page('/oozie/editor/bundle/*', function(ctx){
  788. self.currentContextParams(ctx.params);
  789. self.currentQueryString(ctx.querystring);
  790. self.loadApp('oozie_bundle');
  791. });
  792. page('/metastore', function(ctx){
  793. page('/metastore/tables');
  794. });
  795. page('/metastore/*', function(ctx){
  796. self.currentContextParams(ctx.params);
  797. self.loadApp('metastore');
  798. });
  799. page('/indexer/importer/prefill/*', function(ctx){
  800. self.loadApp('indexer');
  801. self.getActiveAppViewModel(function (viewModel) {
  802. var arguments = ctx.path.match(/\/indexer\/importer\/prefill\/?([^/]+)\/?([^/]+)\/?([^/]+)?/);
  803. if (! arguments) {
  804. console.warn('Could not match ' + href)
  805. }
  806. hueUtils.waitForVariable(viewModel.createWizard, function(){
  807. hueUtils.waitForVariable(viewModel.createWizard.prefill, function(){
  808. viewModel.createWizard.prefill.source_type(arguments && arguments[1] ? arguments[1] : '');
  809. viewModel.createWizard.prefill.target_type(arguments && arguments[2] ? arguments[2] : '');
  810. viewModel.createWizard.prefill.target_path(arguments && arguments[3] ? arguments[3] : '');
  811. });
  812. });
  813. })
  814. });
  815. page('/indexer/', function(ctx){
  816. self.loadApp('indexes');
  817. });
  818. page('/jobbrowser/apps', function(ctx){
  819. self.loadApp('jobbrowser');
  820. });
  821. page('/hbase/', function(ctx){
  822. self.loadApp('hbase');
  823. });
  824. page('/security/hive2', function(ctx){
  825. self.loadApp('security_hive2');
  826. });
  827. page('/security/hive', function(ctx){
  828. self.loadApp('security_hive');
  829. });
  830. page('/security/solr', function(ctx){
  831. self.loadApp('security_solr');
  832. });
  833. page('/security/hdfs', function(ctx){
  834. self.loadApp('security_hdfs');
  835. });
  836. page('/indexer/importer/', function(ctx){
  837. self.loadApp('importer');
  838. });
  839. page('/sqoop', function(ctx){
  840. self.loadApp('sqoop');
  841. });
  842. page('/500', function(ctx){
  843. self.loadApp('500');
  844. });
  845. page('/', function(ctx){
  846. % if 'beeswax' in apps or 'impala' in apps:
  847. page('/editor');
  848. % elif SHOW_NOTEBOOKS.get():
  849. page('/notebook');
  850. % elif interpreters:
  851. page('/editor');
  852. % elif IS_DASHBOARD_ENABLED.get():
  853. page('/dashboard/new_search');
  854. % elif 'jobbrowser' in apps:
  855. page('/jobbrowser/apps');
  856. % else:
  857. page('/home');
  858. % endif
  859. });
  860. page('*', function(ctx){
  861. console.error('Route not found', ctx);
  862. self.loadApp('404');
  863. });
  864. page();
  865. huePubSub.subscribe('page.route', page);
  866. };
  867. var onePageViewModel = new OnePageViewModel();
  868. ko.applyBindings(onePageViewModel, $('.page-content')[0]);
  869. return onePageViewModel;
  870. })();
  871. var sidePanelViewModel = (function () {
  872. function SidePanelViewModel () {
  873. var self = this;
  874. self.apiHelper = ApiHelper.getInstance();
  875. self.leftAssistVisible = ko.observable();
  876. self.rightAssistVisible = ko.observable();
  877. self.rightAssistVisible.subscribe(function () {
  878. window.setTimeout(function () {
  879. huePubSub.publish('reposition.scroll.anchor.up')
  880. }, 0);
  881. });
  882. self.rightAssistAvailable = ko.observable(false);
  883. self.assistantAvailable = ko.observable(false);
  884. self.activeRightTab = ko.observable();
  885. self.activeAppViewModel = ko.observable();
  886. huePubSub.subscribe('set.current.app.name', function (appName) {
  887. self.rightAssistAvailable(appName === 'editor' || appName === 'notebook');
  888. });
  889. huePubSub.publish('get.current.app.name');
  890. self.contextPanelVisible = ko.observable(false);
  891. self.sessionsAvailable = ko.observable(false);
  892. self.activeAppViewModel.subscribe(function (viewModel) {
  893. self.sessionsAvailable(typeof viewModel.selectedNotebook !== 'undefined');
  894. });
  895. huePubSub.subscribe('context.panel.visible', function (visible) {
  896. self.contextPanelVisible(visible);
  897. });
  898. huePubSub.subscribe('active.snippet.type.changed', function (type) {
  899. if (type === 'hive' || type === 'impala') {
  900. if (!self.assistantAvailable() && self.activeRightTab() !== 'assistant') {
  901. self.activeRightTab('assistant');
  902. }
  903. self.assistantAvailable(true);
  904. } else {
  905. if (self.activeRightTab() === 'assistant') {
  906. self.activeRightTab('functions');
  907. }
  908. self.assistantAvailable(false);
  909. }
  910. });
  911. huePubSub.subscribe('set.current.app.view.model', self.activeAppViewModel);
  912. huePubSub.publish('get.current.app.view.model');
  913. if (!self.activeRightTab()) {
  914. self.activeRightTab('functions');
  915. }
  916. if (self.assistantAvailable()) {
  917. self.activeRightTab = ko.observable('assistant');
  918. }
  919. self.apiHelper.withTotalStorage('assist', 'left_assist_panel_visible', self.leftAssistVisible, true);
  920. self.apiHelper.withTotalStorage('assist', 'right_assist_panel_visible', self.rightAssistVisible, true);
  921. }
  922. var sidePanelViewModel = new SidePanelViewModel();
  923. ko.applyBindings(sidePanelViewModel, $('.left-panel')[0]);
  924. ko.applyBindings(sidePanelViewModel, $('#leftResizer')[0]);
  925. ko.applyBindings(sidePanelViewModel, $('#rightResizer')[0]);
  926. ko.applyBindings(sidePanelViewModel, $('.right-panel')[0]);
  927. ko.applyBindings(sidePanelViewModel, $('.context-panel')[0]);
  928. return sidePanelViewModel;
  929. })();
  930. var topNavViewModel = (function (onePageViewModel) {
  931. // TODO: Extract to common module (shared with nav search autocomplete)
  932. var SEARCH_FACET_ICON = 'fa-tags';
  933. var SEARCH_TYPE_ICONS = {
  934. 'DATABASE': 'fa-database',
  935. 'TABLE': 'fa-table',
  936. 'VIEW': 'fa-eye',
  937. 'FIELD': 'fa-columns',
  938. 'PARTITION': 'fa-th',
  939. 'SOURCE': 'fa-server',
  940. 'OPERATION': 'fa-cogs',
  941. 'OPERATION_EXECUTION': 'fa-cog',
  942. 'DIRECTORY': 'fa-folder-o',
  943. 'FILE': 'fa-file-o',
  944. 'SUB_OPERATION': 'fa-code-fork',
  945. 'COLLECTION': 'fa-search',
  946. 'HBASE': 'fa-th-large',
  947. 'HUE': 'fa-file-o'
  948. };
  949. function TopNavViewModel () {
  950. var self = this;
  951. self.onePageViewModel = onePageViewModel;
  952. self.leftNavVisible = ko.observable(false);
  953. self.leftNavVisible.subscribe(function (val) {
  954. huePubSub.publish('left.nav.open.toggle', val);
  955. });
  956. self.onePageViewModel.currentApp.subscribe(function () {
  957. self.leftNavVisible(false);
  958. });
  959. self.apiHelper = ApiHelper.getInstance();
  960. self.searchActive = ko.observable(false);
  961. self.searchHasFocus = ko.observable(false);
  962. self.searchInput = ko.observable();
  963. self.jobsPanelVisible = ko.observable(false);
  964. self.historyPanelVisible = ko.observable(false);
  965. self.searchAutocompleteSource = function (request, callback) {
  966. // TODO: Extract complete contents to common module (shared with nav search autocomplete)
  967. var facetMatch = request.term.match(/([a-z]+):\s*(\S+)?$/i);
  968. var isFacet = facetMatch !== null;
  969. var partialMatch = isFacet ? null : request.term.match(/\S+$/);
  970. var partial = isFacet && facetMatch[2] ? facetMatch[2] : (partialMatch ? partialMatch[0] : '');
  971. var beforePartial = request.term.substring(0, request.term.length - partial.length);
  972. self.apiHelper.globalSearchAutocomplete({
  973. query: request.term,
  974. successCallback: function (data) {
  975. var values = [];
  976. var facetPartialRe = new RegExp(partial.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i'); // Protect for 'tags:*axe'
  977. if (typeof data.resultsHuedocuments !== 'undefined') {
  978. data.resultsHuedocuments.forEach(function (result) {
  979. values.push({ data: { label: result.hue_name, icon: SEARCH_TYPE_ICONS[result.type], description: result.hue_description }, value: beforePartial + result.originalName });
  980. });
  981. }
  982. if (values.length > 0) {
  983. values.push({ divider: true });
  984. }
  985. if (isFacet && typeof data.facets !== 'undefined') { // Is typed facet, e.g. type: type:bla
  986. var facetInQuery = facetMatch[1];
  987. if (typeof data.facets[facetInQuery] !== 'undefined') {
  988. $.map(data.facets[facetInQuery], function (count, value) {
  989. if (facetPartialRe.test(value)) {
  990. values.push({ data: { label: facetInQuery + ':' + value, icon: SEARCH_FACET_ICON, description: count }, value: beforePartial + value})
  991. }
  992. });
  993. }
  994. } else {
  995. if (typeof data.facets !== 'undefined') {
  996. Object.keys(data.facets).forEach(function (facet) {
  997. if (facetPartialRe.test(facet)) {
  998. if (Object.keys(data.facets[facet]).length > 0) {
  999. values.push({ data: { label: facet + ':', icon: SEARCH_FACET_ICON, description: $.map(data.facets[facet], function (key, value) { return value + ' (' + key + ')'; }).join(', ') }, value: beforePartial + facet + ':'});
  1000. } else { // Potential facet from the list
  1001. values.push({ data: { label: facet + ':', icon: SEARCH_FACET_ICON, description: '' }, value: beforePartial + facet + ':'});
  1002. }
  1003. } else if (partial.length > 0) {
  1004. Object.keys(data.facets[facet]).forEach(function (facetValue) {
  1005. if (facetValue.indexOf(partial) !== -1) {
  1006. values.push({ data: { label: facet + ':' + facetValue, icon: SEARCH_FACET_ICON, description: facetValue }, value: beforePartial + facet + ':' + facetValue });
  1007. }
  1008. });
  1009. }
  1010. });
  1011. }
  1012. }
  1013. if (values.length > 0) {
  1014. values.push({ divider: true });
  1015. }
  1016. if (typeof data.results !== 'undefined') {
  1017. data.results.forEach(function (result) {
  1018. values.push({ data: { label: result.hue_name, icon: SEARCH_TYPE_ICONS[result.type], description: result.hue_description }, value: beforePartial + result.originalName });
  1019. });
  1020. }
  1021. if (values.length > 0 && values[values.length - 1].divider) {
  1022. values.pop();
  1023. }
  1024. if (values.length === 0) {
  1025. values.push({ noMatch: true });
  1026. }
  1027. callback(values);
  1028. },
  1029. silenceErrors: true,
  1030. errorCallback: function () {
  1031. callback([]);
  1032. }
  1033. });
  1034. };
  1035. }
  1036. TopNavViewModel.prototype.performSearch = function () {
  1037. };
  1038. var topNavViewModel = new TopNavViewModel();
  1039. ko.applyBindings(topNavViewModel, $('.top-nav')[0]);
  1040. ko.applyBindings(topNavViewModel, $('.left-nav')[0]);
  1041. return topNavViewModel;
  1042. })(onePageViewModel);
  1043. window.hueDebug = {
  1044. viewModel: function (element) {
  1045. return element ? ko.dataFor(element) : window.hueDebug.onePageViewModel;
  1046. },
  1047. onePageViewModel: onePageViewModel,
  1048. sidePanelViewModel: sidePanelViewModel,
  1049. topNavViewModel: topNavViewModel
  1050. };
  1051. });
  1052. </script>
  1053. ${ commonHeaderFooterComponents.footer(messages) }
  1054. </body>
  1055. </html>