hue.mako 50 KB

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