hue.mako 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873
  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.conf import IS_EMBEDDED
  20. from desktop.conf import DEV_EMBEDDED
  21. from desktop.views import _ko, commonshare, login_modal
  22. from desktop.lib.i18n import smart_unicode
  23. from desktop.models import PREFERENCE_IS_WELCOME_TOUR_SEEN, ANALYTIC_DB, hue_version
  24. from dashboard.conf import IS_ENABLED as IS_DASHBOARD_ENABLED
  25. from indexer.conf import ENABLE_NEW_INDEXER
  26. from metadata.conf import has_optimizer, OPTIMIZER
  27. %>
  28. <%namespace name="koComponents" file="/ko_components.mako" />
  29. <%namespace name="assist" file="/assist.mako" />
  30. <%namespace name="hueIcons" file="/hue_icons.mako" />
  31. <%namespace name="commonHeaderFooterComponents" file="/common_header_footer_components.mako" />
  32. <!DOCTYPE html>
  33. <html lang="en" dir="ltr">
  34. <head>
  35. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  36. <meta charset="utf-8">
  37. <title>Hue</title>
  38. <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  39. <link rel="icon" type="image/x-icon" href="${ static('desktop/art/favicon.ico') }"/>
  40. <meta name="description" content="">
  41. <meta name="author" content="">
  42. % if DEV_EMBEDDED.get():
  43. <style>
  44. html {
  45. height: 100%;
  46. width: 100%;
  47. margin: 0;
  48. font-size: 1em;
  49. }
  50. body {
  51. position: relative;
  52. height: 100%;
  53. width: 100%;
  54. margin: 0;
  55. padding: 0;
  56. overflow: hidden;
  57. background-color: pink;
  58. }
  59. .hue-embedded-container {
  60. position: absolute !important;
  61. top: 60px !important;
  62. left: 60px !important;
  63. bottom: 60px !important;
  64. right: 60px !important;
  65. }
  66. </style>
  67. % endif
  68. <link href="${ static('desktop/css/roboto.css') }" rel="stylesheet">
  69. <link href="${ static('desktop/ext/css/font-awesome.min.css') }" rel="stylesheet">
  70. % if IS_EMBEDDED.get():
  71. <link href="${ static('desktop/css/hue-bootstrap-embedded.css') }" rel="stylesheet">
  72. <link href="${ static('desktop/css/hue-embedded.css') }" rel="stylesheet">
  73. % else:
  74. <link href="${ static('desktop/ext/css/cui/cui.css') }" rel="stylesheet">
  75. <link href="${ static('desktop/ext/css/cui/bootstrap2.css') }" rel="stylesheet">
  76. <link href="${ static('desktop/ext/css/cui/bootstrap-responsive2.css') }" rel="stylesheet">
  77. <link href="${ static('desktop/css/hue.css') }" rel="stylesheet">
  78. <link href="${ static('desktop/css/jquery-ui.css') }" rel="stylesheet">
  79. <link href="${ static('desktop/css/home.css') }" rel="stylesheet">
  80. % endif
  81. <script type="text/javascript">
  82. window.IS_HUE_4 = true;
  83. % if IS_EMBEDDED.get():
  84. // Bootstrap 2.3.2 relies on the hide css class presence for modals but doesn't remove it when opened for fade type
  85. // modals, a parent container might have it set to !important which will prevent the modal from showing. This
  86. // redefines all .hide definitions to exclude .modal.fade
  87. for (var i = 0; i < document.styleSheets.length; i++) {
  88. if (document.styleSheets[i] && document.styleSheets[i].cssRules) {
  89. for (var j = document.styleSheets[i].cssRules.length - 1; j > 0; j--) {
  90. if (document.styleSheets[i] && document.styleSheets[i].cssRules[j] && document.styleSheets[i].cssRules[j].selectorText === '.hide') {
  91. var originalCssText = document.styleSheets[i].cssRules[j].cssText;
  92. if (originalCssText.indexOf('!important') !== -1) {
  93. document.styleSheets[i].deleteRule(j);
  94. document.styleSheets[i].insertRule(originalCssText.replace('.hide', '.hide:not(.modal):not(.fade)'));
  95. }
  96. }
  97. }
  98. }
  99. }
  100. // Add modified URL for .clearable background
  101. var originalClearableImgUrl = '${ static('desktop/art/clearField@2x.png') }';
  102. var clearableImgUrl = typeof adaptHueEmbeddedUrls !== 'undefined' ? adaptHueEmbeddedUrls(originalClearableImgUrl) : originalClearableImgUrl;
  103. document.styleSheets[0].insertRule('.clearable { background: url(' + clearableImgUrl + ') no-repeat right -10px center; }');
  104. % endif
  105. </script>
  106. ${ commonHeaderFooterComponents.header_i18n_redirection() }
  107. <script src="/desktop/globalJsConstants.js?v=${ hue_version() }"></script>
  108. % if not conf.DEV.get():
  109. <script src="${ static('desktop/js/hue.errorcatcher.js') }"></script>
  110. % endif
  111. <script src="${ static('desktop/js/hue4.utils.js') }"></script>
  112. </head>
  113. <body>
  114. % if IS_EMBEDDED.get():
  115. <div class="hue-embedded-container">
  116. % endif
  117. % if is_demo:
  118. <ul class="side-labels unstyled">
  119. <li class="feedback"><a href="javascript:showClassicWidget()"><i class="fa fa-envelope-o"></i> ${_('Feedback')}</a></li>
  120. </ul>
  121. <!-- UserVoice JavaScript SDK -->
  122. <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>
  123. <script>
  124. UserVoice = window.UserVoice || [];
  125. function showClassicWidget() {
  126. UserVoice.push(['showLightbox', 'classic_widget', {
  127. mode: 'feedback',
  128. primary_color: '#338cb8',
  129. link_color: '#338cb8',
  130. forum_id: 247008
  131. }]);
  132. }
  133. </script>
  134. % endif
  135. <div id="jHueNotify" class="alert hide">
  136. <button class="close">&times;</button>
  137. <div class="message"></div>
  138. </div>
  139. ${ hueIcons.symbols() }
  140. <div class="main-page">
  141. % if banner_message or conf.CUSTOM.BANNER_TOP_HTML.get():
  142. <div class="banner">
  143. ${ banner_message or conf.CUSTOM.BANNER_TOP_HTML.get() | n,unicode }
  144. </div>
  145. % endif
  146. % if not IS_EMBEDDED.get():
  147. <nav class="navbar navbar-default">
  148. <div class="navbar-inner top-nav">
  149. <div class="top-nav-left">
  150. % if not IS_EMBEDDED.get():
  151. <a class="hamburger hamburger-hue pull-left" data-bind="toggle: leftNavVisible, css: { 'is-active': leftNavVisible }">
  152. <span class="hamburger-box"><span class="hamburger-inner"></span></span>
  153. </a>
  154. <a class="brand" data-bind="hueLink: '/home/'" href="javascript: void(0);" title="${_('Documents')}">
  155. <svg style="height: 24px; width: 120px;"><use xlink:href="#hi-logo"></use></svg>
  156. </a>
  157. % endif
  158. <div class="btn-group" data-bind="visible: true" style="display:none; margin-top: 8px">
  159. <!-- ko if: mainQuickCreateAction -->
  160. <!-- ko with: mainQuickCreateAction -->
  161. <a class="btn btn-primary disable-feedback hue-main-create-btn" data-bind="hueLink: url, attr: {title: tooltip}, style: { borderBottomRightRadius: $parent.quickCreateActions().length > 1 ? '0px' : '4px', borderTopRightRadius: $parent.quickCreateActions().length > 1 ? '0px' : '4px' }">
  162. <span data-bind="text: displayName"></span>
  163. </a>
  164. <!-- /ko -->
  165. <!-- /ko -->
  166. <button class="btn btn-primary dropdown-toggle hue-main-create-btn-dropdown" data-toggle="dropdown" data-bind="visible: quickCreateActions().length > 1 || (quickCreateActions().length == 1 && quickCreateActions()[0].children && quickCreateActions()[0].children.length > 1)">
  167. <!-- ko ifnot: mainQuickCreateAction -->${ _('More') } <!-- /ko -->
  168. <span class="caret"></span>
  169. </button>
  170. <ul class="dropdown-menu hue-main-create-dropdown" data-bind="foreach: { data: quickCreateActions, as: 'item' }">
  171. <!-- ko template: 'quick-create-item-template' --><!-- /ko -->
  172. </ul>
  173. </div>
  174. <script type="text/html" id="quick-create-item-template">
  175. <!-- ko if: item.dividerAbove -->
  176. <li class="divider"></li>
  177. <!-- /ko -->
  178. <li data-bind="css: { 'dropdown-submenu': item.isCategory && item.children.length > 1 }">
  179. <!-- ko if: item.url -->
  180. <a href="javascript: void(0);" data-bind="hueLink: item.url">
  181. <!-- ko if: item.icon -->
  182. <!-- ko template: { name: 'app-icon-template', data: item } --><!-- /ko -->
  183. <!-- /ko -->
  184. <span data-bind="css: { 'dropdown-no-icon': !item.icon }, text: item.displayName"></span>
  185. </a>
  186. <!-- /ko -->
  187. <!-- ko if: item.href -->
  188. <a data-bind="attr: { href: item.href }, text: item.displayName" target="_blank"></a>
  189. <!-- /ko -->
  190. <!-- ko if: item.isCategory && item.children.length > 1 -->
  191. <ul class="dropdown-menu" data-bind="foreach: { data: item.children, as: 'item' }">
  192. <!-- ko template: 'quick-create-item-template' --><!-- /ko -->
  193. </ul>
  194. <!-- /ko -->
  195. </li>
  196. </script>
  197. </div>
  198. <div class="top-nav-middle">
  199. <!-- ko if: cluster.clusters().length > 1 && cluster.clusters()[0].type() != ANALYTIC_DB -->
  200. <div class="btn-group pull-right" style="display: none;" data-bind="visible: cluster.clusters().length > 1">
  201. <button class="btn" data-bind="text: cluster.cluster().name() + (cluster.cluster().interface ? ' ' + cluster.cluster().interface() : '')"></button>
  202. <button class="btn dropdown-toggle" data-toggle="dropdown">
  203. <span class="caret"></span>
  204. </button>
  205. <ul class="dropdown-menu">
  206. <!-- ko foreach: cluster.clusters -->
  207. <!-- ko if: ['dataeng', 'cm'].indexOf(type()) != -1 && interfaces().length > 0 -->
  208. <li class="dropdown-submenu">
  209. <a data-rel="navigator-tooltip" href="javascript: void(0)">
  210. <i class="fa fa-fw fa-th-large inline-block"></i> <span data-bind="text: name"></span>
  211. </a>
  212. <ul class="dropdown-menu">
  213. <li data-bind="visible: type() == 'dataeng'">
  214. <a data-rel="navigator-tooltip" href="#">
  215. <span class="dropdown-no-icon"><i class="fa fa-fw fa-plus inline-block"></i></span>
  216. </a>
  217. </li>
  218. <!-- ko foreach: interfaces -->
  219. <li>
  220. <a href="javascript: void(0)" data-bind="click: function() { $root.cluster.cluster($data) }">
  221. <span class="dropdown-no-icon" data-bind="text: interface"></span>
  222. </a>
  223. </li>
  224. <!-- /ko -->
  225. </ul>
  226. </li>
  227. <!-- /ko -->
  228. <!-- ko if: ['dataeng', 'cm'].indexOf(type()) == -1 || interfaces().length == 0 -->
  229. <li><a href="javascript: void(0)" data-bind="click: function(){ $root.cluster.cluster($data) }">
  230. <i class="fa fa-fw fa-square"></i> <span data-bind="text: name"></span></a>
  231. </li>
  232. <!-- /ko -->
  233. <!-- /ko -->
  234. <!-- /ko -->
  235. </ul>
  236. </div>
  237. <!-- /ko -->
  238. <div class="search-container-top" data-bind="component: 'hue-global-search'"></div>
  239. </div>
  240. <div class="top-nav-right">
  241. % if user.is_authenticated() and section != 'login' and cluster != ANALYTIC_DB:
  242. <div class="dropdown navbar-dropdown pull-right">
  243. <%
  244. view_profile = user.has_hue_permission(action="access_view:useradmin:edit_user", app="useradmin") or user.is_superuser
  245. %>
  246. <button class="btn btn-flat" data-toggle="dropdown" data-bind="click: function(){ huePubSub.publish('hide.jobs.panel'); huePubSub.publish('hide.history.panel'); }">
  247. <i class="fa fa-user"></i> ${ user.username } <span class="caret"></span>
  248. </button>
  249. <ul class="dropdown-menu">
  250. % if view_profile:
  251. <li><a href="javascript:void(0)" data-bind="hueLink: '/useradmin/users/edit/${ user.username }'" title="${ _('View Profile') if is_ldap_setup else _('Edit Profile') }"><i class="fa fa-fw fa-user"></i> ${_('My Profile')}</a></li>
  252. % endif
  253. % if user.is_superuser:
  254. <li data-bind="hueLink: '/useradmin/users/'"><a href="javascript: void(0);"><i class="fa fa-fw fa-group"></i> ${_('Manage Users')}</a></li>
  255. % endif
  256. % if not conf.DISABLE_HUE_3.get():
  257. <li><a href="javascript:void(0)" onclick="huePubSub.publish('set.hue.version', 3)"><i class="fa fa-fw fa-exchange"></i> ${_('Switch to Hue 3')}</a></li>
  258. % endif
  259. <li><a href="http://gethue.com" target="_blank"><span class="dropdown-no-icon">${_('Help')}</span></a></li>
  260. <li><a href="javascript:void(0)" onclick="huePubSub.publish('show.welcome.tour')"><span class="dropdown-no-icon">${_('Welcome Tour')}</span></a></li>
  261. % if user.is_superuser:
  262. <li><a href="/about/"><span class="dropdown-no-icon">${_('Hue Administration')}</span></a></li>
  263. % endif
  264. <li class="divider"></li>
  265. <li><a title="${_('Sign out')}" href="/accounts/logout/"><i class="fa fa-fw fa-sign-out"></i> ${ _('Sign out') }</a></li>
  266. </ul>
  267. </div>
  268. % endif
  269. <!-- ko component: 'hue-history-panel' --><!-- /ko -->
  270. <!-- ko if: hasJobBrowser -->
  271. <!-- ko component: { name: 'hue-job-browser-links', params: { onePageViewModel: onePageViewModel }} --><!-- /ko -->
  272. <!-- /ko -->
  273. </div>
  274. </div>
  275. </nav>
  276. <div id="jobsPanel" class="jobs-panel" style="display: none;">
  277. <a class="pointer inactive-action pull-right" onclick="huePubSub.publish('hide.jobs.panel')"><i class="fa fa-fw fa-times"></i></a>
  278. <a class="pointer inactive-action pull-right" onclick="huePubSub.publish('mini.jb.expand'); huePubSub.publish('hide.jobs.panel')"><i class="fa fa-fw fa-expand" title="${ _('Open Job Browser') }"></i></a>
  279. <ul class="nav nav-pills">
  280. % if cluster != ANALYTIC_DB:
  281. <li class="active" data-interface="jobs"><a href="javascript:void(0)" onclick="huePubSub.publish('mini.jb.navigate', 'jobs')">${_('Jobs')}</a></li>
  282. % endif
  283. % if 'jobbrowser' in apps:
  284. <% from jobbrowser.conf import ENABLE_QUERY_BROWSER %>
  285. % if ENABLE_QUERY_BROWSER.get():
  286. <li data-interface="queries" class="${ 'active' if cluster == ANALYTIC_DB else '' }"><a href="javascript:void(0)" onclick="huePubSub.publish('mini.jb.navigate', 'queries')">${_('Queries')}</a></li>
  287. % endif
  288. % endif
  289. % if cluster != ANALYTIC_DB:
  290. <li data-interface="workflows"><a href="javascript:void(0)" onclick="huePubSub.publish('mini.jb.navigate', 'workflows')">${_('Workflows')}</a></li>
  291. <li data-interface="schedules"><a href="javascript:void(0)" onclick="huePubSub.publish('mini.jb.navigate', 'schedules')">${_('Schedules')}</a></li>
  292. % endif
  293. </ul>
  294. <div id="mini_jobbrowser"></div>
  295. </div>
  296. % endif
  297. <div class="content-wrapper">
  298. <script type="text/html" id="hue-tmpl-sidebar-link">
  299. <a role="button" class="hue-sidebar-item" data-bind="hueLink: item.url, attr: { title: item.displayName }">
  300. <span class="hue-sidebar-item-name" data-bind="text: item.displayName"></span>
  301. </a>
  302. </script>
  303. <div class="hue-sidebar hue-sidebar-below-top-bar" data-bind="visible: leftNavVisible" style="display:none;">
  304. <div class="hue-sidebar-content">
  305. <!-- ko foreach: {data: items, as: 'item'} -->
  306. <!-- ko if: item.isCategory -->
  307. <h4 class="hue-sidebar-category-item" data-bind="text: item.displayName"></h4>
  308. <!-- ko template: {name: 'hue-tmpl-sidebar-link', foreach: item.children, as: 'item'} --><!-- /ko -->
  309. <!-- /ko -->
  310. <!-- ko ifnot: item.isCategory -->
  311. <!-- ko template: { name: 'hue-tmpl-sidebar-link' } --><!-- /ko -->
  312. <!-- /ko -->
  313. <!-- /ko -->
  314. </div>
  315. <div class="hue-sidebar-footer-panel">
  316. <div data-bind="dropzone: {
  317. clickable: false,
  318. url: '/filebrowser/upload/file?dest=' + DROPZONE_HOME_DIR,
  319. params: { dest: DROPZONE_HOME_DIR },
  320. paramName: 'hdfs_file',
  321. onError: onePageViewModel.dropzoneError,
  322. onComplete: onePageViewModel.dropzoneComplete },
  323. click: function(){ page('/indexer/importer/') }" class="pointer" title="${ _('Import data wizard') }">
  324. <div class="dz-message" data-dz-message><i class="fa fa-fw fa-cloud-upload"></i> ${ _('Click or Drop files here') }</div>
  325. </div>
  326. </div>
  327. </div>
  328. <div class="left-panel" data-bind="css: { 'side-panel-closed': !leftAssistVisible() }, visibleOnHover: { selector: '.hide-left-side-panel' }">
  329. <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>
  330. <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>
  331. <div class="assist" data-bind="component: {
  332. name: 'assist-panel',
  333. params: {
  334. user: '${user.username}',
  335. sql: {
  336. navigationSettings: {
  337. openItem: false,
  338. showStats: true
  339. }
  340. },
  341. visibleAssistPanels: ['sql']
  342. }
  343. }, visible: leftAssistVisible" style="display:none;"></div>
  344. </div>
  345. <div id="leftResizer" class="resizer" data-bind="visible: leftAssistVisible(), splitFlexDraggable : {
  346. containerSelector: '.content-wrapper',
  347. sidePanelSelector: '.left-panel',
  348. sidePanelVisible: leftAssistVisible,
  349. orientation: 'left',
  350. onPosition: function() { huePubSub.publish('split.draggable.position') }
  351. }"><div class="resize-bar"></div></div>
  352. <div class="page-content">
  353. <!-- ko hueSpinner: { spin: isLoadingEmbeddable, center: true, size: 'xlarge', blackout: true } --><!-- /ko -->
  354. <div id="embeddable_editor" class="embeddable"></div>
  355. <div id="embeddable_notebook" class="embeddable"></div>
  356. <div id="embeddable_metastore" class="embeddable"></div>
  357. <div id="embeddable_dashboard" class="embeddable"></div>
  358. <div id="embeddable_oozie_workflow" class="embeddable"></div>
  359. <div id="embeddable_oozie_coordinator" class="embeddable"></div>
  360. <div id="embeddable_oozie_bundle" class="embeddable"></div>
  361. <div id="embeddable_oozie_info" class="embeddable"></div>
  362. <div id="embeddable_jobbrowser" class="embeddable"></div>
  363. <div id="embeddable_filebrowser" class="embeddable"></div>
  364. <div id="embeddable_home" class="embeddable"></div>
  365. <div id="embeddable_indexer" class="embeddable"></div>
  366. <div id="embeddable_importer" class="embeddable"></div>
  367. <div id="embeddable_collections" class="embeddable"></div>
  368. <div id="embeddable_indexes" class="embeddable"></div>
  369. <div id="embeddable_useradmin_users" class="embeddable"></div>
  370. <div id="embeddable_useradmin_groups" class="embeddable"></div>
  371. <div id="embeddable_useradmin_newgroup" class="embeddable"></div>
  372. <div id="embeddable_useradmin_editgroup" class="embeddable"></div>
  373. <div id="embeddable_useradmin_permissions" class="embeddable"></div>
  374. <div id="embeddable_useradmin_editpermission" class="embeddable"></div>
  375. <div id="embeddable_useradmin_configurations" class="embeddable"></div>
  376. <div id="embeddable_useradmin_newuser" class="embeddable"></div>
  377. <div id="embeddable_useradmin_addldapusers" class="embeddable"></div>
  378. <div id="embeddable_useradmin_addldapgroups" class="embeddable"></div>
  379. <div id="embeddable_useradmin_edituser" class="embeddable"></div>
  380. <div id="embeddable_hbase" class="embeddable"></div>
  381. <div id="embeddable_security_hive" class="embeddable"></div>
  382. <div id="embeddable_security_hdfs" class="embeddable"></div>
  383. <div id="embeddable_security_hive2" class="embeddable"></div>
  384. <div id="embeddable_security_solr" class="embeddable"></div>
  385. <div id="embeddable_help" class="embeddable"></div>
  386. <div id="embeddable_admin_wizard" class="embeddable"></div>
  387. <div id="embeddable_logs" class="embeddable"></div>
  388. <div id="embeddable_dump_config" class="embeddable"></div>
  389. <div id="embeddable_threads" class="embeddable"></div>
  390. <div id="embeddable_metrics" class="embeddable"></div>
  391. <div id="embeddable_403" class="embeddable"></div>
  392. <div id="embeddable_404" class="embeddable"></div>
  393. <div id="embeddable_500" class="embeddable"></div>
  394. <div id="embeddable_sqoop" class="embeddable"></div>
  395. <div id="embeddable_jobsub" class="embeddable"></div>
  396. % if other_apps:
  397. % for other in other_apps:
  398. <div id="embeddable_${ other.display_name }" class="embeddable"></div>
  399. % endfor
  400. % endif
  401. </div>
  402. <div id="rightResizer" class="resizer" data-bind="visible: rightAssistVisible() && rightAssistAvailable(), splitFlexDraggable : {
  403. containerSelector: '.content-wrapper',
  404. sidePanelSelector: '.right-panel',
  405. sidePanelVisible: rightAssistVisible,
  406. orientation: 'right',
  407. onPosition: function() { huePubSub.publish('split.draggable.position') }
  408. }"><div class="resize-bar" style="right: 0">&nbsp;</div></div>
  409. <div class="right-panel side-panel-closed" data-bind="visible: rightAssistAvailable, css: { 'side-panel-closed': !rightAssistVisible() || !rightAssistAvailable() }, visibleOnHover: { selector: '.hide-right-side-panel' }" style="display:none;">
  410. <a href="javascript:void(0);" style="display: none;" title="${_('Show Assist')}" class="pointer side-panel-toggle show-right-side-panel" data-bind="visible: rightAssistAvailable() && !rightAssistVisible(), toggle: rightAssistVisible"><i class="fa fa-chevron-left"></i></a>
  411. <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: rightAssistAvailable() && rightAssistVisible(), toggle: rightAssistVisible"><i class="fa fa-chevron-right"></i></a>
  412. <div class="assist" data-bind="component: {
  413. name: 'right-assist-panel',
  414. params: {
  415. rightAssistAvailable: rightAssistAvailable
  416. }
  417. }, visible: rightAssistAvailable() && rightAssistVisible()" style="display: none;">
  418. </div>
  419. </div>
  420. <div class="context-panel" data-bind="slideVisible: contextPanelVisible">
  421. <div class="margin-top-10 padding-left-10 padding-right-10">
  422. <h4 class="margin-bottom-30"><i class="fa fa-cogs"></i> ${_('Session')}</h4>
  423. <div class="context-panel-content">
  424. <!-- ko if: sessionsAvailable() && templateApp() -->
  425. <div class="row-fluid">
  426. <div class="span11" data-bind="template: { name: 'notebook-session-config-template' + templateApp(), data: activeAppViewModel }"></div>
  427. </div>
  428. <!-- /ko -->
  429. <!-- ko ifnot: sessionsAvailable() && templateApp() -->
  430. ${_('There are currently no information about the sessions.')}
  431. <!-- /ko -->
  432. </div>
  433. </div>
  434. <a class="pointer demi-modal-chevron" style="position: absolute; bottom: 0" data-bind="click: function () { huePubSub.publish('context.panel.visible.editor', false); }"><i class="fa fa-chevron-up"></i></a>
  435. </div>
  436. </div>
  437. </div>
  438. ${ commonshare() | n,unicode }
  439. <script src="${ static('desktop/js/hue-bundle.js') }"></script>
  440. % if IS_EMBEDDED.get():
  441. <script src="${ static('desktop/ext/js/page.js') }"></script>
  442. % endif
  443. <script src="${ static('desktop/js/jquery.migration.js') }"></script>
  444. <script src="${ static('desktop/js/hue.utils.js') }"></script>
  445. <script src="${ static('desktop/ext/js/bootstrap.min.js') }"></script>
  446. <script src="${ static('desktop/ext/js/tether.js') }"></script>
  447. <script src="${ static('desktop/ext/js/shepherd.min.js') }"></script>
  448. <script src="${ static('desktop/js/bootstrap-tooltip.js') }"></script>
  449. <script src="${ static('desktop/js/bootstrap-typeahead-touchscreen.js') }"></script>
  450. <script src="${ static('desktop/ext/js/bootstrap-better-typeahead.min.js') }"></script>
  451. <script src="${ static('desktop/ext/js/fileuploader.js') }"></script>
  452. <script src="${ static('desktop/ext/js/filesize.min.js') }"></script>
  453. <script src="${ static('desktop/ext/js/moment-with-locales.min.js') }"></script>
  454. <script src="${ static('desktop/ext/js/moment-timezone-with-data.min.js') }" type="text/javascript" charset="utf-8"></script>
  455. <script src="${ static('desktop/ext/js/tzdetect.js') }" type="text/javascript" charset="utf-8"></script>
  456. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.total-storage.min.js') }"></script>
  457. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.cookie.js') }"></script>
  458. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.dataTables.1.8.2.min.js') }"></script>
  459. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.form.js') }"></script>
  460. <script src="${ static('desktop/js/jquery.datatables.sorting.js') }"></script>
  461. <script src="${ static('desktop/ext/js/jquery/plugins/jquery.basictable.min.js') }"></script>
  462. <script src="${ static('desktop/ext/js/jquery/plugins/jquery-ui-1.10.4.custom.min.js') }"></script>
  463. <script src="${ static('desktop/js/jquery.nicescroll.js') }"></script>
  464. <script src="${ static('desktop/js/jquery.hiveautocomplete.js') }"></script>
  465. <script src="${ static('desktop/js/jquery.hdfsautocomplete.js') }"></script>
  466. <script src="${ static('desktop/js/jquery.filechooser.js') }"></script>
  467. <script src="${ static('desktop/js/jquery.selector.js') }"></script>
  468. <script src="${ static('desktop/js/jquery.delayedinput.js') }"></script>
  469. <script src="${ static('desktop/js/jquery.rowselector.js') }"></script>
  470. <script src="${ static('desktop/js/jquery.notify.js') }"></script>
  471. <script src="${ static('desktop/js/jquery.titleupdater.js') }"></script>
  472. <script src="${ static('desktop/js/jquery.horizontalscrollbar.js') }"></script>
  473. <script src="${ static('desktop/js/jquery.tablescroller.js') }"></script>
  474. <script src="${ static('desktop/js/jquery.tableextender.js') }"></script>
  475. % if IS_EMBEDDED.get():
  476. <script src="${ static('desktop/js/jquery.tableextender3.js') }"></script>
  477. % else:
  478. <script src="${ static('desktop/js/jquery.tableextender2.js') }"></script>
  479. % endif
  480. <script src="${ static('desktop/js/hue.colors.js') }"></script>
  481. <script src="${ static('desktop/ext/js/localforage.min.js') }"></script>
  482. <script src="${ static('desktop/js/dataCatalog.js') }"></script>
  483. <script src="${ static('desktop/js/apiHelper.js') }"></script>
  484. <script src="${ static('desktop/ext/js/knockout-sortable.min.js') }"></script>
  485. <script src="${ static('desktop/ext/js/knockout.validation.min.js') }"></script>
  486. <script src="${ static('desktop/ext/js/bootstrap-editable.min.js') }"></script>
  487. <script src="${ static('desktop/js/ko.editable.js') }"></script>
  488. <script src="${ static('desktop/js/ko.switch-case.js') }"></script>
  489. <script src="${ static('desktop/js/ko.hue-bindings.js') }"></script>
  490. <script src="${ static('desktop/js/sqlUtils.js') }"></script>
  491. <script src="${ static('desktop/js/jquery.scrollleft.js') }"></script>
  492. <script src="${ static('desktop/js/jquery.scrollup.js') }"></script>
  493. <script src="${ static('desktop/js/jquery.huedatatable.js') }"></script>
  494. <script src="${ static('desktop/js/sqlFunctions.js') }"></script>
  495. <script src="${ static('desktop/ext/js/selectize.min.js') }"></script>
  496. <script src="${ static('desktop/js/ko.selectize.js') }"></script>
  497. <script src="${ static('desktop/js/ace/ace.js') }"></script>
  498. <script src="${ static('desktop/js/ace/mode-impala.js') }"></script>
  499. <script src="${ static('desktop/js/ace/mode-hive.js') }"></script>
  500. <script src="${ static('desktop/js/ace/ext-language_tools.js') }"></script>
  501. <script src="${ static('desktop/js/ace.extended.js') }"></script>
  502. <script>
  503. ace.config.set("basePath", "/static/desktop/js/ace");
  504. </script>
  505. <script src="${ static('desktop/ext/js/dropzone.min.js') }"></script>
  506. <script src="${ static('desktop/js/autocomplete/sqlParseSupport.js') }"></script>
  507. <script src="${ static('desktop/js/autocomplete/sqlAutocompleteParser.js') }"></script>
  508. <script src="${ static('desktop/js/autocomplete/globalSearchParser.js') }"></script>
  509. <script src="${ static('desktop/js/autocomplete/solrQueryParser.js') }"></script>
  510. <script src="${ static('desktop/js/autocomplete/solrFormulaParser.js') }"></script>
  511. <script src="${ static('desktop/js/sqlAutocompleter.js') }"></script>
  512. <script src="${ static('desktop/js/sqlAutocompleter2.js') }"></script>
  513. <script src="${ static('desktop/js/sqlAutocompleter3.js') }"></script>
  514. <script src="${ static('desktop/js/hdfsAutocompleter.js') }"></script>
  515. <script src="${ static('desktop/js/autocompleter.js') }"></script>
  516. <script src="${ static('desktop/js/hue.json.js') }"></script>
  517. <script src="${ static('notebook/js/notebook.ko.js') }"></script>
  518. <script src="${ static('metastore/js/metastore.model.js') }"></script>
  519. <script src="${ static('desktop/js/share2.vm.js') }"></script>
  520. <script>
  521. var shareViewModel = initSharing("#documentShareModal");
  522. </script>
  523. <%namespace name="charting" file="/charting.mako" />
  524. <%namespace name="configKoComponents" file="/config_ko_components.mako" />
  525. <%namespace name="notebookKoComponents" file="/common_notebook_ko_components.mako" />
  526. <%namespace name="hueAceAutocompleter" file="/hue_ace_autocompleter.mako" />
  527. ${ charting.import_charts() }
  528. ${ configKoComponents.config() }
  529. ${ notebookKoComponents.aceKeyboardShortcuts() }
  530. ${ notebookKoComponents.downloadSnippetResults() }
  531. ${ hueAceAutocompleter.hueAceAutocompleter() }
  532. <script type="text/javascript">
  533. (function () {
  534. var proxiedKoRegister = ko.components.register;
  535. var registeredComponents = [];
  536. ko.components.register = function () {
  537. // This guarantees a ko component is only registered once
  538. // Some currently get registered twice when switching between notebook and editor
  539. if (registeredComponents.indexOf(arguments[0]) === -1) {
  540. registeredComponents.push(arguments[0]);
  541. return proxiedKoRegister.apply(this, arguments);
  542. }
  543. };
  544. })();
  545. </script>
  546. ${ koComponents.all() }
  547. ${ commonHeaderFooterComponents.header_pollers(user, is_s3_enabled, apps) }
  548. ## clusterConfig makes an Ajax call so it needs to be after commonHeaderFooterComponents
  549. <script src="${ static('desktop/js/clusterConfig.js') }"></script>
  550. ${ assist.assistJSModels() }
  551. ${ assist.assistPanel() }
  552. % if request is not None:
  553. ${ smart_unicode(login_modal(request).content) | n,unicode }
  554. % endif
  555. <div class="shepherd-backdrop"></div>
  556. <iframe id="zoomDetectFrame" style="width: 250px; display: none" ></iframe>
  557. <script type="text/javascript">
  558. $(document).ready(function () {
  559. var onePageViewModel = (function () {
  560. var EMBEDDABLE_PAGE_URLS = {
  561. 403: { url: '/403', title: '403' },
  562. 404: { url: '/404', title: '404' },
  563. 500: { url: '/500', title: '500' },
  564. editor: { url: '/editor', title: '${_('Editor')}' },
  565. notebook: { url: '/notebook', title: '${_('Notebook')}' },
  566. metastore: { url: '/metastore/*', title: '${_('Table Browser')}' },
  567. dashboard: { url: '/dashboard/*', title: '${_('Dashboard')}' },
  568. oozie_workflow: { url: '/oozie/editor/workflow/*', title: '${_('Workflow')}' },
  569. oozie_coordinator: { url: '/oozie/editor/coordinator/*', title: '${_('Schedule')}' },
  570. oozie_bundle: { url: '/oozie/editor/bundle/*', title: '${_('Bundle')}' },
  571. oozie_info: { url: '/oozie/list_oozie_info', title: '${_('Oozie')}' },
  572. jobbrowser: { url: '/jobbrowser/apps', title: '${_('Job Browser')}' },
  573. filebrowser: { url: '/filebrowser/view=*', title: '${_('File Browser')}' },
  574. home: { url: '/home*', title: '${_('Home')}' },
  575. indexer: { url: '/indexer/indexer/', title: '${_('Indexer')}' },
  576. collections: { url: '/dashboard/admin/collections', title: '${_('Search')}' },
  577. % if hasattr(ENABLE_NEW_INDEXER, 'get') and ENABLE_NEW_INDEXER.get():
  578. indexes: { url: '/indexer/indexes/*', title: '${_('Indexes')}' },
  579. % else:
  580. indexes: { url: '/indexer/', title: '${_('Indexes')}' },
  581. % endif
  582. importer: { url: '/indexer/importer/', title: '${_('Importer')}' },
  583. useradmin_users: { url: '/useradmin/users', title: '${_('User Admin - Users')}' },
  584. useradmin_groups: { url: '/useradmin/groups', title: '${_('User Admin - Groups')}' },
  585. useradmin_newgroup: { url: '/useradmin/groups/new', title: '${_('User Admin - New Group')}' },
  586. useradmin_editgroup: { url: '/useradmin/groups/edit/:group', title: '${_('User Admin - Edit Group')}' },
  587. useradmin_permissions: { url: '/useradmin/permissions', title: '${_('User Admin - Permissions')}' },
  588. useradmin_editpermission: { url: '/useradmin/permissions/edit/*', title: '${_('User Admin - Edit Permission')}' },
  589. useradmin_configurations: { url: '/useradmin/configurations', title: '${_('User Admin - Configurations')}' },
  590. useradmin_newuser: { url: '/useradmin/users/new', title: '${_('User Admin - New User')}' },
  591. useradmin_addldapusers: { url: '/useradmin/users/add_ldap_users', title: '${_('User Admin - Add LDAP User')}' },
  592. useradmin_edituser: { url: '/useradmin/users/edit/:user', title: '${_('User Admin - Edit User')}' },
  593. useradmin_addldapgroups: { url: '/useradmin/users/add_ldap_groups', title: '${_('User Admin - Add LDAP Groups')}' },
  594. hbase: { url: '/hbase/', title: '${_('HBase Browser')}' },
  595. security_hive: { url: '/security/hive', title: '${_('Security - Hive')}' },
  596. security_hdfs: { url: '/security/hdfs', title: '${_('Security - HDFS')}' },
  597. security_hive2: { url: '/security/hive2', title: '${_('Security - Hive')}' },
  598. security_solr: { url: '/security/solr', title: '${_('Security - SOLR')}' },
  599. help: { url: '/help/', title: '${_('Help')}' },
  600. admin_wizard: { url: '/about/admin_wizard', title: '${_('Admin Wizard')}' },
  601. logs: { url: '/logs', title: '${_('Logs')}' },
  602. dump_config: { url: '/desktop/dump_config', title: '${_('Dump Configuration')}' },
  603. threads: { url: '/desktop/debug/threads', title: '${_('Threads')}' },
  604. metrics: { url: '/desktop/metrics', title: '${_('Metrics')}' },
  605. sqoop: { url: '/sqoop', title: '${_('Sqoop')}' },
  606. jobsub: { url: '/jobsub/not_available', title: '${_('Job Designer')}' },
  607. % if other_apps:
  608. % for other in other_apps:
  609. ${ other.display_name }: { url: '/${ other.display_name }', title: '${ other.nice_name }' },
  610. % endfor
  611. % endif
  612. };
  613. var SKIP_CACHE = [
  614. 'home', 'oozie_workflow', 'oozie_coordinator', 'oozie_bundle', 'dashboard', 'metastore',
  615. 'filebrowser', 'useradmin_users', 'useradmin_groups', 'useradmin_newgroup', 'useradmin_editgroup',
  616. 'useradmin_permissions', 'useradmin_editpermission', 'useradmin_configurations', 'useradmin_newuser',
  617. 'useradmin_addldapusers', 'useradmin_addldapgroups', 'useradmin_edituser', 'importer',
  618. 'security_hive', 'security_hdfs', 'security_hive2', 'security_solr', 'logs',
  619. % if hasattr(ENABLE_NEW_INDEXER, 'get') and ENABLE_NEW_INDEXER.get():
  620. 'indexes',
  621. % endif
  622. % if other_apps:
  623. % for other in other_apps:
  624. '${ other.display_name }',
  625. % endfor
  626. % endif
  627. ];
  628. var OnePageViewModel = function () {
  629. var self = this;
  630. self.embeddable_cache = {};
  631. self.currentApp = ko.observable();
  632. self.currentContextParams = ko.observable(null);
  633. self.currentQueryString = ko.observable(null);
  634. self.isLoadingEmbeddable = ko.observable(false);
  635. self.extraEmbeddableURLParams = ko.observable('');
  636. self.getActiveAppViewModel = function (callback) {
  637. var checkInterval = window.setInterval(function () {
  638. var $koElement = $('#' + self.currentApp() + 'Components');
  639. if ($koElement.length > 0 && ko.dataFor($koElement[0])) {
  640. window.clearInterval(checkInterval);
  641. callback(ko.dataFor($koElement[0]));
  642. }
  643. }, 25);
  644. };
  645. self.changeEditorType = function (type) {
  646. self.getActiveAppViewModel(function (viewModel) {
  647. if (viewModel && viewModel.selectedNotebook) {
  648. hueUtils.waitForObservable(viewModel.selectedNotebook, function(){
  649. if (viewModel.editorType() !== type) {
  650. viewModel.selectedNotebook().selectedSnippet(type);
  651. viewModel.editorType(type);
  652. viewModel.newNotebook(type);
  653. }
  654. });
  655. }
  656. })
  657. };
  658. self.currentApp.subscribe(function (newApp) {
  659. huePubSub.publish('set.current.app.name', newApp);
  660. self.getActiveAppViewModel(function (viewModel) {
  661. huePubSub.publish('set.current.app.view.model', viewModel);
  662. })
  663. });
  664. huePubSub.subscribe('get.current.app.view.model', function () {
  665. self.getActiveAppViewModel(function (viewModel) {
  666. huePubSub.publish('set.current.app.view.model', viewModel);
  667. })
  668. });
  669. huePubSub.subscribe('get.current.app.name', function () {
  670. huePubSub.publish('set.current.app.name', self.currentApp());
  671. });
  672. huePubSub.subscribe('open.editor.query', function (uuid) {
  673. self.loadApp('editor');
  674. self.getActiveAppViewModel(function (viewModel) {
  675. viewModel.openNotebook(uuid);
  676. })
  677. });
  678. huePubSub.subscribe('resize.form.actions', function () {
  679. document.styleSheets[0].addRule('.form-actions','width: ' + $('.page-content').width() + 'px');
  680. if ($('.content-panel:visible').length > 0) {
  681. document.styleSheets[0].addRule('.form-actions','margin-left: -11px !important');
  682. }
  683. });
  684. huePubSub.subscribe('split.panel.resized', function() {
  685. huePubSub.publish('resize.form.actions');
  686. huePubSub.publish('resize.plotly.chart');
  687. });
  688. huePubSub.publish('resize.form.actions');
  689. huePubSub.subscribe('open.editor.new.query', function (statementOptions) {
  690. self.loadApp('editor'); // Should open in Default
  691. self.getActiveAppViewModel(function (viewModel) {
  692. var editorType = statementOptions['type'] || 'hive'; // Next: use file extensions and default type of Editor for SQL
  693. viewModel.newNotebook(editorType, function() {
  694. self.changeEditorType(editorType);
  695. if (statementOptions['statementPath']) {
  696. viewModel.selectedNotebook().snippets()[0].statementType(statementOptions['statementType']);
  697. viewModel.selectedNotebook().snippets()[0].statementPath(statementOptions['statementPath']);
  698. }
  699. if (statementOptions['directoryUuid']) {
  700. viewModel.selectedNotebook().directoryUuid(statementOptions['directoryUuid']);
  701. }
  702. });
  703. })
  704. });
  705. var loadedJs = [];
  706. var loadedCss = [];
  707. var loadedApps = [];
  708. var head = document.getElementsByTagName('head')[0];
  709. $('script[src]').each(function(){
  710. loadedJs.push($(this).attr('src'));
  711. });
  712. $('link[href]').each(function(){
  713. loadedCss.push($(this).attr('href'));
  714. });
  715. var loadScriptsSync = function (scriptUrls, promise) {
  716. if (scriptUrls.length) {
  717. var scriptUrl = typeof adaptHueEmbeddedUrls !== 'undefined' ? adaptHueEmbeddedUrls(scriptUrls.shift()) : scriptUrls.shift();
  718. if (loadedJs.indexOf(scriptUrl) !== -1) {
  719. loadScriptsSync(scriptUrls, promise);
  720. return;
  721. }
  722. var scriptElement = document.createElement('script');
  723. % if conf.DEV.get():
  724. scriptElement.src = scriptUrl + '?dev=' + Math.random();
  725. % else:
  726. scriptElement.src = scriptUrl;
  727. % endif
  728. scriptElement.type = 'text/javascript';
  729. scriptElement.onload = function () {
  730. loadedJs.push(scriptUrl);
  731. loadScriptsSync(scriptUrls, promise);
  732. };
  733. scriptElement.onerror = function () {
  734. loadScriptsSync(scriptUrls, promise);
  735. };
  736. // Legacy IE not happy with onload
  737. scriptElement.onreadystatechange = function() {
  738. if (this.readyState === 'complete') {
  739. loadedJs.push(scriptUrl);
  740. loadScriptsSync(scriptUrls, promise);
  741. }
  742. };
  743. head.appendChild(scriptElement);
  744. } else {
  745. promise.resolve();
  746. }
  747. };
  748. var addGlobalCss = function ($el) {
  749. var cssFile = $el.attr('href').split('?')[0];
  750. if (loadedCss.indexOf(cssFile) === -1) {
  751. loadedCss.push(cssFile);
  752. $.ajaxSetup({ cache: true });
  753. if (typeof adaptHueEmbeddedUrls !== 'undefined') {
  754. $el.attr('href', adaptHueEmbeddedUrls($el.attr('href')));
  755. }
  756. % if conf.DEV.get():
  757. $el.attr('href', $el.attr('href') + '?dev=' + Math.random());
  758. % endif
  759. $el.clone().appendTo($('head'));
  760. $.ajaxSetup({ cache: false });
  761. }
  762. $el.remove();
  763. };
  764. // Only load CSS and JS files that are not loaded before
  765. self.processHeaders = function (response){
  766. var promise = $.Deferred();
  767. var $rawHtml = $('<span>').html(response);
  768. var $allScripts = $rawHtml.find('script[src]');
  769. var scriptsToLoad = $allScripts.map(function () {
  770. return $(this).attr('src');
  771. }).toArray();
  772. $allScripts.remove();
  773. var scriptsPromise = $.Deferred();
  774. loadScriptsSync(scriptsToLoad, scriptsPromise);
  775. $rawHtml.find('link[href]').each(function () {
  776. addGlobalCss($(this)); // Also removes the elements;
  777. });
  778. $rawHtml.find('a[href]').each(function () {
  779. var link = $(this).attr('href');
  780. if (link.startsWith('/') && !link.startsWith('/hue')){
  781. link = '/hue' + link;
  782. }
  783. $(this).attr('href', link);
  784. });
  785. if (typeof adaptHueEmbeddedUrls !== 'undefined') {
  786. $rawHtml.find('img[src]').each(function () {
  787. var $img = $(this);
  788. $img.attr('src', adaptHueEmbeddedUrls($img.attr('src')));
  789. })
  790. }
  791. $rawHtml.unwrap('<span>');
  792. scriptsPromise.done(function () {
  793. promise.resolve($rawHtml);
  794. });
  795. return promise;
  796. };
  797. huePubSub.subscribe('hue4.process.headers', function(opts){
  798. self.processHeaders(opts.response).done(function (rawHtml) {
  799. opts.callback(rawHtml);
  800. });
  801. });
  802. self.loadApp = function(app, loadDeep) {
  803. if (self.currentApp() == 'editor' && $('#editorComponents').length) {
  804. var vm = ko.dataFor($('#editorComponents')[0]);
  805. if (vm.isPresentationMode()) {
  806. vm.selectedNotebook().isPresentationMode(false);
  807. }
  808. }
  809. self.currentApp(app);
  810. if (!app.startsWith('security')) {
  811. self.lastContext = null;
  812. }
  813. SKIP_CACHE.forEach(function (skipped) {
  814. $('#embeddable_' + skipped).html('');
  815. });
  816. self.isLoadingEmbeddable(true);
  817. loadedApps.forEach(function (loadedApp) {
  818. window.pauseAppIntervals(loadedApp);
  819. huePubSub.pauseAppSubscribers(loadedApp);
  820. });
  821. $('.tooltip').hide();
  822. huePubSub.publish('hue.datatable.search.hide');
  823. huePubSub.publish('nicescroll.resize');
  824. huePubSub.publish('hue.scrollleft.hide');
  825. huePubSub.publish('context.panel.visible', false);
  826. huePubSub.publish('context.panel.visible.editor', false);
  827. if (app === 'filebrowser') {
  828. $(window).unbind('hashchange.fblist');
  829. }
  830. if (app.startsWith('oozie')) {
  831. huePubSub.clearAppSubscribers('oozie');
  832. }
  833. if (app.startsWith('security')) {
  834. $('#embeddable_security_hive').html('');
  835. $('#embeddable_security_hdfs').html('');
  836. $('#embeddable_security_hive2').html('');
  837. $('#embeddable_security_solr').html('');
  838. }
  839. if (typeof self.embeddable_cache[app] === 'undefined') {
  840. if (loadedApps.indexOf(app) == -1){
  841. loadedApps.push(app);
  842. }
  843. var baseURL = EMBEDDABLE_PAGE_URLS[app].url;
  844. if (self.currentContextParams() !== null) {
  845. if (loadDeep && self.currentContextParams()[0]) {
  846. baseURL += self.currentContextParams()[0];
  847. }
  848. else {
  849. var route = new page.Route(baseURL);
  850. route.keys.forEach(function (key) {
  851. if (key.name === 0) {
  852. if (typeof self.currentContextParams()[key.name] !== 'undefined') {
  853. baseURL = baseURL.replace('*', self.currentContextParams()[key.name]);
  854. }
  855. else {
  856. baseURL = baseURL.replace('*', '');
  857. }
  858. }
  859. else {
  860. baseURL = baseURL.replace(':' + key.name, self.currentContextParams()[key.name]);
  861. }
  862. });
  863. }
  864. self.currentContextParams(null);
  865. }
  866. if (self.currentQueryString() !== null) {
  867. baseURL += (baseURL.indexOf('?') > -1 ? '&' : '?') + self.currentQueryString();
  868. self.currentQueryString(null);
  869. }
  870. $.ajax({
  871. url: baseURL + (baseURL.indexOf('?') > -1 ? '&' : '?') +'is_embeddable=true' + self.extraEmbeddableURLParams(),
  872. beforeSend: function (xhr) {
  873. xhr.setRequestHeader('X-Requested-With', 'Hue');
  874. },
  875. dataType: 'html',
  876. success: function(response, status, xhr){
  877. var type = xhr.getResponseHeader('Content-Type');
  878. if (type.indexOf('text/') > -1) {
  879. window.clearAppIntervals(app);
  880. huePubSub.clearAppSubscribers(app);
  881. self.extraEmbeddableURLParams('');
  882. self.processHeaders(response).done(function ($rawHtml) {
  883. if (SKIP_CACHE.indexOf(app) === -1) {
  884. self.embeddable_cache[app] = $rawHtml;
  885. }
  886. $('#embeddable_' + app).html($rawHtml);
  887. huePubSub.publish('app.dom.loaded', app);
  888. self.isLoadingEmbeddable(false);
  889. });
  890. } else {
  891. window.location.href = baseURL;
  892. }
  893. },
  894. error: function (xhr) {
  895. console.error('Route loading problem', xhr);
  896. if ((xhr.status === 401 || xhr.status === 403) && app !== '403') {
  897. self.loadApp('403');
  898. }
  899. else if (app !== '500') {
  900. self.loadApp('500');
  901. }
  902. else {
  903. $.jHueNotify.error("${ _('It looks like you are offline or an unknown error happened. Please refresh the page.') }")
  904. }
  905. }
  906. });
  907. } else {
  908. self.isLoadingEmbeddable(false);
  909. }
  910. window.document.title = 'Hue - ' + EMBEDDABLE_PAGE_URLS[app].title;
  911. window.resumeAppIntervals(app);
  912. huePubSub.resumeAppSubscribers(app);
  913. $('.embeddable').hide();
  914. $('#embeddable_' + app).show();
  915. huePubSub.publish('app.gained.focus', app);
  916. huePubSub.publish('resize.form.actions');
  917. };
  918. self.dropzoneError = function (filename) {
  919. self.loadApp('importer');
  920. self.getActiveAppViewModel(function (vm) {
  921. vm.createWizard.source.path(DROPZONE_HOME_DIR + '/' + filename);
  922. });
  923. $('.dz-drag-hover').removeClass('dz-drag-hover');
  924. };
  925. var openImporter = function (path) {
  926. self.loadApp('importer');
  927. self.getActiveAppViewModel(function (vm) {
  928. vm.createWizard.source.path(path);
  929. });
  930. };
  931. self.dropzoneComplete = function (path) {
  932. if (path.toLowerCase().endsWith('.csv')){
  933. openImporter(path);
  934. }
  935. else {
  936. huePubSub.publish('open.link', '/filebrowser/view=' + path);
  937. }
  938. $('.dz-drag-hover').removeClass('dz-drag-hover');
  939. };
  940. huePubSub.subscribe('open.in.importer', openImporter);
  941. // prepend /hue to all the link on this page
  942. $('${ '.hue-embedded-container a[href]' if IS_EMBEDDED.get() else 'a[href]' }').each(function () {
  943. var link = $(this).attr('href');
  944. if (link.startsWith('/') && !link.startsWith('/hue')){
  945. link = '/hue' + link;
  946. }
  947. $(this).attr('href', link);
  948. });
  949. % if IS_EMBEDDED.get():
  950. page.base(window.location.pathname);
  951. page({ hashbang: true });
  952. if (!window.location.hash) {
  953. window.location.hash = '#!'
  954. }
  955. % else:
  956. page.base('/hue');
  957. % endif
  958. var getUrlParameter = function (name) {
  959. % if IS_EMBEDDED.get():
  960. if (~window.location.hash.indexOf('?')) {
  961. var paramString = window.location.hash.substring(window.location.hash.indexOf('?'));
  962. var params = paramString.split('&');
  963. for (var i = 0; i < params.length; i++) {
  964. if (~params[i].indexOf(name + '=')) {
  965. return params[i].substring(name.length + 2);
  966. }
  967. }
  968. }
  969. return '';
  970. % else:
  971. return window.location.getParameter(name) || '';
  972. % endif
  973. };
  974. self.lastContext = null;
  975. var pageMapping = [
  976. { url: '/403', app: '403' },
  977. { url: '/500', app: '500' },
  978. { url: '/about/', app: 'admin_wizard' },
  979. { url: '/about/admin_wizard', app: 'admin_wizard' },
  980. { url: '/accounts/logout', app: function () {
  981. location.href = '/accounts/logout';
  982. }},
  983. { url: '/dashboard/admin/collections', app: function (ctx) {
  984. page('/home/?type=search-dashboard');
  985. }},
  986. { url: '/dashboard/*', app: 'dashboard' },
  987. { url: '/desktop/dump_config', app: 'dump_config' },
  988. { url: '/desktop/debug/threads', app: function () {
  989. self.loadApp('threads');
  990. self.getActiveAppViewModel(function (viewModel) {
  991. viewModel.fetchThreads();
  992. });
  993. }},
  994. { url: '/desktop/metrics', app: function () {
  995. self.loadApp('metrics');
  996. self.getActiveAppViewModel(function (viewModel) {
  997. viewModel.fetchMetrics();
  998. });
  999. }},
  1000. { url: '/desktop/download_logs', app: function () {
  1001. location.href = '/desktop/download_logs';
  1002. }},
  1003. { url: '/editor', app: function () {
  1004. // Defer to allow window.location param update
  1005. _.defer(function () {
  1006. if (typeof self.embeddable_cache['editor'] === 'undefined'){
  1007. if (getUrlParameter('editor') !== '') {
  1008. self.extraEmbeddableURLParams('&editor=' + getUrlParameter('editor'));
  1009. } else if (getUrlParameter('type') !== '' && getUrlParameter('type') !== 'notebook') {
  1010. self.extraEmbeddableURLParams('&type=' + getUrlParameter('type'));
  1011. }
  1012. self.loadApp('editor');
  1013. } else {
  1014. self.loadApp('editor');
  1015. if (getUrlParameter('editor') !== '') {
  1016. self.getActiveAppViewModel(function (viewModel) {
  1017. self.isLoadingEmbeddable(true);
  1018. viewModel.openNotebook(getUrlParameter('editor')).always(function () {
  1019. self.isLoadingEmbeddable(false);
  1020. });
  1021. });
  1022. } else if (getUrlParameter('type') !== '') {
  1023. self.changeEditorType(getUrlParameter('type'));
  1024. }
  1025. }
  1026. });
  1027. }},
  1028. { url: '/notebook/editor', app: function (ctx) {
  1029. page('/editor?' + ctx.querystring);
  1030. }},
  1031. { url: '/filebrowser/view=*', app: 'filebrowser' },
  1032. { url: '/filebrowser/download=*', app: 'filebrowser' },
  1033. { url: '/filebrowser/*', app: function () {
  1034. page('/filebrowser/view=' + DROPZONE_HOME_DIR);
  1035. }},
  1036. { url: '/hbase/', app: 'hbase' },
  1037. { url: '/help', app: 'help' },
  1038. { url: '/home2*', app: function (ctx) {
  1039. page(ctx.path.replace(/home2/gi, 'home'));
  1040. }},
  1041. { url: '/home*', app: 'home' },
  1042. { url: '/indexer/indexes/*', app: 'indexes' },
  1043. { url: '/indexer/', app: 'indexes' },
  1044. { url: '/indexer/importer/', app: 'importer' },
  1045. { url: '/indexer/importer/prefill/*', app: function (ctx) {
  1046. self.loadApp('importer');
  1047. self.getActiveAppViewModel(function (viewModel) {
  1048. var _params = ctx.path.match(/\/indexer\/importer\/prefill\/?([^/]+)\/?([^/]+)\/?([^/]+)?/);
  1049. if (! _params) {
  1050. console.warn('Could not match ' + href);
  1051. }
  1052. hueUtils.waitForVariable(viewModel.createWizard, function(){
  1053. hueUtils.waitForVariable(viewModel.createWizard.prefill, function(){
  1054. viewModel.createWizard.prefill.source_type(_params && _params[1] ? _params[1] : '');
  1055. viewModel.createWizard.prefill.target_type(_params && _params[2] ? _params[2] : '');
  1056. viewModel.createWizard.prefill.target_path(_params && _params[3] ? _params[3] : '');
  1057. });
  1058. });
  1059. })
  1060. }},
  1061. { url: '/jobbrowser/jobs/job_*', app: function (ctx) {
  1062. page.redirect('/jobbrowser#!id=application_' + _.trimRight(ctx.params[0], '/').split('/')[0]);
  1063. }},
  1064. { url: '/jobbrowser/jobs/application_*', app: function (ctx) {
  1065. page.redirect('/jobbrowser#!id=application_' + _.trimRight(ctx.params[0], '/').split('/')[0]);
  1066. }},
  1067. { url: '/jobbrowser*', app: 'jobbrowser'},
  1068. { url: '/logs', app: 'logs' },
  1069. { url: '/metastore', app: function () {
  1070. page('/metastore/tables');
  1071. }},
  1072. { url: '/metastore/*', app: 'metastore' },
  1073. { url: '/notebook', app: function (ctx) {
  1074. self.loadApp('notebook');
  1075. var notebookId = hueUtils.getSearchParameter('?' + ctx.querystring, 'notebook');
  1076. if (notebookId !== '') {
  1077. self.getActiveAppViewModel(function (viewModel) {
  1078. self.isLoadingEmbeddable(true);
  1079. viewModel.openNotebook(notebookId).always(function () {
  1080. self.isLoadingEmbeddable(false);
  1081. });
  1082. });
  1083. } else {
  1084. self.getActiveAppViewModel(function (viewModel) {
  1085. viewModel.newNotebook('notebook');
  1086. });
  1087. }
  1088. }},
  1089. { url: '/notebook/notebook', app: function (ctx) {
  1090. page('/notebook?' + ctx.querystring);
  1091. }},
  1092. { url: '/notebook/notebooks', app: function (ctx) {
  1093. page('/home/?' + ctx.querystring);
  1094. }},
  1095. { url: '/oozie/editor/bundle/list', app: function (ctx) {
  1096. page('/home/?type=oozie-bundle');
  1097. }},
  1098. { url: '/oozie/editor/bundle/*', app: 'oozie_bundle' },
  1099. { url: '/oozie/editor/coordinator/list', app: function (ctx) {
  1100. page('/home/?type=oozie-coordinator');
  1101. }},
  1102. { url: '/oozie/editor/coordinator/*', app: 'oozie_coordinator' },
  1103. { url: '/oozie/editor/workflow/list', app: function (ctx) {
  1104. page('/home/?type=oozie-workflow');
  1105. }},
  1106. { url: '/oozie/editor/workflow/*', app: 'oozie_workflow' },
  1107. { url: '/oozie/list_oozie_info', app: 'oozie_info' },
  1108. { url: '/oozie/list_oozie_sla', app: function() {
  1109. page.redirect('/jobbrowser/#!slas');
  1110. }},
  1111. { url: '/pig', app: function () {
  1112. self.loadApp('editor');
  1113. self.changeEditorType('pig');
  1114. }},
  1115. { url: '/search/*', app: 'dashboard' },
  1116. { url: '/security/hdfs', app: function (ctx) {
  1117. if (self.lastContext == null || ctx.path !== self.lastContext.path) {
  1118. self.loadApp('security_hdfs');
  1119. }
  1120. self.lastContext = ctx;
  1121. }},
  1122. { url: '/security/hive', app: function (ctx) {
  1123. if (self.lastContext == null || ctx.path !== self.lastContext.path) {
  1124. self.loadApp('security_hive');
  1125. }
  1126. self.lastContext = ctx;
  1127. }},
  1128. { url: '/security/hive2', app: function (ctx) {
  1129. if (self.lastContext == null || ctx.path !== self.lastContext.path) {
  1130. self.loadApp('security_hive2');
  1131. }
  1132. self.lastContext = ctx;
  1133. }},
  1134. { url: '/security/solr', app: function (ctx) {
  1135. if (self.lastContext == null || ctx.path !== self.lastContext.path) {
  1136. self.loadApp('security_solr');
  1137. }
  1138. self.lastContext = ctx;
  1139. }},
  1140. { url: '/security', app: function () {
  1141. page('/security/hive');
  1142. }},
  1143. { url: '/sqoop', app: 'sqoop' },
  1144. { url: '/jobsub', app: 'jobsub' },
  1145. { url: '/useradmin/configurations/', app: 'useradmin_configurations' },
  1146. { url: '/useradmin/groups/', app: 'useradmin_groups' },
  1147. { url: '/useradmin/groups/new', app: 'useradmin_newgroup' },
  1148. { url: '/useradmin/groups/edit/:group', app: 'useradmin_editgroup' },
  1149. { url: '/useradmin/permissions/', app: 'useradmin_permissions' },
  1150. { url: '/useradmin/permissions/edit/*', app: 'useradmin_editpermission' },
  1151. { url: '/useradmin/users/', app: 'useradmin_users' },
  1152. { url: '/useradmin/users/add_ldap_users', app: 'useradmin_addldapusers' },
  1153. { url: '/useradmin/users/add_ldap_groups', app: 'useradmin_addldapgroups' },
  1154. { url: '/useradmin/users/edit/:user', app: 'useradmin_edituser' },
  1155. { url: '/useradmin/users/new', app: 'useradmin_newuser' },
  1156. { url: '/useradmin/users/', app: 'useradmin_users' },
  1157. { url: '/useradmin', app: 'useradmin_users' },
  1158. % if other_apps:
  1159. % for other in other_apps:
  1160. { url: '/${ other.display_name }*', app: function (ctx) {
  1161. self.currentContextParams(ctx.params);
  1162. self.currentQueryString(ctx.querystring);
  1163. self.loadApp('${ other.display_name }', true)
  1164. }}
  1165. % endfor
  1166. % endif
  1167. ];
  1168. if (typeof HUE_EMBEDDED_PAGE_MAPPINGS !== 'undefined') {
  1169. pageMapping = pageMapping.concat(HUE_EMBEDDED_PAGE_MAPPINGS)
  1170. }
  1171. pageMapping.forEach(function (mapping) {
  1172. page(mapping.url, _.isFunction(mapping.app) ? mapping.app : function (ctx) {
  1173. self.currentContextParams(ctx.params);
  1174. self.currentQueryString(ctx.querystring);
  1175. self.loadApp(mapping.app);
  1176. })
  1177. });
  1178. huePubSub.subscribe('cluster.config.set.config', function (clusterConfig) {
  1179. page('/', function() { page(clusterConfig['main_button_action'].page); });
  1180. page('*', function (ctx) {
  1181. console.error('Route not found', ctx);
  1182. self.loadApp('404');
  1183. });
  1184. page();
  1185. });
  1186. huePubSub.subscribe('open.link', function (href) {
  1187. if (href) {
  1188. var prefix = '${ '' if IS_EMBEDDED.get() else '/hue' }';
  1189. if (href.startsWith('/') && !href.startsWith(prefix)){
  1190. page(prefix + href);
  1191. } else {
  1192. page(href);
  1193. }
  1194. } else {
  1195. console.warn('Received an open.link without href.')
  1196. }
  1197. });
  1198. };
  1199. var onePageViewModel = new OnePageViewModel();
  1200. ko.applyBindings(onePageViewModel, $('.page-content')[0]);
  1201. return onePageViewModel;
  1202. })();
  1203. var sidePanelViewModel = (function () {
  1204. function SidePanelViewModel () {
  1205. var self = this;
  1206. self.apiHelper = ApiHelper.getInstance();
  1207. self.assistWithoutStorage = ko.observable(false);
  1208. self.leftAssistVisible = ko.observable(self.apiHelper.getFromTotalStorage('assist', 'left_assist_panel_visible', true));
  1209. self.leftAssistVisible.subscribe(function (val) {
  1210. if (!self.assistWithoutStorage()){
  1211. self.apiHelper.setInTotalStorage('assist', 'left_assist_panel_visible', val);
  1212. }
  1213. hueAnalytics.convert('hue', 'leftAssistVisible/' + val);
  1214. window.setTimeout(function () {
  1215. huePubSub.publish('split.panel.resized');
  1216. $(window).trigger('resize');
  1217. }, 0);
  1218. });
  1219. self.rightAssistVisible = ko.observable(self.apiHelper.getFromTotalStorage('assist', 'right_assist_panel_visible', true));
  1220. self.rightAssistVisible.subscribe(function (val) {
  1221. if (!self.assistWithoutStorage()){
  1222. self.apiHelper.setInTotalStorage('assist', 'right_assist_panel_visible', val);
  1223. }
  1224. hueAnalytics.convert('hue', 'rightAssistVisible/' + val)
  1225. window.setTimeout(function () {
  1226. huePubSub.publish('reposition.scroll.anchor.up');
  1227. huePubSub.publish('nicescroll.resize');
  1228. huePubSub.publish('split.panel.resized');
  1229. $(window).trigger('resize');
  1230. }, 0);
  1231. });
  1232. self.rightAssistAvailable = ko.observable(false);
  1233. huePubSub.subscribe('assist.highlight.risk.suggestions', function () {
  1234. if (self.rightAssistAvailable() && !self.rightAssistVisible()) {
  1235. self.rightAssistVisible(true);
  1236. }
  1237. });
  1238. self.activeAppViewModel = ko.observable();
  1239. self.currentApp = ko.observable('');
  1240. self.templateApp = ko.pureComputed(function(){
  1241. if (['editor', 'notebook'].indexOf(self.currentApp()) > -1){
  1242. return self.currentApp()
  1243. }
  1244. else {
  1245. return '';
  1246. }
  1247. });
  1248. self.contextPanelVisible = ko.observable(false);
  1249. self.contextPanelVisible.subscribe(function () {
  1250. var $el = $('.snippet .ace-editor:visible');
  1251. if ($el.length === 0) {
  1252. $el = $('.content-panel:visible');
  1253. }
  1254. $('.context-panel').width($el.width()).css('left', $el.offset().left);
  1255. });
  1256. self.sessionsAvailable = ko.observable(false);
  1257. self.activeAppViewModel.subscribe(function (viewModel) {
  1258. self.sessionsAvailable(typeof viewModel.selectedNotebook !== 'undefined');
  1259. });
  1260. huePubSub.subscribe('context.panel.visible', function (visible) {
  1261. self.contextPanelVisible(visible);
  1262. });
  1263. huePubSub.subscribe('set.current.app.view.model', self.activeAppViewModel);
  1264. huePubSub.subscribe('app.dom.loaded', self.currentApp);
  1265. huePubSub.publish('get.current.app.view.model');
  1266. var previousVisibilityValues = {};
  1267. huePubSub.subscribe('side.panels.hide', function(withoutStorage){
  1268. previousVisibilityValues = {
  1269. left: self.leftAssistVisible(),
  1270. right: self.rightAssistVisible()
  1271. };
  1272. self.assistWithoutStorage(withoutStorage);
  1273. self.leftAssistVisible(false);
  1274. self.rightAssistVisible(false);
  1275. window.setTimeout(function(){
  1276. self.assistWithoutStorage(false);
  1277. }, 0);
  1278. });
  1279. huePubSub.subscribe('side.panel.right.hide', function(withoutStorage){
  1280. previousVisibilityValues = {
  1281. left: self.leftAssistVisible(),
  1282. right: self.rightAssistVisible()
  1283. };
  1284. self.assistWithoutStorage(withoutStorage);
  1285. self.rightAssistVisible(false);
  1286. window.setTimeout(function(){
  1287. self.assistWithoutStorage(false);
  1288. }, 0);
  1289. });
  1290. huePubSub.subscribe('side.panels.show', function(withoutStorage){
  1291. self.assistWithoutStorage(withoutStorage);
  1292. self.leftAssistVisible(previousVisibilityValues.left);
  1293. self.rightAssistVisible(previousVisibilityValues.right);
  1294. window.setTimeout(function(){
  1295. self.assistWithoutStorage(false);
  1296. }, 0);
  1297. });
  1298. huePubSub.subscribe('left.assist.show', function () {
  1299. if (!self.leftAssistVisible()) {
  1300. self.leftAssistVisible(true);
  1301. }
  1302. })
  1303. }
  1304. var sidePanelViewModel = new SidePanelViewModel();
  1305. ko.applyBindings(sidePanelViewModel, $('.left-panel')[0]);
  1306. ko.applyBindings(sidePanelViewModel, $('#leftResizer')[0]);
  1307. ko.applyBindings(sidePanelViewModel, $('#rightResizer')[0]);
  1308. ko.applyBindings(sidePanelViewModel, $('.right-panel')[0]);
  1309. ko.applyBindings(sidePanelViewModel, $('.context-panel')[0]);
  1310. return sidePanelViewModel;
  1311. })();
  1312. var topNavViewModel = (function (onePageViewModel) {
  1313. function TopNavViewModel (onePageViewModel) {
  1314. var self = this;
  1315. self.onePageViewModel = onePageViewModel;
  1316. self.leftNavVisible = ko.observable(false);
  1317. self.leftNavVisible.subscribe(function (val) {
  1318. huePubSub.publish('left.nav.open.toggle', val);
  1319. hueAnalytics.convert('hue', 'leftNavVisible/' + val);
  1320. if (val) {
  1321. // Defer or it will be triggered by the open click
  1322. window.setTimeout(function () {
  1323. $(document).one('click', function () {
  1324. if (self.leftNavVisible()) {
  1325. self.leftNavVisible(false);
  1326. }
  1327. })
  1328. }, 0);
  1329. }
  1330. });
  1331. self.onePageViewModel.currentApp.subscribe(function () {
  1332. self.leftNavVisible(false);
  1333. });
  1334. self.mainQuickCreateAction = ko.observable();
  1335. self.quickCreateActions = ko.observableArray();
  1336. self.hasJobBrowser = ko.observable(true);
  1337. huePubSub.subscribe('cluster.config.set.config', function (clusterConfig) {
  1338. if (clusterConfig && clusterConfig['main_button_action']) {
  1339. var topApp = clusterConfig['main_button_action'];
  1340. self.mainQuickCreateAction({
  1341. displayName: topApp.buttonName,
  1342. icon: topApp.type,
  1343. tooltip: topApp.tooltip,
  1344. url: topApp.page
  1345. });
  1346. } else {
  1347. self.mainQuickCreateAction(undefined);
  1348. }
  1349. if (clusterConfig && clusterConfig['button_actions']) {
  1350. var apps = [];
  1351. var buttonActions = clusterConfig['button_actions'];
  1352. buttonActions.forEach(function(app) {
  1353. var interpreters = [];
  1354. var toAddDivider = false;
  1355. var dividerAdded = false;
  1356. var lastInterpreter = null;
  1357. $.each(app['interpreters'], function(index, interpreter) {
  1358. // Promote the first catagory of interpreters
  1359. if (! dividerAdded) {
  1360. toAddDivider = (app.name === 'editor' || app.name === 'dashboard') && (lastInterpreter != null && lastInterpreter.is_sql != interpreter.is_sql);
  1361. }
  1362. interpreters.push({
  1363. displayName: interpreter.displayName,
  1364. dividerAbove: toAddDivider,
  1365. icon: interpreter.type,
  1366. url: interpreter.page
  1367. });
  1368. lastInterpreter = interpreter;
  1369. if (toAddDivider) {
  1370. dividerAdded = true;
  1371. toAddDivider = false;
  1372. }
  1373. });
  1374. % if user.is_superuser and cluster != ANALYTIC_DB:
  1375. if (app.name === 'editor') {
  1376. interpreters.push({
  1377. displayName: '${ _('Add more...') }',
  1378. dividerAbove: true,
  1379. href: 'http://gethue.com/sql-editor/'
  1380. });
  1381. }
  1382. % endif
  1383. apps.push({
  1384. displayName: app.displayName,
  1385. icon: app.name,
  1386. isCategory: interpreters.length > 0,
  1387. children: interpreters,
  1388. url: app.page
  1389. });
  1390. });
  1391. self.quickCreateActions(apps);
  1392. } else {
  1393. self.quickCreateActions([]);
  1394. }
  1395. self.hasJobBrowser(clusterConfig && clusterConfig['app_config'] && clusterConfig['app_config']['browser'] && (clusterConfig['app_config']['browser']['interpreter_names'].indexOf('yarn') != -1 || clusterConfig['app_config']['browser']['interpreter_names'].indexOf('dataeng') != -1));
  1396. });
  1397. huePubSub.subscribe('hue.new.default.app', function () {
  1398. huePubSub.publish('cluster.config.refresh.config');
  1399. });
  1400. var ClusterPanelViewModel = function() {
  1401. var self = this;
  1402. self.apiHelper = ApiHelper.getInstance();
  1403. self.clusters = ko.mapping.fromJS(${ clusters_config_json | n,unicode });
  1404. self.cluster = ko.observable(self.clusters().length > 0 ? self.clusters()[${ default_cluster_index }] : self.clusters()[0]);
  1405. self.cluster.subscribe(function(newValue) {
  1406. new ClusterConfig({'cluster': ko.mapping.toJSON(newValue)});
  1407. });
  1408. self.contextPanelVisible = ko.observable(false);
  1409. self._loadInterface = function() {
  1410. var interfaces = self.cluster().interfaces().filter(function (i) {return i.interface() == '${ default_cluster_interface }'});
  1411. if (interfaces.length > 0) {
  1412. self.cluster(interfaces[0]);
  1413. }
  1414. };
  1415. var dataEngCluster = $.grep(self.clusters(), function(cluster) {
  1416. return cluster.type() == 'dataeng';
  1417. });
  1418. if (dataEngCluster.length > 0) {
  1419. $.post("/jobbrowser/api/jobs", {
  1420. interface: ko.mapping.toJSON('dataeng-clusters'),
  1421. filters: ko.mapping.toJSON([]),
  1422. }, function (data) {
  1423. if (data.status == 0) {
  1424. var interfaces = [];
  1425. if (data && data.apps) {
  1426. data.apps.forEach(function(cluster) {
  1427. interfaces.push(ko.mapping.fromJS({'name': dataEngCluster[0].name(), 'type': 'dataeng', 'interface': cluster.name, 'id': cluster.id}));
  1428. });
  1429. }
  1430. dataEngCluster[0]['interfaces'](interfaces);
  1431. if (dataEngCluster[0].type() == 'dataeng') {
  1432. self._loadInterface();
  1433. }
  1434. } else {
  1435. $(document).trigger("error", data.message);
  1436. }
  1437. });
  1438. }
  1439. if (self.cluster().type() != 'dataeng') {
  1440. self._loadInterface();
  1441. }
  1442. };
  1443. self.cluster = new ClusterPanelViewModel();
  1444. }
  1445. var topNavViewModel = new TopNavViewModel(onePageViewModel);
  1446. % if not IS_EMBEDDED.get():
  1447. ko.applyBindings(topNavViewModel, $('.top-nav')[0]);
  1448. % endif
  1449. return topNavViewModel;
  1450. })(onePageViewModel);
  1451. (function (onePageViewModel, topNavViewModel) {
  1452. function SideBarViewModel (onePageViewModel, topNavViewModel) {
  1453. var self = this;
  1454. self.items = ko.observableArray();
  1455. huePubSub.subscribe('cluster.config.set.config', function (clusterConfig) {
  1456. var items = [];
  1457. if (clusterConfig && clusterConfig['app_config']) {
  1458. var appsItems = [];
  1459. var appConfig = clusterConfig['app_config'];
  1460. if (appConfig['editor']) {
  1461. var editor = null;
  1462. if (clusterConfig['main_button_action'] && clusterConfig['main_button_action'].page.indexOf('/editor') === 0) {
  1463. editor = clusterConfig['main_button_action'];
  1464. }
  1465. if (!editor) {
  1466. var defaultEditor = appConfig['editor']['default_sql_interpreter'];
  1467. if (defaultEditor) {
  1468. var foundEditor = appConfig['editor']['interpreters'].filter(function (interpreter) {
  1469. return interpreter.type === defaultEditor;
  1470. });
  1471. if (foundEditor.length === 1) {
  1472. editor = foundEditor[0];
  1473. }
  1474. }
  1475. }
  1476. if (!editor && appConfig['editor']['interpreters'].length > 1) {
  1477. editor = appConfig['editor']['interpreters'][1];
  1478. }
  1479. if (editor) {
  1480. appsItems.push({
  1481. displayName: '${ _("Editor") }',
  1482. url: editor['page'],
  1483. icon: 'editor'
  1484. });
  1485. } else {
  1486. appsItems.push({
  1487. displayName: appConfig['editor']['displayName'],
  1488. url: appConfig['editor']['page'],
  1489. icon: 'editor'
  1490. });
  1491. }
  1492. }
  1493. ['dashboard', 'scheduler'].forEach(function(appName) {
  1494. if (appConfig[appName]) {
  1495. appsItems.push({
  1496. displayName: appConfig[appName]['displayName'],
  1497. url: appConfig[appName]['page'],
  1498. icon: appName
  1499. });
  1500. }
  1501. });
  1502. if (appsItems.length > 0) {
  1503. items.push({
  1504. isCategory: true,
  1505. displayName: '${ _('Apps') }',
  1506. children: appsItems
  1507. })
  1508. }
  1509. var browserItems = [];
  1510. browserItems.push({
  1511. displayName: '${ _('Documents') }',
  1512. url: '/home/',
  1513. icon: 'documents'
  1514. });
  1515. if (appConfig['browser'] && appConfig['browser']['interpreters']) {
  1516. appConfig['browser']['interpreters'].forEach(function(browser) {
  1517. browserItems.push({
  1518. displayName: browser.displayName,
  1519. url: browser.page,
  1520. icon: browser.type
  1521. });
  1522. });
  1523. }
  1524. if (browserItems.length > 0) {
  1525. items.push({
  1526. isCategory: true,
  1527. displayName: '${ _('Browsers') }',
  1528. children: browserItems
  1529. })
  1530. }
  1531. var sdkItems = [];
  1532. if (appConfig['sdkapps'] && appConfig['sdkapps']['interpreters']) {
  1533. appConfig['sdkapps']['interpreters'].forEach(function(browser) {
  1534. sdkItems.push({
  1535. displayName: browser['displayName'],
  1536. url: browser['page']
  1537. });
  1538. });
  1539. }
  1540. if (sdkItems.length > 0) {
  1541. items.push({
  1542. isCategory: true,
  1543. displayName: appConfig['sdkapps']['displayName'],
  1544. children: sdkItems
  1545. })
  1546. }
  1547. }
  1548. self.items(items);
  1549. });
  1550. self.leftNavVisible = topNavViewModel.leftNavVisible;
  1551. self.onePageViewModel = onePageViewModel;
  1552. }
  1553. var sidebarViewModel = new SideBarViewModel(onePageViewModel, topNavViewModel);
  1554. ko.applyBindings(sidebarViewModel, $('.hue-sidebar')[0]);
  1555. })(onePageViewModel, topNavViewModel);
  1556. huePubSub.publish('cluster.config.get.config');
  1557. $(document).on('hideHistoryModal', function (e) {
  1558. $('#clearNotificationHistoryModal').modal('hide');
  1559. });
  1560. huePubSub.subscribe('query.and.watch', function (query) {
  1561. $.post(query['url'], {
  1562. format: "json",
  1563. sourceType: query['sourceType']
  1564. },function(resp) {
  1565. if (resp.history_uuid) {
  1566. huePubSub.publish('open.editor.query', resp.history_uuid);
  1567. } else if (resp.message) {
  1568. $(document).trigger("error", resp.message);
  1569. }
  1570. }).fail(function (xhr) {
  1571. $(document).trigger("error", xhr.responseText);
  1572. });
  1573. });
  1574. var hideJobsPanels = function (e) {
  1575. if ($(e.target).parents('.navbar-default').length > 0 && $(e.target).closest('.history-panel').length === 0 && $(e.target).closest('.btn-toggle-jobs-panel').length === 0 && $(e.target).closest('.hamburger-hue').length === 0 && $('.jobs-panel').is(':visible')) {
  1576. huePubSub.publish('hide.jobs.panel');
  1577. huePubSub.publish('hide.history.panel');
  1578. }
  1579. };
  1580. var clickThrottle = -1;
  1581. $(window).click(function (e) {
  1582. window.clearTimeout(clickThrottle);
  1583. clickThrottle = window.setTimeout(function () {
  1584. hideJobsPanels(e);
  1585. }, 10);
  1586. });
  1587. $('.page-content').jHueScrollUp();
  1588. if (typeof window.hueDebug === 'undefined') {
  1589. window.hueDebug = {};
  1590. }
  1591. window.hueDebug.onePageViewModel = onePageViewModel;
  1592. window.hueDebug.sidePanelViewModel = sidePanelViewModel;
  1593. window.hueDebug.topNavViewModel = topNavViewModel;
  1594. window.hueDebug.viewModel = function (element) {
  1595. if (typeof element !== 'undefined' && typeof element === 'string') {
  1596. element = $(element)[0];
  1597. }
  1598. return element ? ko.dataFor(element) : window.hueDebug.onePageViewModel;
  1599. };
  1600. var tour = new Shepherd.Tour({
  1601. defaults: {
  1602. classes: 'shepherd-theme-hue',
  1603. showCancelLink: true
  1604. }
  1605. });
  1606. tour.addStep('welcome', {
  1607. text: '<b>${ _ko('Welcome to Hue 4!') }</b><br><br>${ _ko('We want to introduce you to the new interface. It takes less than a minute. Ready? ') }'
  1608. });
  1609. tour.addStep('topnav', {
  1610. text: '${ _ko('A new nav bar and big blue button!') }<br><br>${ _ko('Open Hue to your favorite app, select other apps from the blue button, do global search, and view notification panels at right.') }',
  1611. attachTo: '.navbar-default bottom'
  1612. });
  1613. %if user.is_superuser:
  1614. tour.addStep('admin', {
  1615. text: '${ _ko('As a superuser, you can check system configuration from the username drop down and install sample data and jobs for your users.') }',
  1616. attachTo: '.top-nav-right .dropdown bottom'
  1617. });
  1618. %endif
  1619. tour.addStep('leftpanel', {
  1620. text: '${ _ko('Discover data sources with the improved data assist panel. Remember to right-click for more!') }',
  1621. attachTo: '.left-panel right'
  1622. });
  1623. tour.addStep('pagecontent', {
  1624. text: '${ _ko('This is the main attraction, where your selected app runs.') }<br>${ _ko('Hover on the app name to star it as your favorite application.') }',
  1625. attachTo: '.page-content center'
  1626. });
  1627. tour.addStep('rightpanel', {
  1628. text: '${ _ko('Some apps have a right panel with additional information to assist you in your data discovery.') }',
  1629. attachTo: '.right-panel left'
  1630. });
  1631. tour.addStep('bye', {
  1632. text: '${ _ko('This ends the tour. To see it again, click Welcome Tour from the username drop down.') }<br><br>${ _ko('And now go ') }<b>${ _ko('Query, Explore, Repeat') }</b>!'
  1633. });
  1634. var closeTourOnEsc = function (e) {
  1635. if (e.keyCode === 27) {
  1636. tour.cancel();
  1637. }
  1638. };
  1639. % if is_demo or not user_preferences.get(PREFERENCE_IS_WELCOME_TOUR_SEEN):
  1640. $(document).on('keyup', closeTourOnEsc);
  1641. $(document).on('click', '.shepherd-backdrop', tour.cancel);
  1642. tour.start();
  1643. % endif
  1644. tour.on('complete', function () {
  1645. $.post('/desktop/api2/user_preferences/${ PREFERENCE_IS_WELCOME_TOUR_SEEN }', {
  1646. 'set': 'seen'
  1647. });
  1648. $(document).off('keyup', closeTourOnEsc);
  1649. });
  1650. tour.on('cancel', function () {
  1651. $.post('/desktop/api2/user_preferences/${ PREFERENCE_IS_WELCOME_TOUR_SEEN }', {
  1652. 'set': 'seen'
  1653. });
  1654. $(document).off('keyup', closeTourOnEsc);
  1655. });
  1656. huePubSub.subscribe('show.welcome.tour', function () {
  1657. $(document).on('keyup', closeTourOnEsc);
  1658. tour.start();
  1659. });
  1660. });
  1661. </script>
  1662. ${ commonHeaderFooterComponents.footer(messages) }
  1663. % if IS_EMBEDDED.get():
  1664. </div>
  1665. % endif
  1666. <div class="monospace-preload" style="opacity: 0">
  1667. ${ _('Hue and the Hue logo are trademarks of Cloudera, Inc.') }
  1668. <b>Query. Explore. Repeat.</b>
  1669. </div>
  1670. </body>
  1671. </html>