responsive.mako 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161
  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. %>
  25. <%namespace name="koComponents" file="/ko_components.mako" />
  26. <%namespace name="assist" file="/assist.mako" />
  27. <%namespace name="hueIcons" file="/hue_icons.mako" />
  28. <%namespace name="commonHeaderFooterComponents" file="/common_header_footer_components.mako" />
  29. <!DOCTYPE html>
  30. <html lang="en" dir="ltr">
  31. <head>
  32. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  33. <meta charset="utf-8">
  34. <title>Hue</title>
  35. <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  36. <link rel="icon" type="image/x-icon" href="${ static('desktop/art/favicon.ico') }"/>
  37. <meta name="description" content="">
  38. <meta name="author" content="">
  39. ## TODO: Get rid of bootplus and hue3.css
  40. <link href="${ static('desktop/ext/css/bootplus.css') }" rel="stylesheet">
  41. <link href="${ static('desktop/css/hue3.css') }" rel="stylesheet">
  42. <link href="${ static('desktop/ext/css/font-awesome.min.css') }" rel="stylesheet">
  43. <link href="${ static('desktop/css/hue.css') }" rel="stylesheet">
  44. <link href="${ static('desktop/css/jquery-ui.css') }" rel="stylesheet">
  45. <link href="${ static('desktop/css/cui.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. </head>
  51. <body>
  52. % if is_demo:
  53. <ul class="side-labels unstyled">
  54. <li class="feedback"><a href="javascript:showClassicWidget()"><i class="fa fa-envelope-o"></i> ${_('Feedback')}</a></li>
  55. </ul>
  56. <!-- UserVoice JavaScript SDK -->
  57. <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>
  58. <script>
  59. UserVoice = window.UserVoice || [];
  60. function showClassicWidget() {
  61. UserVoice.push(['showLightbox', 'classic_widget', {
  62. mode: 'feedback',
  63. primary_color: '#338cb8',
  64. link_color: '#338cb8',
  65. forum_id: 247008
  66. }]);
  67. }
  68. </script>
  69. % endif
  70. <div id="jHueNotify" class="alert hide">
  71. <button class="close">&times;</button>
  72. <div class="message"></div>
  73. </div>
  74. ${ hueIcons.symbols() }
  75. <div class="main-page">
  76. <div class="top-nav">
  77. <div class="top-nav-left">
  78. <a class="hamburger hamburger-hue pull-left" type="button" data-bind="toggle: leftNavVisible, css: { 'is-active': leftNavVisible }">
  79. <span class="hamburger-box">
  80. <span class="hamburger-inner"></span>
  81. </span>
  82. </a>
  83. <a class="nav-tooltip pull-left" title="${_('Homepage')}" rel="navigator-tooltip" href="#" data-bind="click: function(){ onePageViewModel.currentApp('home') }">
  84. <svg style="margin-top:12px;margin-left:8px;height: 24px;width:120px;display: inline-block;">
  85. <use xlink:href="#hue-logo"></use>
  86. </svg>
  87. </a>
  88. <div class="compose-action btn-group">
  89. <button class="btn" data-bind="click: function(){ onePageViewModel.changeEditorType('hive'); onePageViewModel.currentApp('editor') }" title="${ _('Open 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')}" rel="navigator-tooltip" href="javascript: void(0)" data-bind="click: function(){ onePageViewModel.changeEditorType('hive'); onePageViewModel.currentApp('editor') }"><i class="fa fa-fw fa-edit inline-block"></i> ${ _('Query') }</a>
  97. <ul class="dropdown-menu">
  98. <li><a href="javascript: void(0)" data-bind="click: function(){ onePageViewModel.changeEditorType('hive'); onePageViewModel.currentApp('editor') }"><img src="${ static(apps['beeswax'].icon_path) }" class="app-icon"/> ${_('Hive Query')}</a></li>
  99. <li><a href="javascript: void(0)" data-bind="click: function(){ onePageViewModel.changeEditorType('impala'); onePageViewModel.currentApp('editor') }"><img src="${ static(apps['impala'].icon_path) }" class="app-icon"/> ${_('Impala Query')}</a></li>
  100. </ul>
  101. </li>
  102. % endif
  103. % if 'beeswax' in apps and 'impala' not in apps:
  104. <li><a href="javascript: void(0)" data-bind="click: function(){ onePageViewModel.changeEditorType('hive'); onePageViewModel.currentApp('editor') }"><img src="${ static(apps['beeswax'].icon_path) }" class="app-icon"/> ${_('Hive Query')}</a></li>
  105. % endif
  106. % if 'impala' in apps and 'beeswax' not in apps: ## impala requires beeswax anyway
  107. <li><a href="javascript: void(0)" data-bind="click: function(){ onePageViewModel.changeEditorType('impala'); onePageViewModel.currentApp('editor') }"><img src="${ static(apps['impala'].icon_path) }" class="app-icon"/> ${_('Impala Query')}</a></li>
  108. % endif
  109. % if IS_DASHBOARD_ENABLED.get():
  110. <li><a href="javascript: void(0)" data-bind="click: function(){ onePageViewModel.currentApp('dashboard') }"><i class="fa fa-fw fa-area-chart"></i> ${ _('Dashboard') }</a></li>
  111. % endif
  112. <li><a href="javascript: void(0)" data-bind="click: function(){ onePageViewModel.currentApp('notebook') }"><i class="fa fa-fw fa-file-text-o inline-block"></i> ${ _('Presentation') }</a></li>
  113. % if 'oozie' in apps:
  114. % if not user.has_hue_permission(action="disable_editor_access", app="oozie") or user.is_superuser:
  115. <li class="dropdown-submenu">
  116. <a title="${_('Schedule with Oozie')}" rel="navigator-tooltip" href="#"><img src="${ static('oozie/art/icon_oozie_editor_48.png') }" class="app-icon" /> ${ _('Workflow') }</a>
  117. <ul class="dropdown-menu">
  118. <li><a href="javascript: void(0)" data-bind="click: function(){ onePageViewModel.currentApp('oozie_workflow') }"><img src="${ static('oozie/art/icon_oozie_workflow_48.png') }" class="app-icon"/> ${_('Workflow')}</a></li>
  119. <li><a href="javascript: void(0)" data-bind="click: function(){ onePageViewModel.currentApp('oozie_coordinator') }"><img src="${ static('oozie/art/icon_oozie_coordinator_48.png') }" class="app-icon" /> ${_('Schedule')}</a></li>
  120. <li><a href="javascript: void(0)" data-bind="click: function(){ onePageViewModel.currentApp('oozie_bundle') }"/><img src="${ static('oozie/art/icon_oozie_bundle_48.png') }" class="app-icon" /> ${_('Bundle')}</a></li>
  121. </ul>
  122. </li>
  123. % endif
  124. % endif
  125. % if len(interpreters) > 0:
  126. <li class="divider"></li>
  127. <li class="dropdown-submenu">
  128. <a title="${_('More...')}" rel="navigator-tooltip" href="#"><span class="dropdown-no-icon">${ _('More') }</span></a>
  129. <ul class="dropdown-menu">
  130. % for interpreter in interpreters:
  131. % if interpreter['name'] != 'Hive' and interpreter['name'] != 'Impala':
  132. <li><a href="javascript: void(0)" data-bind="click: function(){ onePageViewModel.changeEditorType('${ interpreter['type'] }'); onePageViewModel.currentApp('editor') }"><span class="dropdown-no-icon">${ interpreter['name'] }</span></a></li>
  133. % endif
  134. % endfor
  135. % if user.is_superuser:
  136. <li class="divider"></li>
  137. <li><a href="gethue.com" class="dropdown-no-icon">${ _('Add more...') }</a></li>
  138. % endif
  139. </ul>
  140. </li>
  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. >
  162. <a class="inactive-action" data-bind="click: performSearch"><i class="fa fa-search" data-bind="css: { 'blue': searchHasFocus() || searchActive() }"></i></a>
  163. </div>
  164. </div>
  165. <div class="top-nav-right">
  166. % if user.is_authenticated() and section != 'login':
  167. <div class="compose-action btn-group">
  168. <%
  169. view_profile = user.has_hue_permission(action="access_view:useradmin:edit_user", app="useradmin") or user.is_superuser
  170. %>
  171. <button class="btn"
  172. % if view_profile:
  173. ### <a href="${ url('useradmin.views.edit_user', username=user.username) }"
  174. data-bind="click: function(){ onePageViewModel.currentApp('jobbrowser') }" title="${ _('View Profile') if is_ldap_setup else _('Edit Profile') }"
  175. % endif
  176. >
  177. ${ user.username }
  178. </button>
  179. % if user.is_superuser:
  180. <button class="btn dropdown-toggle" data-toggle="dropdown">
  181. <span class="caret"></span>
  182. </button>
  183. <ul class="dropdown-menu" >
  184. <li><a href="${ url('useradmin.views.list_users') }"><i class="fa fa-group"></i> ${_('Manage Users')}</a></li>
  185. <li><a href="${ url('useradmin.views.list_permissions') }"><i class="fa fa-key"></i> ${_('Set Permissions')}</a></li>
  186. <li><a href="/about"><span class="dropdown-no-icon">${_('Help')}</span></a></li>
  187. <li><a href="/about"><span class="dropdown-no-icon">${_('About Hue')}</span></a></li>
  188. <li class="divider"></li>
  189. <li><a title="${_('Sign out')}" href="/accounts/logout/"><i class="fa fa-sign-out"></i> ${ _('Sign out') }</a></li>
  190. </ul>
  191. % endif
  192. </div>
  193. <div class="compose-action btn-group">
  194. <button class="btn" title="${_('Submission history')}" data-bind="toggle: historyPanelVisible"><i class="fa fa-history"></i> <div class="jobs-badge">5</div></button>
  195. </div>
  196. <div class="jobs-panel" data-bind="visible: historyPanelVisible" style="display: none;">
  197. <a class="pointer pull-right" data-bind="click: function(){ historyPanelVisible(false); }"><i class="fa fa-times"></i></a>
  198. <!-- ko if: editorVM.selectedNotebook() -->
  199. <!-- ko with: editorVM.selectedNotebook() -->
  200. <div>
  201. Showing
  202. <span data-bind="text: uuid"></span>
  203. <a href="javascript:void(0)" data-bind="attr: { href: onSuccessUrl() }, text: onSuccessUrl" target="_blank"></a>
  204. <!-- ko if: selectedSnippet -->
  205. <!-- ko if: selectedSnippet().progress -->
  206. <div class="snippet-progress-container">
  207. <div class="progress-snippet progress active" data-bind="css: {
  208. 'progress-starting': progress() == 0 && status() == 'running',
  209. 'progress-warning': progress() > 0 && progress() < 100,
  210. 'progress-success': progress() == 100,
  211. 'progress-danger': progress() == 0 && errors().length > 0}" style="background-color: #FFF; width: 100%">
  212. <div class="bar" data-bind="style: {'width': (errors().length > 0 ? 100 : Math.max(2,progress())) + '%'}"></div>
  213. </div>
  214. </div>
  215. <!-- /ko -->
  216. <!-- ko if: selectedSnippet().result -->
  217. <pre data-bind="visible: selectedSnippet().result.logs().length == 0" class="logs logs-bigger">${ _('No logs available at this moment.') }</pre>
  218. <pre data-bind="visible: selectedSnippet().result.logs().length > 0, text: result.logs, logScroller: result.logs, logScrollerVisibilityEvent: showLogs, niceScroll" class="logs logs-bigger logs-populated"></pre>
  219. <!-- /ko -->
  220. <!-- /ko -->
  221. </div>
  222. <!-- ko if: history -->
  223. <hr>
  224. <div class="notification-history margin-bottom-10" data-bind="niceScroll">
  225. <!-- ko if: history().length == 0 -->
  226. <span style="font-style: italic">${ _('No history to be shown.') }</span>
  227. <!-- /ko -->
  228. <!-- ko if: history().length > 0 -->
  229. <div class="notification-history-title">
  230. <strong>${ _('History') }</strong>
  231. <div class="inactive-action pointer pull-right" title="${_('Clear the query history')}" data-target="#clearNotificationHistoryModal" data-toggle="modal" rel="tooltip"><i class="fa fa-calendar-times-o"></i></div>
  232. <div class="clearfix"></div>
  233. </div>
  234. <ul class="unstyled notification-history-list">
  235. <!-- ko foreach: history -->
  236. <li data-bind="click: function() { editorVM.openNotebook(uuid()); }">
  237. <div class="muted pull-left" data-bind="momentFromNow: {data: lastExecuted, interval: 10000, titleFormat: 'LLL'}"></div>
  238. <div class="pull-right muted">
  239. <!-- ko switch: status -->
  240. <!-- ko case: 'running' -->
  241. <div class="history-status" data-bind="tooltip: { title: '${ _ko("Query running") }', placement: 'bottom' }"><i class="fa fa-fighter-jet fa-fw"></i></div>
  242. <!-- /ko -->
  243. <!-- ko case: 'failed' -->
  244. <div class="history-status" data-bind="tooltip: { title: '${ _ko("Query failed") }', placement: 'bottom' }"><i class="fa fa-exclamation fa-fw"></i></div>
  245. <!-- /ko -->
  246. <!-- ko case: 'available' -->
  247. <div class="history-status" data-bind="tooltip: { title: '${ _ko("Result available") }', placement: 'bottom' }"><i class="fa fa-check fa-fw"></i></div>
  248. <!-- /ko -->
  249. <!-- ko case: 'expired' -->
  250. <div class="history-status" data-bind="tooltip: { title: '${ _ko("Result expired") }', placement: 'bottom' }"><i class="fa fa-unlink fa-fw"></i></div>
  251. <!-- /ko -->
  252. <!-- /ko -->
  253. </div>
  254. <div class="clearfix"></div>
  255. <strong data-bind="text: name, attr: { title: uuid }"></strong>
  256. <div data-bind="highlight: { value: 'statement' }"></div>
  257. </li>
  258. <!-- /ko -->
  259. </ul>
  260. <!-- /ko -->
  261. </div>
  262. <!-- /ko -->
  263. <!-- /ko -->
  264. <!-- /ko -->
  265. </div>
  266. <div class="compose-action btn-group">
  267. <button class="btn" title="${_('Running jobs and workflows')}" data-bind="click: function(){ onePageViewModel.currentApp('jobbrowser') }">${ _('Jobs') } <div id="jobBrowserCount" class="jobs-badge" style="display:none;">0</div></button>
  268. <button class="btn dropdown-toggle" data-bind="toggle: jobsPanelVisible">
  269. <span class="caret"></span>
  270. </button>
  271. </div>
  272. <div class="jobs-panel" data-bind="visible: jobsPanelVisible" style="display: none;">
  273. <span style="font-size: 15px; font-weight: 300">${_('Jobs')} | ${_('Workflows')} | ${_('Schedules')}</span>
  274. <div id="mini_jobbrowser"></div>
  275. </div>
  276. % endif
  277. </div>
  278. </div>
  279. <div class="content-wrapper">
  280. <div class="left-nav" data-bind="css: { 'left-nav-visible': leftNavVisible }, niceScroll">
  281. <ul class="left-nav-menu">
  282. <li class="header" style="padding-left: 4px; border-bottom: 1px solid #DDD; padding-bottom: 3px;">${ _('Analyse') }</li>
  283. <li data-bind="click: function () { onePageViewModel.currentApp('home') }"><a href="javascript: void(0);">Home</a></li>
  284. <li data-bind="click: function () { onePageViewModel.changeEditorType('hive'); onePageViewModel.currentApp('editor') }"><a href="javascript: void(0);">Editor</a></li>
  285. <li data-bind="click: function () { onePageViewModel.currentApp('dashboard') }"><a href="javascript: void(0);">Dashboard</a></li>
  286. <li data-bind="click: function () { onePageViewModel.currentApp('notebook') }"><a href="javascript: void(0);">Report</a></li>
  287. <li data-bind="click: function () { onePageViewModel.currentApp('oozie_workflow') }"><a href="javascript: void(0);">Workflows</a></li>
  288. <li class="header">&nbsp;</li>
  289. <li class="header" style="padding-left: 4px; border-bottom: 1px solid #DDD; padding-bottom: 3px;">${ _('Browse') }</li>
  290. <li data-bind="click: function () { onePageViewModel.currentApp('filebrowser') }"><a href="javascript: void(0);">Files</a></li>
  291. <li data-bind="click: function () { onePageViewModel.currentApp('filebrowser_s3') }"><a href="javascript: void(0);">S3</a></li>
  292. <li data-bind="click: function () { onePageViewModel.currentApp('metastore') }"><a href="javascript: void(0);">Tables</a></li>
  293. <li data-bind="click: function () { onePageViewModel.currentApp('indexes') }"><a href="javascript: void(0);">Indexes</a></li>
  294. <li data-bind="click: function () { onePageViewModel.currentApp('jobbrowser') }"><a href="javascript: void(0);">Jobs</a></li>
  295. <li data-bind="click: function () { onePageViewModel.currentApp('useradmin_users') }"><a href="javascript: void(0);">Users</a></li>
  296. <li><a href="javascript: void(0);">HBase</a></li>
  297. <li><a href="javascript: void(0);">Security</a></li>
  298. <li class="header">&nbsp;</li>
  299. <li class="header" style="padding-left: 4px; border-bottom: 1px solid #DDD; padding-bottom: 3px;">${ _('Apps') }</li>
  300. <li><a href="javascript: void(0);">Custom App 1</a></li>
  301. <li><a href="javascript: void(0);">Custom App 2</a></li>
  302. </ul>
  303. <div class="left-nav-drop">
  304. <div data-bind="dropzone: { clickable: false, url: '/filebrowser/upload/file?dest=' + DropzoneGlobals.homeDir, params: {dest: DropzoneGlobals.homeDir}, paramName: 'hdfs_file', onError: onePageViewModel.dropzoneError, onComplete: onePageViewModel.dropzoneComplete }, click: function(){ onePageViewModel.currentApp('importer')}" class="pointer" title="${ _('Import data wizard') }">
  305. <div class="dz-message" data-dz-message><i class="fa fa-fw fa-cloud-upload"></i> ${ _('Drop files here') }</div>
  306. </div>
  307. </div>
  308. </div>
  309. <div class="left-panel" data-bind="css: { 'side-panel-closed': !leftAssistVisible() }, visibleOnHover: { selector: '.hide-left-side-panel' }">
  310. <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>
  311. <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>
  312. <!-- ko if: leftAssistVisible -->
  313. <div class="assist" data-bind="component: {
  314. name: 'assist-panel',
  315. params: {
  316. user: '${user.username}',
  317. sql: {
  318. navigationSettings: {
  319. openItem: false,
  320. showStats: true
  321. }
  322. },
  323. visibleAssistPanels: ['sql']
  324. }
  325. }"></div>
  326. <!-- /ko -->
  327. </div>
  328. <div id="leftResizer" class="resizer" data-bind="visible: leftAssistVisible(), splitFlexDraggable : {
  329. containerSelector: '.content-wrapper',
  330. sidePanelSelector: '.left-panel',
  331. sidePanelVisible: leftAssistVisible,
  332. orientation: 'left',
  333. onPosition: function() { huePubSub.publish('split.draggable.position') }
  334. }"><div class="resize-bar">&nbsp;</div></div>
  335. <div class="page-content" data-bind="niceScroll: {horizrailenabled: false}">
  336. <!-- ko hueSpinner: { spin: isLoadingEmbeddable, center: true, size: 'xlarge' } --><!-- /ko -->
  337. <div id="embeddable_editor" class="embeddable"></div>
  338. <div id="embeddable_notebook" class="embeddable"></div>
  339. <div id="embeddable_metastore" class="embeddable"></div>
  340. <div id="embeddable_dashboard" class="embeddable"></div>
  341. <div id="embeddable_oozie_workflow" class="embeddable"></div>
  342. <div id="embeddable_oozie_coordinator" class="embeddable"></div>
  343. <div id="embeddable_oozie_bundle" class="embeddable"></div>
  344. <div id="embeddable_jobbrowser" class="embeddable"></div>
  345. <div id="embeddable_filebrowser" class="embeddable"></div>
  346. <div id="embeddable_filebrowser_s3" class="embeddable"></div>
  347. <div id="embeddable_fileviewer" class="embeddable"></div>
  348. <div id="embeddable_home" class="embeddable"></div>
  349. <div id="embeddable_indexer" class="embeddable"></div>
  350. <div id="embeddable_importer" class="embeddable"></div>
  351. <div id="embeddable_collections" class="embeddable"></div>
  352. <div id="embeddable_indexes" class="embeddable"></div>
  353. <div id="embeddable_useradmin_users" class="embeddable"></div>
  354. <div id="embeddable_useradmin_groups" class="embeddable"></div>
  355. <div id="embeddable_useradmin_permissions" class="embeddable"></div>
  356. <div id="embeddable_useradmin_configurations" class="embeddable"></div>
  357. </div>
  358. <div id="rightResizer" class="resizer" data-bind="visible: rightAssistVisible(), splitFlexDraggable : {
  359. containerSelector: '.content-wrapper',
  360. sidePanelSelector: '.right-panel',
  361. sidePanelVisible: rightAssistVisible,
  362. orientation: 'right',
  363. onPosition: function() { huePubSub.publish('split.draggable.position') }
  364. }"><div class="resize-bar" style="right: 0">&nbsp;</div></div>
  365. <div class="right-panel" data-bind="css: { 'side-panel-closed': !rightAssistVisible() }, visibleOnHover: { selector: '.hide-right-side-panel' }">
  366. <a href="javascript:void(0);" style="display: none;" title="${_('Show Assist')}" class="pointer side-panel-toggle show-right-side-panel" data-bind="visible: ! rightAssistVisible(), toggle: rightAssistVisible"><i class="fa fa-chevron-left"></i></a>
  367. <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, toggle: rightAssistVisible"><i class="fa fa-chevron-right"></i></a>
  368. <div data-bind="visible: rightAssistVisible" style="display: none; height: 100%; width: 100%; position: relative;">
  369. <ul class="right-panel-tabs nav nav-pills">
  370. <li data-bind="css: { 'active' : activeRightTab() === 'assistant' }, visible: assistantAvailable"><a href="javascript: void(0);" data-bind="click: function() { activeRightTab('assistant'); }">${ _('Assistant') }</a></li>
  371. <li data-bind="css: { 'active' : activeRightTab() === 'functions' }"><a href="javascript: void(0);" data-bind="click: function() { activeRightTab('functions'); }">${ _('Functions') }</a></li>
  372. <li data-bind="css: { 'active' : activeRightTab() === 'schedules' }"><a href="javascript: void(0);" data-bind="click: function() { activeRightTab('schedules'); }">${ _('Schedule') }</a></li>
  373. </ul>
  374. <div class="right-panel-tab-content tab-content">
  375. <!-- ko if: activeRightTab() === 'assistant' -->
  376. <div data-bind="component: { name: 'assistant-panel' }"></div>
  377. <!-- /ko -->
  378. <!-- ko if: activeRightTab() === 'functions' -->
  379. <div data-bind="component: { name: 'functions-panel' }"></div>
  380. <!-- /ko -->
  381. <!-- ko if: activeRightTab() === 'schedules' -->
  382. <div>Schedules</div>
  383. <!-- /ko -->
  384. </div>
  385. </div>
  386. </div>
  387. <div class="context-panel" data-bind="css: { 'visible': contextPanelVisible }">
  388. <ul class="nav nav-tabs">
  389. <!-- ko if: sessionsAvailable -->
  390. <li class="active"><a href="#sessionsTab" data-toggle="tab" data-bind="visible: sessionsAvailable">${_('Sessions')}</a></li>
  391. <!-- /ko -->
  392. </ul>
  393. <div class="tab-content">
  394. <!-- ko if: sessionsAvailable -->
  395. <div class="tab-pane active" id="sessionsTab">
  396. <div class="row-fluid">
  397. <div class="span12" data-bind="template: { name: 'notebook-session-config-template', data: activeAppViewModel }"></div>
  398. </div>
  399. </div>
  400. <!-- /ko -->
  401. </div>
  402. </div>
  403. </div>
  404. </div>
  405. <div id="clearNotificationHistoryModal" class="modal hide fade">
  406. <div class="modal-header">
  407. <a href="#" class="close" data-dismiss="modal">&times;</a>
  408. <h3>${_('Confirm History Clear')}</h3>
  409. </div>
  410. <div class="modal-body">
  411. <p>${_('Are you sure you want to clear the query history?')}</p>
  412. </div>
  413. <div class="modal-footer">
  414. <a class="btn" data-dismiss="modal">${_('No')}</a>
  415. <a class="btn btn-danger disable-feedback" onclick="editorVM.selectedNotebook().clearHistory()">${_('Yes')}</a>
  416. </div>
  417. </div>
  418. <script src="${ static('desktop/js/cui-bundle.js') }"></script>
  419. <script src="${ static('desktop/js/jquery.migration.js') }"></script>
  420. <script src="${ static('desktop/js/hue.utils.js') }"></script>
  421. <script src="${ static('desktop/ext/js/bootstrap.min.js') }"></script>
  422. <script src="${ static('desktop/ext/js/bootstrap-better-typeahead.min.js') }"></script>
  423. <script src="${ static('desktop/ext/js/fileuploader.js') }"></script>
  424. <script src="${ static('desktop/ext/js/filesize.min.js') }"></script>
  425. <script src="${ static('desktop/ext/js/moment-with-locales.min.js') }"></script>
  426. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.total-storage.min.js') }"></script>
  427. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.cookie.js') }"></script>
  428. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.dataTables.1.8.2.min.js') }"></script>
  429. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.form.js') }"></script>
  430. <script src="${ static('desktop/js/jquery.datatables.sorting.js') }"></script>
  431. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.basictable.min.js') }"></script>
  432. <script src="${ static('desktop/ext/js/jquery/plugins/jquery-ui-1.10.4.custom.min.js') }"></script>
  433. <script src="${ static('desktop/js/jquery.nicescroll.js') }"></script>
  434. <script src="${ static('desktop/js/jquery.hiveautocomplete.js') }"></script>
  435. <script src="${ static('desktop/js/jquery.hdfsautocomplete.js') }"></script>
  436. <script src="${ static('desktop/js/jquery.filechooser.js') }"></script>
  437. <script src="${ static('desktop/js/jquery.selector.js') }"></script>
  438. <script src="${ static('desktop/js/jquery.delayedinput.js') }"></script>
  439. <script src="${ static('desktop/js/jquery.rowselector.js') }"></script>
  440. <script src="${ static('desktop/js/jquery.notify.js') }"></script>
  441. <script src="${ static('desktop/js/jquery.titleupdater.js') }"></script>
  442. <script src="${ static('desktop/js/jquery.horizontalscrollbar.js') }"></script>
  443. <script src="${ static('desktop/js/jquery.tablescroller.js') }"></script>
  444. <script src="${ static('desktop/js/jquery.tableextender.js') }"></script>
  445. <script src="${ static('desktop/js/jquery.tableextender2.js') }"></script>
  446. <script src="${ static('desktop/ext/js/d3.v3.js') }"></script>
  447. <script src="${ static('desktop/ext/js/d3.v4.js') }"></script>
  448. <script src="${ static('desktop/js/hue.colors.js') }"></script>
  449. <script src="${ static('desktop/js/apiHelper.js') }"></script>
  450. <script src="${ static('desktop/js/ko.charts.js') }"></script>
  451. <script src="${ static('desktop/ext/js/knockout-sortable.min.js') }"></script>
  452. <script src="${ static('desktop/ext/js/knockout.validation.min.js') }"></script>
  453. <script src="${ static('desktop/ext/js/bootstrap-editable.min.js') }"></script>
  454. <script src="${ static('desktop/js/ko.editable.js') }"></script>
  455. <script src="${ static('desktop/js/ko.switch-case.js') }"></script>
  456. <script src="${ static('desktop/js/ko.hue-bindings.js') }"></script>
  457. <script src="${ static('desktop/js/jquery.scrollleft.js') }"></script>
  458. <script src="${ static('desktop/js/jquery.scrollup.js') }"></script>
  459. <script src="${ static('desktop/js/jquery.tour.js') }"></script>
  460. <script src="${ static('desktop/js/jquery.huedatatable.js') }"></script>
  461. <script src="${ static('desktop/js/sqlFunctions.js') }"></script>
  462. <script src="${ static('desktop/ext/js/selectize.min.js') }"></script>
  463. <script src="${ static('desktop/js/ko.selectize.js') }"></script>
  464. <script src="${ static('desktop/js/ace/ace.js') }"></script>
  465. <script src="${ static('desktop/js/ace/mode-impala.js') }"></script>
  466. <script src="${ static('desktop/js/ace/mode-hive.js') }"></script>
  467. <script src="${ static('desktop/js/ace/ext-language_tools.js') }"></script>
  468. <script src="${ static('desktop/js/ace.extended.js') }"></script>
  469. <script src="${ static('desktop/ext/js/dropzone.min.js') }"></script>
  470. # Task History
  471. <script src="${ static('desktop/js/autocomplete/sql.js') }"></script>
  472. <script src="${ static('desktop/js/sqlAutocompleter.js') }"></script>
  473. <script src="${ static('desktop/js/sqlAutocompleter2.js') }"></script>
  474. <script src="${ static('desktop/js/hdfsAutocompleter.js') }"></script>
  475. <script src="${ static('desktop/js/autocompleter.js') }"></script>
  476. <script src="${ static('desktop/js/hue.json.js') }"></script>
  477. <script src="${ static('notebook/js/notebook.ko.js') }"></script>
  478. <script type="text/javascript">
  479. (function () {
  480. var proxiedKORegister = ko.components.register;
  481. var LOADED_COMPONENTS = [];
  482. ko.components.register = function () {
  483. if (LOADED_COMPONENTS.indexOf(arguments[0]) === -1) {
  484. LOADED_COMPONENTS.push(arguments[0]);
  485. return proxiedKORegister.apply(this, arguments);
  486. }
  487. };
  488. })();
  489. </script>
  490. ${ koComponents.all() }
  491. ${ commonHeaderFooterComponents.header_pollers(user, is_s3_enabled, apps) }
  492. ${ assist.assistJSModels() }
  493. ${ assist.assistPanel() }
  494. <iframe id="zoomDetectFrame" style="width: 250px; display: none" ></iframe>
  495. <script type="text/javascript">
  496. $(document).ready(function () {
  497. var options = {
  498. user: '${ user.username }',
  499. i18n: {
  500. errorLoadingDatabases: "${ _('There was a problem loading the databases') }"
  501. }
  502. };
  503. $(document).on('hideHistoryModal', function (e) {
  504. $('#clearNotificationHistoryModal').modal('hide');
  505. });
  506. var onePageViewModel = (function () {
  507. var LOADED_JS = [];
  508. var LOADED_CSS = [];
  509. $('script[src]').each(function(){
  510. LOADED_JS.push($(this).attr('src'));
  511. });
  512. $('link[href]').each(function(){
  513. LOADED_CSS.push($(this).attr('href'));
  514. });
  515. var OnePageViewModel = function () {
  516. var self = this;
  517. self.EMBEDDABLE_PAGE_URLS = {
  518. editor: '/notebook/editor_embeddable',
  519. notebook: '/notebook/notebook_embeddable',
  520. metastore: '/metastore/tables/?is_embeddable=true',
  521. dashboard: '/dashboard/embeddable/new_search',
  522. oozie_workflow: '/oozie/editor/workflow/new/?is_embeddable=true',
  523. oozie_coordinator: '/oozie/editor/coordinator/new/?is_embeddable=true',
  524. oozie_bundle: '/oozie/editor/bundle/new/?is_embeddable=true',
  525. jobbrowser: '/jobbrowser/apps?is_embeddable=true',
  526. filebrowser: '/filebrowser/?is_embeddable=true',
  527. filebrowser_s3: '/filebrowser/view=S3A://?is_embeddable=true',
  528. fileviewer: 'filebrowser/view=',
  529. home: '/home_embeddable',
  530. indexer: '/indexer/indexer/?is_embeddable=true',
  531. collections: '/dashboard/admin/collections?is_embeddable=true',
  532. indexes: '/indexer/?is_embeddable=true',
  533. importer: '/indexer/importer/?is_embeddable=true',
  534. useradmin_users: '/useradmin/users?is_embeddable=true',
  535. useradmin_groups: '/useradmin/groups?is_embeddable=true',
  536. useradmin_permissions: '/useradmin/permissions?is_embeddable=true',
  537. useradmin_configurations: '/useradmin/configurations?is_embeddable=true',
  538. };
  539. self.SKIP_CACHE = ['fileviewer', 'useradmin_users', 'useradmin_groups', 'useradmin_permissions', 'useradmin_configurations'];
  540. self.embeddable_cache = {};
  541. self.getActiveAppViewModel = function (callback) {
  542. var checkInterval = window.setInterval(function () {
  543. var $koElement = $('#' + self.currentApp() + 'Components');
  544. if ($koElement.length > 0 && ko.dataFor($koElement[0])) {
  545. window.clearInterval(checkInterval);
  546. callback(ko.dataFor($koElement[0]));
  547. }
  548. }, 25);
  549. }
  550. self.currentApp = ko.observable();
  551. self.currentApp.subscribe(function () {
  552. self.getActiveAppViewModel(function (viewModel) {
  553. huePubSub.publish('set.current.app.view.model', viewModel);
  554. })
  555. })
  556. huePubSub.subscribe('get.current.app.view.model', function () {
  557. self.getActiveAppViewModel(function (viewModel) {
  558. huePubSub.publish('set.current.app.view.model', viewModel);
  559. })
  560. })
  561. self.isLoadingEmbeddable = ko.observable(false);
  562. self.extraEmbeddableURLParams = ko.observable('');
  563. self.changeEditorType = function (type) {
  564. self.extraEmbeddableURLParams('?type=' + type);
  565. hueUtils.changeURLParameter('type', type);
  566. self.getActiveAppViewModel(function (viewModel) {
  567. if (viewModel && viewModel.selectedNotebook && viewModel.selectedNotebook()) {
  568. viewModel.selectedNotebook().selectedSnippet(type);
  569. viewModel.editorType(type);
  570. viewModel.newNotebook();
  571. }
  572. })
  573. }
  574. huePubSub.subscribe('open.fb.file', function (path) {
  575. self.extraEmbeddableURLParams(path + '?is_embeddable=true');
  576. hueUtils.changeURLParameter('path', path);
  577. self.currentApp('fileviewer');
  578. });
  579. huePubSub.subscribe('open.fb.folder', function (path) {
  580. hueUtils.removeURLParameter('path');
  581. self.currentApp('filebrowser');
  582. window.location.hash = path;
  583. });
  584. huePubSub.subscribe('open.link', function (href) {
  585. if (href.startsWith('/notebook/editor')){
  586. if (hueUtils.getSearchParameter(href, 'editor') !== '') {
  587. hueUtils.changeURLParameter('editor', hueUtils.getSearchParameter(href, 'editor'));
  588. self.currentApp('editor')
  589. self.getActiveAppViewModel(function (viewModel) {
  590. viewModel.openNotebook(hueUtils.getSearchParameter(href, 'editor'));
  591. })
  592. } else if (location.getParameter('type') !== ''){
  593. if (hueUtils.getSearchParameter(href, 'type') !== '' && hueUtils.getSearchParameter(href, 'type') !== location.getParameter('type')) {
  594. self.changeEditorType(hueUtils.getSearchParameter(href, 'type'));
  595. }
  596. } else {
  597. if (hueUtils.getSearchParameter(href, 'type') !== ''){
  598. self.changeEditorType(hueUtils.getSearchParameter(href, 'type'));
  599. } else {
  600. self.changeEditorType('hive');
  601. }
  602. self.currentApp('editor')
  603. }
  604. } else if (href.startsWith('/metastore')){
  605. self.currentApp('metastore');
  606. hueUtils.changeURLParameter('path', href.substring('/metastore'.length + 1));
  607. self.getActiveAppViewModel(function (metastoreViewModel) {
  608. metastoreViewModel.loadURL();
  609. });
  610. } else if (href.startsWith('/indexer/importer/prefill')){
  611. self.currentApp('importer');
  612. self.getActiveAppViewModel(function (viewModel) {
  613. var arguments = href.match(/\/indexer\/importer\/prefill\/?([^/]+)\/?([^/]+)\/?([^/]+)/);
  614. if (! arguments) {
  615. console.warn('Could not match ' + href)
  616. }
  617. viewModel.createWizard.prefill.source_type(arguments && arguments[1] ? arguments[1] : '');
  618. viewModel.createWizard.prefill.target_type(arguments && arguments[2] ? arguments[2] : '');
  619. viewModel.createWizard.prefill.target_path(arguments && arguments[3] ? arguments[3] : '');
  620. })
  621. } else if (href.startsWith('/notebook')){
  622. self.currentApp('notebook');
  623. } else if (href.startsWith('/pig')){
  624. self.changeEditorType('pig');
  625. self.currentApp('editor');
  626. } else if (href.startsWith('/dashboard')){
  627. self.currentApp('dashboard');
  628. } else if (href.startsWith('/oozie/editor/workflow/new')){
  629. self.currentApp('oozie_workflow');
  630. } else if (href.startsWith('/oozie/editor/coordinator/new')){
  631. self.currentApp('oozie_coordinator');
  632. } else if (href.startsWith('/oozie/editor/bundle/new')){
  633. self.currentApp('oozie_bundle');
  634. } else if (href.startsWith('/filebrowser')){
  635. self.currentApp('filebrowser');
  636. } else if (href.startsWith('/useradmin/users')){
  637. self.currentApp('useradmin_users');
  638. } else if (href.startsWith('/useradmin/groups')){
  639. self.currentApp('useradmin_groups');
  640. } else if (href.startsWith('/useradmin/permissions')){
  641. self.currentApp('useradmin_permissions');
  642. } else if (href.startsWith('/useradmin/configurations')){
  643. self.currentApp('useradmin_configurations');
  644. }
  645. });
  646. function processHeaders(response){
  647. var r = $('<span>').html(response);
  648. r.find('link').each(function () {
  649. $(this).attr('href', $(this).attr('href') + '?' + Math.random())
  650. });
  651. // load just CSS and JS files that are not loaded before
  652. r.find('script[src]').each(function () {
  653. var jsFile = $(this).attr('src').split('?')[0];
  654. if (LOADED_JS.indexOf(jsFile) === -1) {
  655. LOADED_JS.push(jsFile);
  656. $(this).clone().appendTo($('head'));
  657. }
  658. $(this).remove();
  659. });
  660. r.find('link[href]').each(function () {
  661. var cssFile = $(this).attr('href').split('?')[0];
  662. if (LOADED_CSS.indexOf(cssFile) === -1) {
  663. LOADED_CSS.push(cssFile);
  664. $(this).clone().appendTo($('head'));
  665. }
  666. $(this).remove();
  667. });
  668. r.unwrap('<span>');
  669. return r;
  670. }
  671. self.currentApp.subscribe(function (newVal) {
  672. hueUtils.changeURLParameter('app', newVal);
  673. if (newVal !== 'editor') {
  674. hueUtils.removeURLParameter('type');
  675. }
  676. self.isLoadingEmbeddable(true);
  677. if (typeof self.embeddable_cache[newVal] === 'undefined') {
  678. $.ajax({
  679. url: self.EMBEDDABLE_PAGE_URLS[newVal] + self.extraEmbeddableURLParams(),
  680. beforeSend: function (xhr) {
  681. xhr.setRequestHeader('X-Requested-With', 'Hue');
  682. },
  683. dataType: 'html',
  684. success: function (response) {
  685. self.extraEmbeddableURLParams('');
  686. var r = processHeaders(response);
  687. if (self.SKIP_CACHE.indexOf(newVal) === -1) {
  688. self.embeddable_cache[newVal] = r;
  689. }
  690. $('#embeddable_' + newVal).html(r);
  691. self.isLoadingEmbeddable(false);
  692. }
  693. });
  694. } else {
  695. self.isLoadingEmbeddable(false);
  696. }
  697. $('.embeddable').hide();
  698. $('#embeddable_' + newVal).insertBefore($('.embeddable:first')).show();
  699. });
  700. self.loadAppState = function () {
  701. if (window.location.getParameter('app') !== '' && self.EMBEDDABLE_PAGE_URLS[window.location.getParameter('app')]) {
  702. var app = window.location.getParameter('app');
  703. switch (app) {
  704. case 'fileviewer':
  705. if (window.location.getParameter('path') !== '') {
  706. self.extraEmbeddableURLParams(window.location.getParameter('path') + '?is_embeddable=true');
  707. self.currentApp(app);
  708. }
  709. else {
  710. self.currentApp('filebrowser');
  711. }
  712. break;
  713. case 'filebrowser':
  714. var previousHash = window.location.hash;
  715. self.currentApp(app);
  716. window.location.hash = previousHash;
  717. break;
  718. case 'editor':
  719. if (window.location.getParameter('type') !== '') {
  720. self.changeEditorType(window.location.getParameter('type'));
  721. }
  722. self.currentApp(app);
  723. break;
  724. default:
  725. self.currentApp(app);
  726. }
  727. }
  728. else {
  729. self.currentApp('editor');
  730. }
  731. }
  732. self.dropzoneError = function (filename) {
  733. self.currentApp('importer');
  734. self.getActiveAppViewModel(function (vm) {
  735. vm.createWizard.source.path(DropzoneGlobals.homeDir + '/' + filename);
  736. });
  737. }
  738. self.dropzoneComplete = function (path) {
  739. self.currentApp('importer');
  740. self.getActiveAppViewModel(function (vm) {
  741. vm.createWizard.source.path(path);
  742. });
  743. }
  744. self.loadAppState();
  745. window.onpopstate = function (event) {
  746. self.loadAppState();
  747. };
  748. huePubSub.subscribe('switch.app', function (name) {
  749. self.currentApp(name);
  750. });
  751. // load the mini jobbrowser
  752. $.ajax({
  753. url: '/jobbrowser/apps?is_embeddable=true&is_mini=true',
  754. beforeSend: function (xhr) {
  755. xhr.setRequestHeader('X-Requested-With', 'Hue');
  756. },
  757. dataType: 'html',
  758. success: function (response) {
  759. var r = processHeaders(response);
  760. $('#mini_jobbrowser').html(r);
  761. }
  762. });
  763. };
  764. var onePageViewModel = new OnePageViewModel();
  765. ko.applyBindings(onePageViewModel, $('.page-content')[0]);
  766. return onePageViewModel;
  767. })();
  768. var sidePanelViewModel = (function () {
  769. function SidePanelViewModel () {
  770. var self = this;
  771. self.apiHelper = ApiHelper.getInstance();
  772. self.leftAssistVisible = ko.observable();
  773. self.rightAssistVisible = ko.observable();
  774. self.assistantAvailable = ko.observable(false);
  775. self.activeRightTab = ko.observable();
  776. self.activeAppViewModel = ko.observable();
  777. self.contextPanelVisible = ko.observable(false);
  778. self.sessionsAvailable = ko.observable(false);
  779. self.activeAppViewModel.subscribe(function (viewModel) {
  780. self.sessionsAvailable(typeof viewModel.selectedNotebook !== 'undefined');
  781. })
  782. huePubSub.subscribe('context.panel.visible', function (visible) {
  783. console.log(visible);
  784. self.contextPanelVisible(visible);
  785. })
  786. huePubSub.subscribe('active.snippet.type.changed', function (type) {
  787. if (type === 'hive' || type === 'impala') {
  788. if (!self.assistantAvailable() && self.activeRightTab() !== 'assistant') {
  789. self.activeRightTab('assistant');
  790. }
  791. self.assistantAvailable(true);
  792. } else {
  793. if (self.activeRightTab() === 'assistant') {
  794. self.activeRightTab('functions');
  795. }
  796. self.assistantAvailable(false);
  797. }
  798. });
  799. huePubSub.subscribe('set.current.app.view.model', self.activeAppViewModel);
  800. huePubSub.publish('get.current.app.view.model');
  801. if (!self.activeRightTab()) {
  802. self.activeRightTab('functions');
  803. }
  804. if (self.assistantAvailable()) {
  805. self.activeRightTab = ko.observable('assistant');
  806. }
  807. self.apiHelper.withTotalStorage('assist', 'left_assist_panel_visible', self.leftAssistVisible, true);
  808. self.apiHelper.withTotalStorage('assist', 'right_assist_panel_visible', self.rightAssistVisible, true);
  809. }
  810. var sidePanelViewModel = new SidePanelViewModel();
  811. ko.applyBindings(sidePanelViewModel, $('.left-panel')[0]);
  812. ko.applyBindings(sidePanelViewModel, $('#leftResizer')[0]);
  813. ko.applyBindings(sidePanelViewModel, $('#rightResizer')[0]);
  814. ko.applyBindings(sidePanelViewModel, $('.right-panel')[0]);
  815. ko.applyBindings(sidePanelViewModel, $('.context-panel')[0]);
  816. return sidePanelViewModel;
  817. })();
  818. var topNavViewModel = (function (onePageViewModel) {
  819. function TopNavViewModel () {
  820. var self = this;
  821. self.onePageViewModel = onePageViewModel;
  822. self.leftNavVisible = ko.observable(false);
  823. self.leftNavVisible.subscribe(function (val) {
  824. huePubSub.publish('responsive.left.nav.toggle', val);
  825. });
  826. self.onePageViewModel.currentApp.subscribe(function () {
  827. self.leftNavVisible(false);
  828. });
  829. self.apiHelper = ApiHelper.getInstance();
  830. self.searchActive = ko.observable(false);
  831. self.searchHasFocus = ko.observable(false);
  832. self.searchInput = ko.observable();
  833. self.jobsPanelVisible = ko.observable(false);
  834. self.historyPanelVisible = ko.observable(false);
  835. // TODO: Extract to common module (shared with nav search autocomplete)
  836. var SEARCH_FACET_ICON = 'fa-tags';
  837. var SEARCH_TYPE_ICONS = {
  838. 'DATABASE': 'fa-database',
  839. 'TABLE': 'fa-table',
  840. 'VIEW': 'fa-eye',
  841. 'FIELD': 'fa-columns',
  842. 'PARTITION': 'fa-th',
  843. 'SOURCE': 'fa-server',
  844. 'OPERATION': 'fa-cogs',
  845. 'OPERATION_EXECUTION': 'fa-cog',
  846. 'DIRECTORY': 'fa-folder-o',
  847. 'FILE': 'fa-file-o',
  848. 'SUB_OPERATION': 'fa-code-fork',
  849. 'COLLECTION': 'fa-search',
  850. 'HBASE': 'fa-th-large',
  851. 'HUE': 'fa-file-o'
  852. };
  853. self.searchAutocompleteSource = function (request, callback) {
  854. // TODO: Extract complete contents to common module (shared with nav search autocomplete)
  855. var facetMatch = request.term.match(/([a-z]+):\s*(\S+)?$/i);
  856. var isFacet = facetMatch !== null;
  857. var partialMatch = isFacet ? null : request.term.match(/\S+$/);
  858. var partial = isFacet && facetMatch[2] ? facetMatch[2] : (partialMatch ? partialMatch[0] : '');
  859. var beforePartial = request.term.substring(0, request.term.length - partial.length);
  860. self.apiHelper.globalSearchAutocomplete({
  861. query: request.term,
  862. successCallback: function (data) {
  863. var values = [];
  864. var facetPartialRe = new RegExp(partial.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i'); // Protect for 'tags:*axe'
  865. if (typeof data.resultsHuedocuments !== 'undefined') {
  866. data.resultsHuedocuments.forEach(function (result) {
  867. values.push({ data: { label: result.hue_name, icon: SEARCH_TYPE_ICONS[result.type], description: result.hue_description }, value: beforePartial + result.originalName });
  868. });
  869. }
  870. if (values.length > 0) {
  871. values.push({ divider: true });
  872. }
  873. if (isFacet && typeof data.facets !== 'undefined') { // Is typed facet, e.g. type: type:bla
  874. var facetInQuery = facetMatch[1];
  875. if (typeof data.facets[facetInQuery] !== 'undefined') {
  876. $.map(data.facets[facetInQuery], function (count, value) {
  877. if (facetPartialRe.test(value)) {
  878. values.push({ data: { label: facetInQuery + ':' + value, icon: SEARCH_FACET_ICON, description: count }, value: beforePartial + value})
  879. }
  880. });
  881. }
  882. } else {
  883. if (typeof data.facets !== 'undefined') {
  884. Object.keys(data.facets).forEach(function (facet) {
  885. if (facetPartialRe.test(facet)) {
  886. if (Object.keys(data.facets[facet]).length > 0) {
  887. values.push({ data: { label: facet + ':', icon: SEARCH_FACET_ICON, description: $.map(data.facets[facet], function (key, value) { return value + ' (' + key + ')'; }).join(', ') }, value: beforePartial + facet + ':'});
  888. } else { // Potential facet from the list
  889. values.push({ data: { label: facet + ':', icon: SEARCH_FACET_ICON, description: '' }, value: beforePartial + facet + ':'});
  890. }
  891. } else if (partial.length > 0) {
  892. Object.keys(data.facets[facet]).forEach(function (facetValue) {
  893. if (facetValue.indexOf(partial) !== -1) {
  894. values.push({ data: { label: facet + ':' + facetValue, icon: SEARCH_FACET_ICON, description: facetValue }, value: beforePartial + facet + ':' + facetValue });
  895. }
  896. });
  897. }
  898. });
  899. }
  900. }
  901. if (values.length > 0) {
  902. values.push({ divider: true });
  903. }
  904. if (typeof data.results !== 'undefined') {
  905. data.results.forEach(function (result) {
  906. values.push({ data: { label: result.hue_name, icon: SEARCH_TYPE_ICONS[result.type], description: result.hue_description }, value: beforePartial + result.originalName });
  907. });
  908. }
  909. if (values.length > 0 && values[values.length - 1].divider) {
  910. values.pop();
  911. }
  912. if (values.length === 0) {
  913. values.push({ noMatch: true });
  914. }
  915. callback(values);
  916. },
  917. silenceErrors: true,
  918. errorCallback: function () {
  919. callback([]);
  920. }
  921. });
  922. };
  923. }
  924. TopNavViewModel.prototype.performSearch = function () {
  925. };
  926. self.editorVM = new EditorViewModel(null, '', {
  927. user: '${ user.username }',
  928. userId: ${ user.id },
  929. languages: [{name: "Java", type: "java"}, {name: "Hive SQL", type: "hive"}], // TODO reuse
  930. snippetViewSettings: {
  931. java : {
  932. snippetIcon: 'fa-file-archive-o '
  933. },
  934. hive: {
  935. placeHolder: '${ _("Example: SELECT * FROM tablename, or press CTRL + space") }',
  936. aceMode: 'ace/mode/hive',
  937. snippetImage: '${ static("beeswax/art/icon_beeswax_48.png") }',
  938. sqlDialect: true
  939. },
  940. impala: {
  941. placeHolder: '${ _("Example: SELECT * FROM tablename, or press CTRL + space") }',
  942. aceMode: 'ace/mode/impala',
  943. snippetImage: '${ static("impala/art/icon_impala_48.png") }',
  944. sqlDialect: true
  945. },
  946. java : {
  947. snippetIcon: 'fa-file-code-o'
  948. },
  949. shell: {
  950. snippetIcon: 'fa-terminal'
  951. }
  952. }
  953. });
  954. self.editorVM.editorMode(true);
  955. self.editorVM.isNotificationManager(true);
  956. self.editorVM.newNotebook();
  957. huePubSub.subscribe("notebook.task.submitted", function (history_id) {
  958. self.editorVM.openNotebook(history_id, null, true, function(){
  959. var notebook = self.editorVM.selectedNotebook();
  960. notebook.snippets()[0].progress.subscribe(function(val){
  961. if (val == 100){
  962. //self.indexingStarted(false);
  963. //self.isIndexing(false);
  964. //self.indexingSuccess(true);
  965. }
  966. });
  967. notebook.snippets()[0].status.subscribe(function(val){
  968. if (val == 'failed'){
  969. //self.isIndexing(false);
  970. //self.indexingStarted(false);
  971. //self.indexingError(true);
  972. } else if (val == 'available') {
  973. var snippet = notebook.snippets()[0];
  974. if (! snippet.result.handle().has_more_statements) {
  975. // TODO: Show finish notification and clicking on it does onSuccessUrl
  976. // or if still on initial spinner we redirect automatically to onSuccessUrl
  977. if (notebook.onSuccessUrl()) {
  978. if (notebook.onSuccessUrl() == 'assist.db.refresh') { // TODO: Similar if in in FB directory, also refresh FB dir
  979. huePubSub.publish('assist.db.refresh', { sourceType: 'hive' });
  980. } else {
  981. huePubSub.publish('open.link', notebook.onSuccessUrl());
  982. }
  983. }
  984. } else { // Perform last DROP statement execute
  985. snippet.execute();
  986. }
  987. }
  988. });
  989. notebook.snippets()[0].checkStatus();
  990. // Add to history
  991. notebook.history.unshift(
  992. notebook._makeHistoryRecord(
  993. notebook.onSuccessUrl(),
  994. notebook.snippets()[0].result.handle().statement || '',
  995. notebook.snippets()[0].lastExecuted(),
  996. notebook.snippets()[0].status(),
  997. notebook.name(),
  998. notebook.uuid()
  999. )
  1000. );
  1001. });
  1002. topNavViewModel.historyPanelVisible(true);
  1003. });
  1004. var topNavViewModel = new TopNavViewModel();
  1005. ko.applyBindings(topNavViewModel, $('.top-nav')[0]);
  1006. ko.applyBindings(topNavViewModel, $('.left-nav')[0]);
  1007. return topNavViewModel;
  1008. })(onePageViewModel);
  1009. % if 'jobbrowser' in apps:
  1010. var JB_CHECK_INTERVAL_IN_MILLIS = 30000;
  1011. var checkJobBrowserStatusIdx = window.setTimeout(checkJobBrowserStatus, 10);
  1012. var lastJobBrowserRequest = null;
  1013. function checkJobBrowserStatus(){
  1014. if (lastJobBrowserRequest !== null && lastJobBrowserRequest.readyState < 4) {
  1015. return;
  1016. }
  1017. window.clearTimeout(checkJobBrowserStatusIdx);
  1018. lastJobBrowserRequest = $.post("/jobbrowser/jobs/", {
  1019. "format": "json",
  1020. "state": "running",
  1021. "user": "${user.username}"
  1022. },
  1023. function(data) {
  1024. if (data != null && data.jobs != null) {
  1025. huePubSub.publish('jobbrowser.data', data.jobs);
  1026. if (data.jobs.length > 0){
  1027. $("#jobBrowserCount").show().text(data.jobs.length);
  1028. } else {
  1029. $("#jobBrowserCount").hide();
  1030. }
  1031. }
  1032. checkJobBrowserStatusIdx = window.setTimeout(checkJobBrowserStatus, JB_CHECK_INTERVAL_IN_MILLIS);
  1033. }).fail(function () {
  1034. window.clearTimeout(checkJobBrowserStatusIdx);
  1035. });
  1036. }
  1037. huePubSub.subscribe('check.job.browser', checkJobBrowserStatus);
  1038. % endif
  1039. window.hueDebug = {
  1040. viewModel: function (element) {
  1041. return element ? ko.dataFor(element) : window.hueDebug.onePageViewModel;
  1042. },
  1043. onePageViewModel: onePageViewModel,
  1044. sidePanelViewModel: sidePanelViewModel,
  1045. topNavViewModel: topNavViewModel
  1046. };
  1047. });
  1048. </script>
  1049. ${ commonHeaderFooterComponents.footer(messages) }
  1050. </body>
  1051. </html>