assist.mako 154 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322
  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 metadata.conf import has_navigator, OPTIMIZER
  19. from metastore.conf import ENABLE_NEW_CREATE_TABLE
  20. from notebook.conf import ENABLE_QUERY_BUILDER, ENABLE_QUERY_SCHEDULING, get_ordered_interpreters
  21. from dashboard.conf import HAS_SQL_ENABLED
  22. from desktop import appmanager
  23. from desktop import conf
  24. from desktop.conf import IS_EMBEDDED, USE_NEW_SIDE_PANELS, VCS
  25. from desktop.lib.i18n import smart_unicode
  26. from desktop.views import _ko
  27. %>
  28. <%def name="assistJSModels()">
  29. <script src="${ static('desktop/js/assist/assistDbEntry.js') }"></script>
  30. <script src="${ static('desktop/js/assist/assistDbSource.js') }"></script>
  31. <script src="${ static('desktop/js/assist/assistStorageEntry.js') }"></script>
  32. <script src="${ static('desktop/js/assist/assistGitEntry.js') }"></script>
  33. <script src="${ static('desktop/js/assist/assistHBaseEntry.js') }"></script>
  34. <script src="${ static('desktop/js/document/hueDocument.js') }"></script>
  35. <script src="${ static('desktop/js/document/hueFileEntry.js') }"></script>
  36. </%def>
  37. <%def name="assistPanel(is_s3_enabled=False)">
  38. <%
  39. # TODO remove
  40. try:
  41. home_dir = user.get_home_directory()
  42. if not request.fs.isdir(home_dir):
  43. home_dir = '/'
  44. except:
  45. home_dir = '/'
  46. %>
  47. <script type="text/html" id="assist-no-database-entries">
  48. <ul class="assist-tables">
  49. <li>
  50. <span class="assist-no-entries">${_('No entries found')}</span>
  51. </li>
  52. </ul>
  53. </script>
  54. <script type="text/html" id="assist-no-table-entries">
  55. <ul>
  56. <li>
  57. <span class="assist-no-entries">${_('The table has no columns')}</span>
  58. </li>
  59. </ul>
  60. </script>
  61. <script type="text/html" id="assist-database-actions">
  62. <div class="assist-actions database-actions" style="opacity: 0">
  63. %if has_navigator(user):
  64. <!-- ko if: sourceType === 'hive' || sourceType === 'impala' -->
  65. <a class="inactive-action" href="javascript:void(0)" data-bind="visible: navigationSettings.showStats, click: function (data, event) { showContextPopover(data, event); }, css: { 'blue': statsVisible }"><i class="fa fa-fw fa-info" title="${_('Show details')}"></i></a>
  66. <!-- /ko -->
  67. %endif
  68. <a class="inactive-action" href="javascript:void(0)" data-bind="visible: navigationSettings.openItem, click: openItem"><i class="fa fa-long-arrow-right" title="${_('Open')}"></i></a>
  69. </div>
  70. </script>
  71. <script type="text/html" id="collection-title-context-items">
  72. <li><a href="javascript:void(0);" data-bind="hueLink: '/indexer'"><i class="fa fa-fw fa-table"></i> ${ _('Open in Browser') }</a></li>
  73. </script>
  74. <script type="text/html" id="sql-context-items">
  75. <!-- ko if: typeof catalogEntry !== 'undefined' -->
  76. <!-- ko if: sourceType === 'solr' -->
  77. <li><a href="javascript:void(0);" data-bind="click: function (data) { showContextPopover(data, { target: $parentContext.$contextSourceElement }, { left: -15, top: 2 }); }"><i class="fa fa-fw fa-info"></i> ${ _('Show details') }</a></li>
  78. <!-- ko if: catalogEntry.isTableOrView() -->
  79. <li><a href="javascript:void(0);" data-bind="click: openInIndexer"><i class="fa fa-fw fa-table"></i> ${ _('Open in Browser') }</a></li>
  80. <li>
  81. <a href="javascript: void(0);" data-bind="click: function() { explore(true); }">
  82. <!-- ko template: { name: 'app-icon-template', data: { icon: 'dashboard' } } --><!-- /ko --> ${ _('Open in Dashboard') }
  83. </a>
  84. </li>
  85. <!-- /ko -->
  86. <!-- /ko -->
  87. <!-- ko ifnot: sourceType === 'solr' -->
  88. <li><a href="javascript:void(0);" data-bind="click: function (data) { showContextPopover(data, { target: $parentContext.$contextSourceElement }, { left: -15, top: 2 }); }"><i class="fa fa-fw fa-info"></i> ${ _('Show details') }</a></li>
  89. <!-- ko if: !catalogEntry.isDatabase() && $currentApp() === 'editor' -->
  90. <li><a href="javascript:void(0);" data-bind="click: dblClick"><i class="fa fa-fw fa-paste"></i> ${ _('Insert at cursor') }</a></li>
  91. <!-- /ko -->
  92. % if not IS_EMBEDDED.get():
  93. <!-- ko if: catalogEntry.path.length <=2 -->
  94. <li><a href="javascript:void(0);" data-bind="click: openInMetastore"><i class="fa fa-fw fa-table"></i> ${ _('Open in Browser') }</a></li>
  95. <!-- /ko -->
  96. % endif
  97. <!-- ko if: catalogEntry.isTableOrView() -->
  98. <li>
  99. <a href="javascript:void(0);" data-bind="click: function() { huePubSub.publish('query.and.watch', {'url': '/notebook/browse/' + databaseName + '/' + tableName + '/', sourceType: sourceType}); }">
  100. <i class="fa fa-fw fa-code"></i> ${ _('Open in Editor') }
  101. </a>
  102. </li>
  103. % if HAS_SQL_ENABLED.get():
  104. <li>
  105. <a href="javascript: void(0);" data-bind="click: function() { explore(false); }">
  106. <!-- ko template: { name: 'app-icon-template', data: { icon: 'dashboard' } } --><!-- /ko --> ${ _('Open in Dashboard') }
  107. </a>
  108. </li>
  109. % endif
  110. <!-- /ko -->
  111. %if ENABLE_QUERY_BUILDER.get():
  112. <!-- ko if: catalogEntry.isColumn() && $currentApp() === 'editor' -->
  113. <li class="divider"></li>
  114. <!-- ko template: { name: 'query-builder-context-items' } --><!-- /ko -->
  115. <!-- /ko -->
  116. %endif
  117. <!-- /ko -->
  118. <!-- /ko -->
  119. </script>
  120. <script type="text/html" id="query-builder-context-items">
  121. <li data-bind="contextSubMenu: '.hue-context-sub-menu'">
  122. <a href="javascript:void(0);"><i class="fa fa-fw fa-magic"></i> ${ _('Project') }<i class="sub-icon fa fa-fw fa-chevron-right"></i></a>
  123. <ul class="hue-context-menu hue-context-sub-menu">
  124. <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Select', 'Project', '{0}', false, false); }">${ _('Select') }</a></li>
  125. <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Select distinct', 'Project', '{0}', false, false); }">${ _('Select distinct') }</a></li>
  126. </ul>
  127. </li>
  128. <li data-bind="contextSubMenu: '.hue-context-sub-menu'">
  129. <a href="javascript:void(0);"><i class="fa fa-fw fa-magic"></i> ${ _('Aggregate') }<i class="sub-icon fa fa-fw fa-chevron-right"></i></a>
  130. <ul class="hue-context-menu hue-context-sub-menu">
  131. <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Count', 'Aggregate', 'COUNT({0}.{1}) as count_{1}', false, false); }">${ _('Count') }</a></li>
  132. <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Count distinct', 'Aggregate', 'COUNT(DISTINCT {0}.{1}) as distinct_count_{1}', false, false); }">${ _('Count distinct') }</a></li>
  133. <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Sum', 'Aggregate', 'SUM({0}.{1}) as sum_{1}', false, false); }">${ _('Sum') }</a></li>
  134. <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Minimum', 'Aggregate', 'MIN({0}.{1}) as min_{1}', false, false); }">${ _('Minimum') }</a></li>
  135. <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Maximum', 'Aggregate', 'MAX({0}.{1}) as max_{1}', false, false); }">${ _('Maximum') }</a></li>
  136. <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Average', 'Aggregate', 'AVG({0}.{1}) as avg_{1}', false, false); }">${ _('Average') }</a></li>
  137. </ul>
  138. </li>
  139. <li data-bind="contextSubMenu: '.hue-context-sub-menu'">
  140. <a href="javascript:void(0);"><i class="fa fa-fw fa-magic"></i> ${ _('Filter') }<i class="sub-icon fa fa-fw fa-chevron-right"></i></a>
  141. <ul class="hue-context-menu hue-context-sub-menu">
  142. <li><a href="javascript:void(0);" data-bind="click: function () { var isNotNullRule = QueryBuilder.getRule(databaseName, tableName, columnName, 'Is not null'); if (isNotNullRule.length) { isNotNullRule.attr('rule', 'Is null'); isNotNullRule.find('.rule').text('Is null'); } else { QueryBuilder.addRule(databaseName, tableName, columnName, 'Is null', 'Filter', '{0}.{1} = null', false, false); } }">${ _('Is null') }</a></li>
  143. <li><a href="javascript:void(0);" data-bind="click: function () { var isNullRule = QueryBuilder.getRule(databaseName, tableName, columnName, 'Is null'); if (isNullRule.length) { isNullRule.attr('rule', 'Is not null'); isNullRule.find('.rule').text('Is not null'); } else { QueryBuilder.addRule(databaseName, tableName, columnName, 'Is not null', 'Filter', '{0}.{1} != null', false, false); } }">${ _('Is not null') }</a></li>
  144. <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Equal to', 'Filter', '{0}.{1} = {2}', true, true); }">${ _('Equal to') }</a></li>
  145. <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Not equal to', 'Filter', '{0}.{1} != {2}', true, true); }">${ _('Not equal to') }</a></li>
  146. <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Greater than', 'Filter', '{0}.{1} > {2}', true, false) }">${ _('Greater than') }</a></li>
  147. <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Less than', 'Filter', '{0}.{1} < {2}', true, false); }">${ _('Less than') }</a></li>
  148. </ul>
  149. </li>
  150. <li data-bind="contextSubMenu: '.hue-context-sub-menu'">
  151. <a href="javascript:void(0);"><i class="fa fa-fw fa-magic"></i> ${ _('Order') }<i class="sub-icon fa fa-fw fa-chevron-right"></i></a>
  152. <ul class="hue-context-menu hue-context-sub-menu">
  153. <li><a href="javascript:void(0);" data-bind="click: function () { var descendingRule = QueryBuilder.getRule(databaseName, tableName, columnName, 'Descending'); if (descendingRule.length) { descendingRule.attr('rule', 'Ascending'); descendingRule.find('.rule').text('Ascending'); } else { QueryBuilder.addRule(databaseName, tableName, columnName, 'Ascending', 'Order', '{0}.{1} ASC', false, false); } }">${ _('Ascending') }</a></li>
  154. <li><a href="javascript:void(0);" data-bind="click: function () { var ascendingRule = QueryBuilder.getRule(databaseName, tableName, columnName, 'Ascending'); if (ascendingRule.length) { ascendingRule.attr('rule', 'Descending'); ascendingRule.find('.rule').text('Descending'); } else { QueryBuilder.addRule(databaseName, tableName, columnName, 'Descending', 'Order', '{0}.{1} DESC', false, false); } }">${ _('Descending') }</a></li>
  155. </ul>
  156. </li>
  157. </script>
  158. <script type="text/html" id="hdfs-context-items">
  159. <li><a href="javascript:void(0);" data-bind="click: function (data) { showContextPopover(data, { target: $parentContext.$contextSourceElement }, { left: -15, top: 2 }); }"><i class="fa fa-fw fa-info"></i> ${ _('Show details') }</a></li>
  160. <li><a href="javascript:void(0);" data-bind="hueLink: definition.url"><i class="fa fa-fw" data-bind="css: {'fa-folder-open-o': definition.type === 'dir', 'fa-file-text-o': definition.type === 'file'}"></i> ${ _('Open in Browser') }</a></li>
  161. <!-- ko if: IS_HUE_4 && definition.type === 'file' -->
  162. <li><a href="javascript:void(0);" data-bind="click: openInImporter"><!-- ko template: { name: 'app-icon-template', data: { icon: 'importer' } } --><!-- /ko --> ${ _('Open in Importer') }</a></li>
  163. <!-- /ko -->
  164. <!-- ko if: $currentApp() === 'editor' -->
  165. <li><a href="javascript:void(0);" data-bind="click: dblClick"><i class="fa fa-fw fa-paste"></i> ${ _('Insert at cursor') }</a></li>
  166. <!-- /ko -->
  167. </script>
  168. <script type="text/html" id="document-context-items">
  169. <!-- ko if: definition().type === 'directory' -->
  170. <li><a href="javascript: void(0);" data-bind="click: open"><i class="fa fa-fw fa-folder-open-o"></i> ${ _('Open folder') }</a></li>
  171. <!-- /ko -->
  172. <!-- ko if: definition().type !== 'directory' -->
  173. <li><a href="javascript: void(0);" data-bind="click: function(data) { showContextPopover(data, { target: $parentContext.$contextSourceElement }, { left: -15, top: 2 }); }"><i class="fa fa-fw fa-info"></i> ${ _('Show details') }</a></li>
  174. <li><a href="javascript: void(0);" data-bind="click: open"><i class="fa fa-fw fa-edit"></i> ${ _('Open document') }</a></li>
  175. <li><a href="javascript: void(0);" data-bind="click: function() { huePubSub.publish('doc.show.delete.modal', $data); activeEntry().getSelectedDocsWithDependents(); activeEntry().showDeleteConfirmation(); }"><i class="fa fa-fw fa-trash-o"></i> ${ _('Delete document') }</a></li>
  176. <!-- /ko -->
  177. </script>
  178. <script type="text/html" id="hbase-context-items">
  179. <!-- ko if: definition.host -->
  180. <li><a href="javascript: void(0);" data-bind="click: open"><i class="fa fa-fw fa-folder-open-o"></i> ${ _('Open cluster') }</a></li>
  181. <!-- /ko -->
  182. <!-- ko ifnot: definition.host -->
  183. <li><a href="javascript: void(0);" data-bind="click: open"><!-- ko template: { name: 'app-icon-template', data: { icon: 'hbase' } } --><!-- /ko --> ${ _('Open in HBase') }</a></li>
  184. <!-- /ko -->
  185. </script>
  186. <script type="text/html" id="assist-database-entry">
  187. <li class="assist-table" data-bind="appAwareTemplateContextMenu: { template: 'sql-context-items', scrollContainer: '.assist-db-scrollable' }, visibleOnHover: { selector: '.database-actions' }">
  188. <!-- ko template: { name: 'assist-database-actions' } --><!-- /ko -->
  189. <a class="assist-table-link" href="javascript: void(0);" data-bind="click: function () { $parent.selectedDatabase($data); $parent.selectedDatabaseChanged(); }, attr: {'title': catalogEntry.getTitle(true) }, draggableText: { text: editorText, meta: {'type': 'sql', 'database': databaseName} }"><i class="fa fa-fw fa-database muted valign-middle"></i> <span class="highlightable" data-bind="text: catalogEntry.name, css: { 'highlight': highlight() }"></span></a>
  190. </li>
  191. </script>
  192. <script type="text/html" id="assist-table-entry">
  193. <li class="assist-table" data-bind="appAwareTemplateContextMenu: { template: 'sql-context-items', scrollContainer: '.assist-db-scrollable' }, visibleOnHover: { override: statsVisible() || navigationSettings.rightAssist, selector: '.table-actions' }">
  194. <div class="assist-actions table-actions" data-bind="css: { 'assist-actions-left': navigationSettings.rightAssist }" style="opacity: 0">
  195. <a class="inactive-action" href="javascript:void(0)" data-bind="visible: navigationSettings.showStats, click: showContextPopover, css: { 'blue': statsVisible }"><i class="fa fa-fw fa-info" title="${_('Show details')}"></i></a>
  196. <a class="inactive-action" href="javascript:void(0)" data-bind="visible: navigationSettings.openItem, click: openItem"><i class="fa fa-long-arrow-right" title="${_('Open')}"></i></a>
  197. </div>
  198. <a class="assist-entry assist-table-link" href="javascript:void(0)" data-bind="click: toggleOpen, attr: {'title': catalogEntry.getTitle(true) }, draggableText: { text: editorText, meta: {'type': 'sql', 'isView': catalogEntry.isView(), 'table': tableName, 'database': databaseName} }">
  199. <i class="fa fa-fw fa-table muted valign-middle" data-bind="css: { 'fa-eye': catalogEntry.isView() && !navigationSettings.rightAssist, 'fa-table': catalogEntry.isTable() && sourceType !== 'solr' && !navigationSettings.rightAssist, 'fa-search': sourceType === 'solr' }"></i>
  200. <span class="highlightable" data-bind="text: catalogEntry.getDisplayName(navigationSettings.rightAssist), css: { 'highlight': highlight }"></span>
  201. </a>
  202. <div class="center assist-spinner" data-bind="visible: loading() && open()"><i class="fa fa-spinner fa-spin"></i></div>
  203. <!-- ko template: { if: open, name: 'assist-db-entries' } --><!-- /ko -->
  204. </li>
  205. </script>
  206. <script type="text/html" id="assist-column-entry">
  207. <li data-bind="appAwareTemplateContextMenu: { template: 'sql-context-items', scrollContainer: '.assist-db-scrollable' }, visible: ! hasErrors(), visibleOnHover: { childrenOnly: true, override: statsVisible, selector: catalogEntry.isView() ? '.table-actions' : '.column-actions' }, css: { 'assist-table': catalogEntry.isView(), 'assist-column': catalogEntry.isField() }">
  208. <div class="assist-actions column-actions" data-bind="css: { 'assist-actions-left': navigationSettings.rightAssist }" style="opacity: 0">
  209. <a class="inactive-action" href="javascript:void(0)" data-bind="visible: navigationSettings.showStats, click: showContextPopover, css: { 'blue': statsVisible }"><i class="fa fa-fw fa-info" title="${_('Show details')}"></i></a>
  210. </div>
  211. <!-- ko if: expandable -->
  212. <a class="assist-entry assist-field-link" href="javascript:void(0)" data-bind="click: toggleOpen, attr: {'title': catalogEntry.getTitle(true) }, css: { 'assist-entry-left-action': navigationSettings.rightAssist }">
  213. <span class="highlightable" data-bind="css: { 'highlight': highlight}, attr: {'column': columnName, 'table': tableName, 'database': databaseName }, text: catalogEntry.getDisplayName(), draggableText: { text: editorText, meta: {'type': 'sql', 'column': columnName, 'table': tableName, 'database': databaseName } }"></span><!-- ko if: catalogEntry.isPrimaryKey() --> <i class="fa fa-key"></i><!-- /ko -->
  214. </a>
  215. <!-- /ko -->
  216. <!-- ko ifnot: expandable -->
  217. <div class="assist-entry assist-field-link default-cursor" href="javascript:void(0)" data-bind="event: { dblclick: dblClick }, attr: {'title': catalogEntry.getTitle(true) }, css: { 'assist-entry-left-action': navigationSettings.rightAssist }">
  218. <span class="highlightable" data-bind="css: { 'highlight': highlight}, attr: {'column': columnName, 'table': tableName, 'database': databaseName}, text: catalogEntry.getDisplayName(), draggableText: { text: editorText, meta: {'type': 'sql', 'column': columnName, 'table': tableName, 'database': databaseName} }"></span><!-- ko if: catalogEntry.isPrimaryKey() --> <i class="fa fa-key"></i><!-- /ko -->
  219. </div>
  220. <!-- /ko -->
  221. <div class="center assist-spinner" data-bind="visible: loading"><i class="fa fa-spinner fa-spin"></i></div>
  222. <!-- ko template: { if: open, name: 'assist-db-entries' } --><!-- /ko -->
  223. </li>
  224. </script>
  225. <script type="text/html" id="assist-column-entry-assistant">
  226. <li data-bind="appAwareTemplateContextMenu: { template: 'sql-context-items', scrollContainer: '.assist-db-scrollable' }, visible: ! hasErrors(), visibleOnHover: { childrenOnly: true, override: statsVisible, selector: catalogEntry.isView() ? '.table-actions' : '.column-actions' }, css: { 'assist-table': catalogEntry.isView(), 'assist-column': catalogEntry.isField() }">
  227. <div class="assist-actions column-actions assist-actions-left" style="opacity: 0">
  228. <a class="inactive-action" href="javascript:void(0)" data-bind="visible: navigationSettings.showStats, click: showContextPopover, css: { 'blue': statsVisible }"><i class="fa fa-fw fa-info" title="${_('Show details')}"></i></a>
  229. </div>
  230. <!-- ko if: expandable -->
  231. <a class="assist-entry assist-field-link assist-field-link-dark assist-entry-left-action assist-ellipsis" href="javascript:void(0)" data-bind="click: toggleOpen, attr: {'title': catalogEntry.getTitle(true) }">
  232. <span data-bind="text: catalogEntry.getType()" class="muted pull-right margin-right-20"></span>
  233. <span class="highlightable" data-bind="css: { 'highlight': highlight}, attr: {'column': columnName, 'table': tableName, 'database': databaseName }, text: catalogEntry.name, draggableText: { text: editorText, meta: {'type': 'sql', 'column': columnName, 'table': tableName, 'database': databaseName } }"></span><!-- ko if: catalogEntry.isPrimaryKey() --> <i class="fa fa-key"></i><!-- /ko -->
  234. </a>
  235. <!-- /ko -->
  236. <!-- ko ifnot: expandable -->
  237. <div class="assist-entry assist-field-link assist-field-link-dark default-cursor assist-ellipsis" href="javascript:void(0)" data-bind="event: { dblclick: dblClick }, attr: {'title': catalogEntry.getTitle(true) }, css: { 'assist-entry-left-action': navigationSettings.rightAssist }">
  238. <span data-bind="text: catalogEntry.getType()" class="muted pull-right margin-right-20"></span>
  239. <span class="highlightable" data-bind="css: { 'highlight': highlight}, attr: {'column': columnName, 'table': tableName, 'database': databaseName}, text: catalogEntry.name, draggableText: { text: editorText, meta: {'type': 'sql', 'column': columnName, 'table': tableName, 'database': databaseName} }"></span><!-- ko if: catalogEntry.isPrimaryKey() --> <i class="fa fa-key"></i><!-- /ko -->
  240. </div>
  241. <!-- /ko -->
  242. <div class="center assist-spinner" data-bind="visible: loading"><i class="fa fa-spinner fa-spin"></i></div>
  243. <!-- ko template: { if: open, name: 'assist-db-entries' } --><!-- /ko -->
  244. </li>
  245. </script>
  246. <script type="text/html" id="assist-db-entries">
  247. <!-- ko if: ! hasErrors() && hasEntries() && ! loading() && filteredEntries().length == 0 -->
  248. <ul class="assist-tables">
  249. <li class="assist-entry assist-no-entries"><!-- ko if: catalogEntry.isTableOrView() -->${_('No columns found')}<!--/ko--><!-- ko if: catalogEntry.isDatabase() -->${_('No tables found')}<!--/ko--><!-- ko if: catalogEntry.isField() -->${_('No results found')}<!--/ko--></li>
  250. </ul>
  251. <!-- /ko -->
  252. <!-- ko if: ! hasErrors() && hasEntries() && ! loading() && filteredEntries().length > 0 -->
  253. <ul class="database-tree" data-bind="foreachVisible: { data: filteredEntries, minHeight: navigationSettings.rightAssist ? 22 : 23, container: '.assist-db-scrollable', skipScrollEvent: navigationSettings.rightAssist, usePreloadBackground: true }, css: { 'assist-tables': catalogEntry.isDatabase() }">
  254. <!-- ko template: { if: catalogEntry.isTableOrView(), name: 'assist-table-entry' } --><!-- /ko -->
  255. <!-- ko if: navigationSettings.rightAssist -->
  256. <!-- ko template: { ifnot: catalogEntry.isTableOrView(), name: 'assist-column-entry-assistant' } --><!-- /ko -->
  257. <!-- /ko -->
  258. <!-- ko ifnot: navigationSettings.rightAssist -->
  259. <!-- ko template: { ifnot: catalogEntry.isTableOrView(), name: 'assist-column-entry' } --><!-- /ko -->
  260. <!-- /ko -->
  261. </ul>
  262. <!-- /ko -->
  263. <!-- ko template: { if: ! hasErrors() && ! hasEntries() && ! loading() && (catalogEntry.isTableOrView()), name: 'assist-no-table-entries' } --><!-- /ko -->
  264. <!-- ko template: { if: ! hasErrors() && ! hasEntries() && ! loading() && catalogEntry.isDatabase(), name: 'assist-no-database-entries' } --><!-- /ko -->
  265. <!-- ko if: hasErrors -->
  266. <ul class="assist-tables">
  267. <!-- ko if: catalogEntry.isTableOrView() -->
  268. <li class="assist-errors">${ _('Error loading columns.') }</li>
  269. <!-- /ko -->
  270. <!-- ko if: catalogEntry.isField() -->
  271. <li class="assist-errors">${ _('Error loading fields.') }</li>
  272. <!-- /ko -->
  273. </ul>
  274. <!-- /ko -->
  275. </script>
  276. <script type="text/html" id="assist-db-breadcrumb">
  277. <div class="assist-flex-header assist-breadcrumb">
  278. <!-- ko if: selectedSource() -->
  279. <!-- ko if: selectedSource().selectedNamespace() -->
  280. <!-- ko if: selectedSource().selectedNamespace().selectedDatabase() -->
  281. <a data-bind="click: back, appAwareTemplateContextMenu: { template: 'sql-context-items', viewModel: selectedSource().selectedNamespace().selectedDatabase() }">
  282. <i class="fa fa-chevron-left assist-breadcrumb-back" ></i>
  283. <i class="fa fa-database assist-breadcrumb-text"></i>
  284. <span class="assist-breadcrumb-text" data-bind="text: breadcrumb, attr: {'title': breadcrumb() + ' (' + selectedSource().sourceType + ' ' + selectedSource().selectedNamespace().name + ')' }"></span>
  285. </a>
  286. <!-- /ko -->
  287. <!-- ko ifnot: selectedSource().selectedNamespace().selectedDatabase() -->
  288. <!-- ko if: selectedSource().namespaceRefreshEnabled() || selectedSource().namespaces().length > 1-->
  289. <a data-bind="click: back">
  290. <i class="fa fa-chevron-left assist-breadcrumb-back"></i>
  291. <i class="fa fa-snowflake-o assist-breadcrumb-text"></i>
  292. <span class="assist-breadcrumb-text" data-bind="text: breadcrumb, attr: {'title': breadcrumb() + ' (' + selectedSource().sourceType + ')' }"></span>
  293. </a>
  294. <!-- /ko -->
  295. <!-- ko if: !selectedSource().namespaceRefreshEnabled() && selectedSource().namespaces().length <= 1 -->
  296. <a data-bind="click: back">
  297. <i class="fa fa-chevron-left assist-breadcrumb-back"></i>
  298. <i class="fa fa-server assist-breadcrumb-text"></i>
  299. <span class="assist-breadcrumb-text" data-bind="text: breadcrumb"></span>
  300. </a>
  301. <!-- /ko -->
  302. <!-- /ko -->
  303. <!-- /ko -->
  304. <!-- ko ifnot: selectedSource().selectedNamespace() -->
  305. <a data-bind="click: back">
  306. <i class="fa fa-chevron-left assist-breadcrumb-back"></i>
  307. <i class="fa fa-server assist-breadcrumb-text"></i>
  308. <span class="assist-breadcrumb-text" data-bind="text: breadcrumb"></span>
  309. </a>
  310. <!-- /ko -->
  311. <!-- /ko -->
  312. </div>
  313. </script>
  314. <script type="text/html" id="assist-sql-inner-panel">
  315. <!-- ko template: { if: breadcrumb() !== null, name: 'assist-db-breadcrumb' } --><!-- /ko -->
  316. <!-- ko template: { ifnot: selectedSource, name: 'assist-sources-template' } --><!-- /ko -->
  317. <!-- ko with: selectedSource -->
  318. <!-- ko template: { ifnot: selectedNamespace, name: 'assist-namespaces-template' } --><!-- /ko -->
  319. <!-- ko with: selectedNamespace -->
  320. <!-- ko template: { ifnot: selectedDatabase, name: 'assist-databases-template' }--><!-- /ko -->
  321. <!-- ko with: selectedDatabase -->
  322. <!-- ko template: { name: 'assist-tables-template' } --><!-- /ko -->
  323. <!-- /ko -->
  324. <!-- /ko -->
  325. <!-- /ko -->
  326. </script>
  327. <script type="text/html" id="assist-solr-inner-panel">
  328. <!-- ko template: { ifnot: selectedSource, name: 'assist-sources-template' } --><!-- /ko -->
  329. <!-- ko with: selectedSource -->
  330. <!-- ko template: { ifnot: selectedNamespace, name: 'assist-namespaces-template' }--><!-- /ko -->
  331. <!-- ko with: selectedNamespace -->
  332. <!-- ko template: { ifnot: selectedDatabase, name: 'assist-databases-template' }--><!-- /ko -->
  333. <!-- ko with: selectedDatabase -->
  334. <!-- ko template: { name: 'assist-tables-template' } --><!-- /ko -->
  335. <!-- /ko-->
  336. <!-- /ko -->
  337. <!-- /ko -->
  338. </script>
  339. <script type="text/html" id="assist-s3-header-actions">
  340. <div class="assist-db-header-actions">
  341. <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.s3.refresh'); }"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }" title="${_('Manual refresh')}"></i></a>
  342. </div>
  343. </script>
  344. <script type="text/html" id="assist-s3-inner-panel">
  345. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  346. <!-- ko with: selectedS3Entry -->
  347. <div class="assist-flex-header assist-breadcrumb" >
  348. <!-- ko if: parent !== null -->
  349. <a href="javascript: void(0);" data-bind="appAwareTemplateContextMenu: { template: 'hdfs-context-items', scrollContainer: '.assist-s3-scrollable' }, click: function () { huePubSub.publish('assist.selectS3Entry', parent); }">
  350. <i class="fa fa-fw fa-chevron-left"></i>
  351. <i class="fa fa-fw fa-folder-o"></i>
  352. <span data-bind="text: definition.name, tooltip: {'title': path, 'placement': 'top' }"></span>
  353. </a>
  354. <!-- /ko -->
  355. <!-- ko if: parent === null -->
  356. <div>
  357. <i class="fa fa-fw fa-folder-o"></i>
  358. <span data-bind="text: path"></span>
  359. </div>
  360. <!-- /ko -->
  361. <!-- ko template: 'assist-s3-header-actions' --><!-- /ko -->
  362. </div>
  363. <div class="assist-flex-search">
  364. <div class="assist-filter"><input class="clearable" type="text" placeholder="${ _('Filter...') }" data-bind="clearable: filter, value: filter, valueUpdate: 'afterkeydown'"/></div>
  365. </div>
  366. <div class="assist-flex-fill assist-s3-scrollable" data-bind="delayedOverflow">
  367. <div data-bind="visible: ! loading() && ! hasErrors()" style="position: relative;">
  368. <!-- ko hueSpinner: { spin: loadingMore, overlay: true } --><!-- /ko -->
  369. <ul class="assist-tables" data-bind="foreachVisible: { data: entries, minHeight: 22, container: '.assist-s3-scrollable', fetchMore: $data.fetchMore.bind($data) }">
  370. <li class="assist-entry assist-table-link" style="position: relative;" data-bind="appAwareTemplateContextMenu: { template: 'hdfs-context-items', scrollContainer: '.assist-s3-scrollable' }, visibleOnHover: { override: contextPopoverVisible, 'selector': '.assist-actions' }">
  371. <div class="assist-actions table-actions" style="opacity: 0;" >
  372. <a style="padding: 0 3px;" class="inactive-action" href="javascript:void(0);" data-bind="click: showContextPopover, css: { 'blue': contextPopoverVisible }">
  373. <i class='fa fa-info' title="${ _('Details') }"></i>
  374. </a>
  375. </div>
  376. <a href="javascript:void(0)" class="assist-entry assist-table-link" data-bind="multiClick: { click: toggleOpen, dblClick: dblClick }, attr: {'title': definition.name }">
  377. <!-- ko if: definition.type === 'dir' -->
  378. <i class="fa fa-fw fa-folder-o muted valign-middle"></i>
  379. <!-- /ko -->
  380. <!-- ko if: definition.type === 'file' -->
  381. <i class="fa fa-fw fa-file-o muted valign-middle"></i>
  382. <!-- /ko -->
  383. <span draggable="true" data-bind="text: definition.name, draggableText: { text: '\'' + path + '\'', meta: {'type': 's3', 'definition': definition} }"></span>
  384. </a>
  385. </li>
  386. </ul>
  387. <!-- ko if: !loading() && entries().length === 0 -->
  388. <ul class="assist-tables">
  389. <li class="assist-entry"><span class="assist-no-entries"><!-- ko if: filter() -->${_('No results found')}<!-- /ko --><!-- ko ifnot: filter() -->${_('Empty directory')}<!-- /ko --></span></li>
  390. </ul>
  391. <!-- /ko -->
  392. </div>
  393. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  394. <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
  395. <span>${ _('Error loading contents.') }</span>
  396. </div>
  397. </div>
  398. <!-- /ko -->
  399. </script>
  400. <script type="text/html" id="git-details-title">
  401. <span data-bind="text: definition.name"></span>
  402. </script>
  403. <script type="text/html" id="assist-git-header-actions">
  404. <div class="assist-db-header-actions">
  405. <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.git.refresh'); }"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }" title="${_('Manual refresh')}"></i></a>
  406. </div>
  407. </script>
  408. <script type="text/html" id="assist-git-inner-panel">
  409. <!-- ko with: selectedGitEntry -->
  410. <div class="assist-flex-header assist-breadcrumb" >
  411. <!-- ko if: parent !== null -->
  412. <a href="javascript: void(0);" data-bind="click: function () { huePubSub.publish('assist.selectGitEntry', parent); }">
  413. <i class="fa fa-fw fa-chevron-left"></i>
  414. <i class="fa fa-fw fa-folder-o"></i>
  415. <span data-bind="text: path, attr: {'title': path }"></span>
  416. </a>
  417. <!-- /ko -->
  418. <!-- ko if: parent === null -->
  419. <div>
  420. <i class="fa fa-fw fa-folder-o"></i>
  421. <span data-bind="text: path"></span>
  422. </div>
  423. <!-- /ko -->
  424. <!-- ko template: 'assist-git-header-actions' --><!-- /ko -->
  425. </div>
  426. <div class="assist-flex-fill assist-git-scrollable" data-bind="delayedOverflow">
  427. <div data-bind="visible: ! loading() && ! hasErrors()" style="position: relative;">
  428. <!-- ko hueSpinner: { spin: loadingMore, overlay: true } --><!-- /ko -->
  429. <ul class="assist-tables" data-bind="foreachVisible: { data: entries, minHeight: 22, container: '.assist-git-scrollable' }">
  430. <li class="assist-entry assist-table-link" style="position: relative;" data-bind="visibleOnHover: { 'selector': '.assist-actions' }">
  431. <a href="javascript:void(0)" class="assist-entry assist-table-link" data-bind="multiClick: { click: toggleOpen, dblClick: dblClick }, attr: {'title': definition.name }">
  432. <!-- ko if: definition.type === 'dir' -->
  433. <i class="fa fa-fw fa-folder-o muted valign-middle"></i>
  434. <!-- /ko -->
  435. <!-- ko ifnot: definition.type === 'dir' -->
  436. <i class="fa fa-fw fa-file-o muted valign-middle"></i>
  437. <!-- /ko -->
  438. <span draggable="true" data-bind="text: definition.name, draggableText: { text: '\'' + path + '\'', meta: {'type': 'git', 'definition': definition} }"></span>
  439. </a>
  440. </li>
  441. </ul>
  442. <!-- ko if: !loading() && entries().length === 0 -->
  443. <ul class="assist-tables">
  444. <li class="assist-entry"><span class="assist-no-entries">${_('Empty directory')}</span></li>
  445. </ul>
  446. <!-- /ko -->
  447. </div>
  448. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  449. <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
  450. <span>${ _('Error loading contents.') }</span>
  451. </div>
  452. </div>
  453. <!-- /ko -->
  454. </script>
  455. <script type="text/html" id="assist-hdfs-header-actions">
  456. <div class="assist-db-header-actions">
  457. <a class="inactive-action" href="javascript:void(0)" data-bind="click: goHome" title="Go to ${ home_dir }"><i class="pointer fa fa-home"></i></a>
  458. <a class="inactive-action" data-bind="dropzone: {
  459. url: '/filebrowser/upload/file?dest=' + path,
  460. params: { dest: path },
  461. paramName: 'hdfs_file',
  462. onError: function(x, e){ $(document).trigger('error', e); },
  463. onComplete: function () { huePubSub.publish('assist.hdfs.refresh'); huePubSub.publish('fb.hdfs.refresh', path); } }" title="${_('Upload file')}" href="javascript:void(0)">
  464. <div class="dz-message inline" data-dz-message><i class="pointer fa fa-plus" title="${_('Upload file')}"></i></div>
  465. </a>
  466. <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.hdfs.refresh'); }" title="${_('Manual refresh')}"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }"></i></a>
  467. </div>
  468. </script>
  469. <script type="text/html" id="assist-adls-header-actions">
  470. <div class="assist-db-header-actions">
  471. <a class="inactive-action" href="javascript:void(0)" data-bind="click: goHome" title="Go to ${ home_dir }"><i class="pointer fa fa-home"></i></a>
  472. <a class="inactive-action" data-bind="dropzone: {
  473. url: '/filebrowser/upload/file?dest=adl:' + path,
  474. params: { dest: path },
  475. paramName: 'hdfs_file',
  476. onError: function(x, e){ $(document).trigger('error', e); },
  477. onComplete: function () { huePubSub.publish('assist.adls.refresh'); } }" title="${_('Upload file')}" href="javascript:void(0)">
  478. <div class="dz-message inline" data-dz-message><i class="pointer fa fa-plus" title="${_('Upload file')}"></i></div>
  479. </a>
  480. <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.adls.refresh'); }" title="${_('Manual refresh')}"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }"></i></a>
  481. </div>
  482. </script>
  483. <script type="text/html" id="assist-hdfs-inner-panel">
  484. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  485. <!-- ko with: selectedHdfsEntry -->
  486. <div class="assist-flex-header assist-breadcrumb" >
  487. <!-- ko if: parent !== null -->
  488. <a href="javascript: void(0);" data-bind="appAwareTemplateContextMenu: { template: 'hdfs-context-items', scrollContainer: '.assist-hdfs-scrollable' }, click: function () { huePubSub.publish('assist.selectHdfsEntry', parent); }">
  489. <i class="fa fa-fw fa-chevron-left"></i>
  490. <i class="fa fa-fw fa-folder-o"></i>
  491. <span data-bind="text: definition.name, tooltip: {'title': path, 'placement': 'top' }"></span>
  492. </a>
  493. <!-- /ko -->
  494. <!-- ko if: parent === null -->
  495. <div>
  496. <i class="fa fa-fw fa-folder-o"></i>
  497. <span data-bind="text: path"></span>
  498. </div>
  499. <!-- /ko -->
  500. <!-- ko template: 'assist-hdfs-header-actions' --><!-- /ko -->
  501. </div>
  502. <div class="assist-flex-search">
  503. <div class="assist-filter"><input class="clearable" type="text" placeholder="${ _('Filter...') }" data-bind="clearable: filter, value: filter, valueUpdate: 'afterkeydown'"/></div>
  504. </div>
  505. <div class="assist-flex-fill assist-hdfs-scrollable" data-bind="delayedOverflow">
  506. <div data-bind="visible: ! loading() && ! hasErrors()" style="position: relative;">
  507. <!-- ko hueSpinner: { spin: loadingMore, overlay: true } --><!-- /ko -->
  508. <ul class="assist-tables" data-bind="foreachVisible: { data: entries, minHeight: 22, container: '.assist-hdfs-scrollable', fetchMore: $data.fetchMore.bind($data) }">
  509. <li class="assist-entry assist-table-link" style="position: relative;" data-bind="appAwareTemplateContextMenu: { template: 'hdfs-context-items', scrollContainer: '.assist-hdfs-scrollable' }, visibleOnHover: { override: contextPopoverVisible, 'selector': '.assist-actions' }">
  510. <div class="assist-actions table-actions" style="opacity: 0;" >
  511. <a style="padding: 0 3px;" class="inactive-action" href="javascript:void(0);" data-bind="click: showContextPopover, css: { 'blue': contextPopoverVisible }">
  512. <i class='fa fa-info' title="${ _('Details') }"></i>
  513. </a>
  514. </div>
  515. <a href="javascript:void(0)" class="assist-entry assist-table-link" data-bind="multiClick: { click: toggleOpen, dblClick: dblClick }, attr: {'title': definition.name }">
  516. <!-- ko if: definition.type === 'dir' -->
  517. <i class="fa fa-fw fa-folder-o muted valign-middle"></i>
  518. <!-- /ko -->
  519. <!-- ko if: definition.type === 'file' -->
  520. <i class="fa fa-fw fa-file-o muted valign-middle"></i>
  521. <!-- /ko -->
  522. <span draggable="true" data-bind="text: definition.name, draggableText: { text: '\'' + path + '\'', meta: {'type': 'hdfs', 'definition': definition} }"></span>
  523. </a>
  524. </li>
  525. </ul>
  526. <!-- ko if: !loading() && entries().length === 0 -->
  527. <ul class="assist-tables">
  528. <li class="assist-entry"><span class="assist-no-entries"><!-- ko if: filter() -->${_('No results found')}<!-- /ko --><!-- ko ifnot: filter() -->${_('Empty directory')}<!-- /ko --></span></li>
  529. </ul>
  530. <!-- /ko -->
  531. </div>
  532. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  533. <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
  534. <span>${ _('Error loading contents.') }</span>
  535. </div>
  536. </div>
  537. <!-- /ko -->
  538. </script>
  539. <script type="text/html" id="assist-adls-inner-panel">
  540. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  541. <!-- ko with: selectedAdlsEntry -->
  542. <div class="assist-flex-header assist-breadcrumb" >
  543. <!-- ko if: parent !== null -->
  544. <a href="javascript: void(0);" data-bind="appAwareTemplateContextMenu: { template: 'hdfs-context-items', scrollContainer: '.assist-adls-scrollable' }, click: function () { huePubSub.publish('assist.selectAdlsEntry', parent); }">
  545. <i class="fa fa-fw fa-chevron-left"></i>
  546. <i class="fa fa-fw fa-folder-o"></i>
  547. <span data-bind="text: definition.name, tooltip: {'title': path, 'placement': 'top' }"></span>
  548. </a>
  549. <!-- /ko -->
  550. <!-- ko if: parent === null -->
  551. <div>
  552. <i class="fa fa-fw fa-folder-o"></i>
  553. <span data-bind="text: path"></span>
  554. </div>
  555. <!-- /ko -->
  556. <!-- ko template: 'assist-adls-header-actions' --><!-- /ko -->
  557. </div>
  558. <div class="assist-flex-search">
  559. <div class="assist-filter"><input class="clearable" type="text" placeholder="${ _('Filter...') }" data-bind="clearable: filter, value: filter, valueUpdate: 'afterkeydown'"/></div>
  560. </div>
  561. <div class="assist-flex-fill assist-adls-scrollable" data-bind="delayedOverflow">
  562. <div data-bind="visible: ! loading() && ! hasErrors()" style="position: relative;">
  563. <!-- ko hueSpinner: { spin: loadingMore, overlay: true } --><!-- /ko -->
  564. <ul class="assist-tables" data-bind="foreachVisible: { data: entries, minHeight: 22, container: '.assist-adls-scrollable', fetchMore: $data.fetchMore.bind($data) }">
  565. <li class="assist-entry assist-table-link" style="position: relative;" data-bind="appAwareTemplateContextMenu: { template: 'hdfs-context-items', scrollContainer: '.assist-adls-scrollable' }, visibleOnHover: { override: contextPopoverVisible, 'selector': '.assist-actions' }">
  566. <div class="assist-actions table-actions" style="opacity: 0;" >
  567. <a style="padding: 0 3px;" class="inactive-action" href="javascript:void(0);" data-bind="click: showContextPopover, css: { 'blue': contextPopoverVisible }">
  568. <i class='fa fa-info' title="${ _('Details') }"></i>
  569. </a>
  570. </div>
  571. <a href="javascript:void(0)" class="assist-entry assist-table-link" data-bind="multiClick: { click: toggleOpen, dblClick: dblClick }, attr: {'title': definition.name }">
  572. <!-- ko if: definition.type === 'dir' -->
  573. <i class="fa fa-fw fa-folder-o muted valign-middle"></i>
  574. <!-- /ko -->
  575. <!-- ko if: definition.type === 'file' -->
  576. <i class="fa fa-fw fa-file-o muted valign-middle"></i>
  577. <!-- /ko -->
  578. <span draggable="true" data-bind="text: definition.name, draggableText: { text: '\'' + path + '\'', meta: {'type': 'adls', 'definition': definition} }"></span>
  579. </a>
  580. </li>
  581. </ul>
  582. <!-- ko if: !loading() && entries().length === 0 -->
  583. <ul class="assist-tables">
  584. <li class="assist-entry"><span class="assist-no-entries"><!-- ko if: filter() -->${_('No results found')}<!-- /ko --><!-- ko ifnot: filter() -->${_('Empty directory')}<!-- /ko --></span></li>
  585. </ul>
  586. <!-- /ko -->
  587. </div>
  588. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  589. <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
  590. <span>${ _('Error loading contents.') }</span>
  591. </div>
  592. </div>
  593. <!-- /ko -->
  594. </script>
  595. <script type="text/html" id="assist-document-header-actions">
  596. <div class="assist-db-header-actions">
  597. <!-- ko if: !loading() -->
  598. <div class="highlightable" data-bind="css: { 'highlight': $parent.highlightTypeFilter() }, component: { name: 'hue-drop-down', params: { fixedPosition: true, value: typeFilter, searchable: true, entries: DOCUMENT_TYPES, linkTitle: '${ _ko('Document type') }' } }" style="display: inline-block"></div>
  599. <!-- /ko -->
  600. <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.document.refresh'); }"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }" title="${_('Manual refresh')}"></i></a>
  601. </div>
  602. </script>
  603. <script type="text/html" id="assist-documents-inner-panel">
  604. <!-- ko with: activeEntry -->
  605. <div class="assist-flex-header assist-breadcrumb">
  606. <!-- ko ifnot: isRoot -->
  607. <a href="javascript: void(0);" data-bind="click: function () { if (loaded()) { parent.makeActive(); } }">
  608. <i class="fa fa-fw fa-chevron-left"></i>
  609. <i class="fa fa-fw fa-folder-o"></i>
  610. <span data-bind="text: definition().name, attr: {'title': definition().name }"></span>
  611. </a>
  612. <!-- /ko -->
  613. <!-- ko if: isRoot -->
  614. <div>
  615. <i class="fa fa-fw fa-folder-o"></i>
  616. <span>/</span>
  617. </div>
  618. <!-- /ko -->
  619. <!-- ko template: 'assist-document-header-actions' --><!-- /ko -->
  620. </div>
  621. <div class="assist-flex-search">
  622. <div class="assist-filter"><input class="clearable" type="text" placeholder="${ _('Filter...') }" data-bind="clearable: filter, value: filter, valueUpdate: 'afterkeydown'"/></div>
  623. </div>
  624. <div class="assist-flex-fill assist-file-scrollable" data-bind="delayedOverflow">
  625. <div data-bind="visible: ! loading() && ! hasErrors() && entries().length > 0">
  626. <!-- ko if: filteredEntries().length == 0 -->
  627. <ul class="assist-tables">
  628. <li class="assist-entry"><span class="assist-no-entries">${_('No documents found')}</span></li>
  629. </ul>
  630. <!-- /ko -->
  631. <ul class="assist-tables" data-bind="foreachVisible: { data: filteredEntries, minHeight: 27, container: '.assist-file-scrollable' }">
  632. <li class="assist-entry assist-file-entry" data-bind="appAwareTemplateContextMenu: { template: 'document-context-items', scrollContainer: '.assist-file-scrollable', beforeOpen: beforeContextOpen }, assistFileDroppable, assistFileDraggable, visibleOnHover: { 'selector': '.assist-file-actions' }">
  633. <div class="assist-file-actions table-actions">
  634. <a class="inactive-action" href="javascript:void(0)" data-bind="click: showContextPopover, css: { 'blue': statsVisible }"><i class="fa fa-fw fa-info" title="${_('Show details')}"></i></a>
  635. </div>
  636. <a href="javascript:void(0)" class="assist-entry assist-document-link" data-bind="click: open, attr: {'title': name }">
  637. <!-- ko template: { name: 'document-icon-template', data: { document: $data, showShareAddon: false } } --><!-- /ko -->
  638. <span class="highlightable" data-bind="css: { 'highlight': highlight }, text: definition().name"></span>
  639. </a>
  640. </li>
  641. </ul>
  642. </div>
  643. <div data-bind="visible: !loading() && ! hasErrors() && entries().length === 0">
  644. <span class="assist-no-entries">${_('Empty directory')}</span>
  645. </div>
  646. <div class="center" data-bind="visible: loading() && ! hasErrors()">
  647. <i class="fa fa-spinner fa-spin" style="font-size: 20px; color: #BBB"></i>
  648. </div>
  649. <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
  650. <span>${ _('Error loading contents.') }</span>
  651. </div>
  652. <!-- /ko -->
  653. </div>
  654. </script>
  655. <script type="text/html" id="assist-hbase-header-actions">
  656. <div class="assist-db-header-actions">
  657. <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.hbase.refresh'); }"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }" title="${_('Manual refresh')}"></i></a>
  658. </div>
  659. </script>
  660. <script type="text/html" id="assist-hbase-inner-panel">
  661. <!-- ko with: selectedHBaseEntry -->
  662. <div class="assist-inner-header assist-breadcrumb" >
  663. <!-- ko if: definition.host !== '' -->
  664. <a href="javascript: void(0);" data-bind="click: function () { huePubSub.publish('assist.clickHBaseRootItem'); }">
  665. <i class="fa fa-fw fa-chevron-left"></i>
  666. <i class="fa fa-fw fa-th-large"></i>
  667. <span data-bind="text: definition.name"></span>
  668. </a>
  669. <!-- /ko -->
  670. <!-- ko if: definition.host === '' -->
  671. ${_('Clusters')}
  672. <!-- /ko -->
  673. <!-- ko template: 'assist-hbase-header-actions' --><!-- /ko -->
  674. </div>
  675. <div class="assist-flex-fill assist-hbase-scrollable" data-bind="delayedOverflow">
  676. <div data-bind="visible: ! loading() && ! hasErrors()" style="position: relative;">
  677. <ul class="assist-tables" data-bind="foreachVisible: { data: entries, minHeight: 22, container: '.assist-hbase-scrollable' }">
  678. <li class="assist-entry assist-table-link" style="position: relative;" data-bind="appAwareTemplateContextMenu: { template: 'hbase-context-items', scrollContainer: '.assist-hbase-scrollable' }, visibleOnHover: { 'selector': '.assist-actions' }">
  679. <a href="javascript:void(0)" class="assist-entry assist-table-link" data-bind="multiClick: { click: click, dblClick: dblClick }, attr: {'title': definition.name }">
  680. <!-- ko if: definition.host -->
  681. <i class="fa fa-fw fa-th-large muted valign-middle"></i>
  682. <!-- /ko -->
  683. <!-- ko ifnot: definition.host -->
  684. <i class="fa fa-fw fa-th muted valign-middle"></i>
  685. <!-- /ko -->
  686. <span draggable="true" data-bind="text: definition.name, draggableText: { text: '\'' + definition.name + '\'', meta: {'type': 'collection', 'definition': definition} }"></span>
  687. </a>
  688. </li>
  689. </ul>
  690. <!-- ko if: !loading() && entries().length === 0 -->
  691. <ul class="assist-tables">
  692. <li class="assist-entry">
  693. <span class="assist-no-entries">
  694. <!-- ko if: definition.host === '' -->
  695. ${_('No clusters available.')}
  696. <!-- /ko -->
  697. <!-- ko if: definition.host !== '' -->
  698. ${_('No tables available.')}
  699. <!-- /ko -->
  700. </span>
  701. </li>
  702. </ul>
  703. <!-- /ko -->
  704. </div>
  705. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  706. <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
  707. <span>${ _('Error loading contents.') }</span>
  708. </div>
  709. </div>
  710. <!-- /ko -->
  711. </script>
  712. <script type="text/html" id="ask-for-invalidate-title">
  713. &nbsp;<a class="pull-right pointer close-popover inactive-action">&times;</a>
  714. </script>
  715. <script type="text/html" id="ask-for-invalidate-content">
  716. <label class="radio">
  717. <input type="radio" name="refreshImpala" value="cache" data-bind="checked: invalidateOnRefresh" />
  718. ${ _('Clear cache') }
  719. </label>
  720. <label class="radio">
  721. <input type="radio" name="refreshImpala" value="invalidate" data-bind="checked: invalidateOnRefresh" />
  722. ${ _('Perform incremental metadata update.') }
  723. </label>
  724. <div class="assist-invalidate-description">${ _('This will sync missing tables.') }</div>
  725. <label class="radio">
  726. <input type="radio" name="refreshImpala" value="invalidateAndFlush" data-bind="checked: invalidateOnRefresh" />
  727. ${ _('Invalidate all metadata and rebuild index.') }
  728. </label>
  729. <div class="assist-invalidate-description">${ _('WARNING: This can be both resource and time-intensive.') }</div>
  730. <div style="width: 100%; display: inline-block; margin-top: 5px;"><button class="pull-right btn btn-primary" data-bind="css: { 'btn-primary': invalidateOnRefresh() !== 'invalidateAndFlush', 'btn-danger': invalidateOnRefresh() === 'invalidateAndFlush' }, click: function (data, event) { huePubSub.publish('close.popover'); triggerRefresh(data, event); }, clickBubble: false">${ _('Refresh') }</button></div>
  731. </script>
  732. <script type="text/html" id="assist-namespace-header-actions">
  733. <div class="assist-db-header-actions">
  734. <!-- ko ifnot: loading -->
  735. <span class="assist-tables-counter">(<span data-bind="text: filteredNamespaces().length"></span>)</span>
  736. <!-- ko if: namespaceRefreshEnabled -->
  737. <a class="inactive-action" href="javascript:void(0)" data-bind="click: triggerRefresh"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }" title="${_('Refresh')}"></i></a>
  738. <!-- /ko -->
  739. <!-- /ko -->
  740. <!-- ko if: loading -->
  741. <i class="fa fa-refresh fa-spin blue" title="${_('Refresh')}"></i>
  742. <!-- /ko -->
  743. </div>
  744. </script>
  745. <script type="text/html" id="assist-db-header-actions">
  746. <div class="assist-db-header-actions">
  747. <!-- ko ifnot: loading -->
  748. <span class="assist-tables-counter">(<span data-bind="text: filteredEntries().length"></span>)</span>
  749. % if hasattr(ENABLE_NEW_CREATE_TABLE, 'get') and ENABLE_NEW_CREATE_TABLE.get() and not IS_EMBEDDED.get():
  750. <!-- ko if: sourceType === 'hive' || sourceType === 'impala' -->
  751. <!-- ko if: typeof databaseName !== 'undefined' -->
  752. <a class="inactive-action" data-bind="hueLink: '${ url('indexer:importer_prefill', source_type='all', target_type='table') }' + databaseName + '/?sourceType=' + sourceType" title="${_('Create table')}" href="javascript:void(0)">
  753. <i class="pointer fa fa-plus" title="${_('Create table')}"></i>
  754. </a>
  755. <!-- /ko -->
  756. <!-- ko if: typeof databases !== 'undefined' -->
  757. <a class="inactive-action" data-bind="hueLink: '${ url('indexer:importer_prefill', source_type='manual', target_type='database') }' + '/?sourceType=' + sourceType" href="javascript:void(0)">
  758. <i class="pointer fa fa-plus" title="${ _('Create database') }"></i>
  759. </a>
  760. <!-- /ko -->
  761. <!-- /ko -->
  762. % endif
  763. <!-- ko if: sourceType === 'solr' -->
  764. <a class="inactive-action" data-bind="hueLink: '/indexer/importer/prefill/all/index/'" title="${_('Create index')}">
  765. <i class="pointer fa fa-plus" title="${_('Create index')}"></i>
  766. </a>
  767. <!-- /ko -->
  768. <!-- ko if: sourceType === 'impala' -->
  769. <a class="inactive-action" href="javascript:void(0)" data-bind="templatePopover : { contentTemplate: 'ask-for-invalidate-content', titleTemplate: 'ask-for-invalidate-title', trigger: 'click', minWidth: '320px' }"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }" title="${_('Refresh')}"></i></a>
  770. <!-- /ko -->
  771. <!-- ko if: sourceType !== 'impala' -->
  772. <a class="inactive-action" href="javascript:void(0)" data-bind="click: triggerRefresh"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }" title="${_('Refresh')}"></i></a>
  773. <!-- /ko -->
  774. <!-- /ko -->
  775. <!-- ko if: loading -->
  776. <i class="fa fa-refresh fa-spin blue" title="${_('Refresh')}"></i>
  777. <!-- /ko -->
  778. </div>
  779. </script>
  780. <script type="text/html" id="assist-sources-template">
  781. <div class="assist-flex-header">
  782. <div class="assist-inner-header">
  783. ${_('Sources')}
  784. </div>
  785. </div>
  786. <div class="assist-flex-fill">
  787. <ul class="assist-tables" data-bind="foreach: sources">
  788. <li class="assist-table">
  789. <a class="assist-table-link" href="javascript: void(0);" data-bind="click: function () { $parent.selectedSource($data); }"><i class="fa fa-fw fa-server muted valign-middle"></i> <span data-bind="text: name"></span></a>
  790. </li>
  791. </ul>
  792. </div>
  793. </script>
  794. <script type="text/html" id="assist-namespaces-template">
  795. <div class="assist-flex-header">
  796. <div class="assist-inner-header">
  797. ${_('Namespaces')}
  798. <!-- ko template: 'assist-namespace-header-actions' --><!-- /ko -->
  799. </div>
  800. </div>
  801. <div class="assist-flex-search" data-bind="visible: hasNamespaces() && !hasErrors()">
  802. <div class="assist-filter">
  803. <!-- ko component: {
  804. name: 'inline-autocomplete',
  805. params: {
  806. querySpec: filter.querySpec,
  807. facets: [],
  808. knownFacetValues: {},
  809. autocompleteFromEntries: autocompleteFromNamespaces
  810. }
  811. } --><!-- /ko -->
  812. </div>
  813. </div>
  814. <div class="assist-flex-fill assist-db-scrollable" data-bind="visible: !hasErrors() && !loading() && hasNamespaces(), delayedOverflow">
  815. <!-- ko if: !loading() && filteredNamespaces().length == 0 -->
  816. <ul class="assist-tables">
  817. <li class="assist-entry no-entries">${_('No results found')}</li>
  818. </ul>
  819. <!-- /ko -->
  820. <ul class="assist-tables" data-bind="foreach: filteredNamespaces">
  821. <li class="assist-table">
  822. <!-- ko if: namespace.computes.length -->
  823. <a class="assist-table-link" href="javascript: void(0);" data-bind="click: function () { $parent.selectedNamespace($data); }"><i class="fa fa-fw fa-snowflake-o muted valign-middle"></i> <span data-bind="text: name"></span></a>
  824. <!-- /ko -->
  825. <!-- ko ifnot: namespace.computes.length -->
  826. <span class="assist-table-link" title="${_('No related computes')}" data-bind="tooltip: { placement: 'bottom' }"><i class="fa fa-fw fa-warning muted valign-middle"></i> <span data-bind="text: name"></span></span>
  827. <!-- /ko -->
  828. </li>
  829. </ul>
  830. </div>
  831. <div class="assist-flex-fill" data-bind="visible: loading">
  832. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  833. </div>
  834. <div class="assist-flex-fill" data-bind="visible: hasErrors() && !loading()">
  835. <span class="assist-errors">${ _('Error loading namespaces.') }</span>
  836. </div>
  837. <div class="assist-flex-fill" data-bind="visible: !hasErrors() && !loading() && !hasNamespaces()">
  838. <span class="assist-errors">${ _('No namespaces found.') }</span>
  839. </div>
  840. </script>
  841. <script type="text/html" id="assist-databases-template">
  842. <div class="assist-flex-header" data-bind="visibleOnHover: { selector: '.hover-actions', override: loading() }">
  843. <div class="assist-inner-header">
  844. <!-- ko ifnot: sourceType === 'solr' || sourceType === 'kafka' -->
  845. ${_('Databases')}
  846. <!-- ko template: 'assist-db-header-actions' --><!-- /ko -->
  847. <!-- /ko -->
  848. <!-- ko if: sourceType === 'solr' || sourceType === 'kafka'-->
  849. ${_('Sources')}
  850. <!-- /ko -->
  851. </div>
  852. </div>
  853. <div class="assist-flex-search" data-bind="visible: hasEntries() && ! hasErrors()">
  854. <div class="assist-filter">
  855. <!-- ko component: {
  856. name: 'inline-autocomplete',
  857. params: {
  858. querySpec: filter.querySpec,
  859. facets: [],
  860. knownFacetValues: {},
  861. autocompleteFromEntries: autocompleteFromEntries
  862. }
  863. } --><!-- /ko -->
  864. </div>
  865. </div>
  866. <div class="assist-flex-fill assist-db-scrollable" data-bind="visible: ! hasErrors() && ! loading() && hasEntries(), delayedOverflow">
  867. <!-- ko if: ! loading() && filteredEntries().length == 0 -->
  868. <ul class="assist-tables">
  869. <li class="assist-entry no-entries">${_('No results found')}</li>
  870. </ul>
  871. <!-- /ko -->
  872. <ul class="assist-tables" data-bind="foreachVisible: {data: filteredEntries, minHeight: 23, container: '.assist-db-scrollable', skipScrollEvent: navigationSettings.rightAssist }">
  873. <!-- ko template: { name: 'assist-database-entry' } --><!-- /ko -->
  874. </ul>
  875. </div>
  876. <div class="assist-flex-fill" data-bind="visible: loading">
  877. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  878. </div>
  879. <div class="assist-flex-fill" data-bind="visible: hasErrors() && ! loading()">
  880. <span class="assist-errors">${ _('Error loading databases.') }</span>
  881. </div>
  882. <div class="assist-flex-fill" data-bind="visible: ! hasErrors() && ! loading() && ! hasEntries()">
  883. <span class="assist-errors">${ _('No databases found.') }</span>
  884. </div>
  885. </script>
  886. <script type="text/html" id="assist-tables-template">
  887. <div class="assist-flex-header">
  888. <div class="assist-inner-header" data-bind="visible: !$parent.loading() && !$parent.hasErrors()">
  889. <!-- ko ifnot: sourceType === 'solr' || sourceType === 'kafka' -->
  890. ${_('Tables')}
  891. <!-- /ko -->
  892. <!-- ko if: sourceType === 'solr' -->
  893. <div data-bind="appAwareTemplateContextMenu: { template: 'collection-title-context-items', scrollContainer: '.assist-db-scrollable' }">${_('Indexes')}</div>
  894. <!-- /ko -->
  895. <!-- ko if: sourceType === 'kafka' -->
  896. ${_('Topics')}
  897. <!-- /ko -->
  898. <!-- ko template: 'assist-db-header-actions' --><!-- /ko -->
  899. </div>
  900. </div>
  901. <div class="assist-flex-search" data-bind="visible: hasEntries() && !$parent.loading() && !$parent.hasErrors()">
  902. <div class="assist-filter">
  903. <!-- ko component: {
  904. name: 'inline-autocomplete',
  905. params: {
  906. querySpec: filter.querySpec,
  907. facets: ['type'],
  908. knownFacetValues: knownFacetValues.bind($data),
  909. autocompleteFromEntries: autocompleteFromEntries
  910. }
  911. } --><!-- /ko -->
  912. </div>
  913. </div>
  914. <div class="assist-flex-fill assist-db-scrollable" data-bind="visible: ! hasErrors() && ! loading(), delayedOverflow">
  915. <!-- ko template: 'assist-db-entries' --><!-- /ko -->
  916. </div>
  917. <div class="assist-flex-fill" data-bind="visible: loading() || $parent.loading()">
  918. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  919. </div>
  920. <div class="assist-flex-fill" data-bind="visible: hasErrors() && ! loading()">
  921. <span class="assist-errors">${ _('Error loading tables.') }</span>
  922. </div>
  923. </script>
  924. <script type="text/html" id="assist-panel-inner-header">
  925. <div class="assist-header assist-fixed-height" data-bind="visibleOnHover: { selector: '.assist-header-actions' }, css: { 'assist-resizer': $index() > 0 }" style="display:none;">
  926. <span data-bind="text: $parent.name"></span>
  927. <div class="assist-header-actions">
  928. <div class="inactive-action" data-bind="click: function () { $parent.visible(false) }"><i class="fa fa-times"></i></div>
  929. </div>
  930. </div>
  931. </script>
  932. <script type="text/html" id="assist-panel-template">
  933. <div class="assist-panel" data-bind="dropzone: { url: '/filebrowser/upload/file?dest=' + DROPZONE_HOME_DIR, params: {dest: DROPZONE_HOME_DIR}, paramName: 'hdfs_file', onComplete: function(path){ huePubSub.publish('assist.dropzone.complete', path); } }">
  934. <!-- ko if: availablePanels().length > 1 -->
  935. <div class="assist-panel-switches">
  936. <!-- ko foreach: availablePanels -->
  937. <div class="inactive-action assist-type-switch" data-bind="click: function () { $parent.visiblePanel($data); }, css: { 'blue': $parent.visiblePanel() === $data }, style: { 'float': rightAlignIcon ? 'right' : 'left' }, attr: { 'title': name }">
  938. <!-- ko if: iconSvg --><span style="font-size:22px;"><svg class="hi"><use data-bind="attr: {'xlink:href': iconSvg }" xlink:href=''></use></svg></span><!-- /ko -->
  939. <!-- ko if: !iconSvg --><i class="fa fa-fw valign-middle" data-bind="css: icon"></i><!-- /ko -->
  940. </div>
  941. <!-- /ko -->
  942. </div>
  943. <!-- /ko -->
  944. <!-- ko with: visiblePanel -->
  945. <div class="assist-panel-contents" data-bind="style: { 'padding-top': $parent.availablePanels().length > 1 ? '10px' : '5px' }">
  946. <div class="assist-inner-panel">
  947. <div class="assist-flex-panel">
  948. <!-- ko template: { name: templateName, data: panelData } --><!-- /ko -->
  949. </div>
  950. </div>
  951. </div>
  952. <!-- /ko -->
  953. </div>
  954. </script>
  955. <div class="assist-file-entry-drag">
  956. <span class="drag-text"></span>
  957. </div>
  958. <script type="text/javascript">
  959. var SQL_ASSIST_KNOWN_FACET_VALUES = {
  960. 'type': {'array': -1, 'table': -1, 'view': -1, 'boolean': -1, 'bigint': -1, 'binary': -1, 'char': -1, 'date': -1, 'double': -1, 'decimal': -1, 'float': -1, 'int': -1, 'map': -1, 'real': -1, 'smallint': -1, 'string': -1, 'struct': -1, 'timestamp': -1, 'tinyint': -1, 'varchar': -1 }
  961. };
  962. var SOLR_ASSIST_KNOWN_FACET_VALUES = {
  963. 'type': {'date': -1, 'tdate': -1, 'timestamp': -1, 'pdate': -1, 'int': -1, 'tint': -1, 'pint': -1, 'long': -1, 'tlong': -1, 'plong': -1, 'float': -1, 'tfloat': -1, 'pfloat': -1, 'double': -1, 'tdouble': -1, 'pdouble': -1, 'currency': -1, 'smallint': -1, 'bigint': -1, 'tinyint': -1, 'SpatialRecursivePrefixTreeFieldType': -1, 'string': -1, 'boolean': -1 }
  964. };
  965. (function () {
  966. ko.bindingHandlers.assistFileDroppable = {
  967. init: function(element, valueAccessor, allBindings, boundEntry) {
  968. var dragData;
  969. var dragSub = huePubSub.subscribe('doc.browser.dragging', function (data) {
  970. dragData = data;
  971. });
  972. ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
  973. dragSub.remove();
  974. });
  975. var $element = $(element);
  976. if (boundEntry.isDirectory) {
  977. $element.droppable({
  978. drop: function () {
  979. if (dragData && !dragData.dragToSelect && boundEntry.isDirectory()) {
  980. boundEntry.moveHere(dragData.selectedEntries);
  981. dragData.originEntry.load();
  982. }
  983. $element.removeClass('assist-file-entry-drop');
  984. },
  985. over: function () {
  986. if (!$element.hasClass('assist-file-entry-drop') && dragData && !dragData.dragToSelect && boundEntry.isDirectory()) {
  987. $element.addClass('assist-file-entry-drop');
  988. }
  989. },
  990. out: function () {
  991. $element.removeClass('assist-file-entry-drop');
  992. }
  993. })
  994. }
  995. }
  996. };
  997. ko.bindingHandlers.assistFileDraggable = {
  998. init: function(element, valueAccessor, allBindings, boundEntry, bindingContext) {
  999. var $element = $(element);
  1000. var dragStartY = -1;
  1001. var dragStartX = -1;
  1002. $element.draggable({
  1003. start: function (event, ui) {
  1004. var $container = $('.doc-browser-drag-container');
  1005. boundEntry.selected(true);
  1006. huePubSub.publish('doc.browser.dragging', {
  1007. selectedEntries: [ boundEntry ],
  1008. originEntry: boundEntry,
  1009. dragToSelect: false
  1010. });
  1011. huePubSub.publish('doc.drag.to.select', false);
  1012. dragStartX = event.clientX;
  1013. dragStartY = event.clientY;
  1014. var $helper = $('.assist-file-entry-drag').clone().show();
  1015. $helper.find('.drag-text').text(boundEntry.definition().name);
  1016. $helper.find('i').removeClass().addClass($element.find('.doc-browser-primary-col i').attr('class'));
  1017. $helper.appendTo($container);
  1018. },
  1019. drag: function (event) {
  1020. },
  1021. stop: function (event) {
  1022. var elementAtStart = document.elementFromPoint(dragStartX, dragStartY);
  1023. var elementAtStop = document.elementFromPoint(event.clientX, event.clientY);
  1024. if (elementAtStart.nodeName === "A" && elementAtStop.nodeName === "A" && Math.sqrt((dragStartX-event.clientX)*(dragStartX-event.clientX) + (dragStartY-event.clientY)*(dragStartY-event.clientY)) < 8) {
  1025. $(elementAtStop).trigger('click');
  1026. }
  1027. boundEntry.selected(false);
  1028. },
  1029. helper: function (event) {
  1030. return $('<div>').addClass('doc-browser-drag-container');
  1031. },
  1032. appendTo: "body",
  1033. cursorAt: {
  1034. top: 0,
  1035. left: 0
  1036. }
  1037. });
  1038. }
  1039. };
  1040. /**
  1041. * @param {Object} options
  1042. * @param {ApiHelper} options.apiHelper
  1043. * @param {string} options.type
  1044. * @param {number} options.minHeight
  1045. * @param {string} options.icon
  1046. * @param {boolean} [options.rightAlignIcon] - Default false
  1047. * @param {boolean} options.visible
  1048. * @param {(AssistDbPanel|AssistHdfsPanel|AssistGitPanel|AssistDocumentsPanel|AssistS3Panel)} panelData
  1049. * @constructor
  1050. */
  1051. function AssistInnerPanel (options) {
  1052. var self = this;
  1053. self.minHeight = options.minHeight;
  1054. self.icon = options.icon;
  1055. self.type = options.type;
  1056. self.name = options.name;
  1057. self.panelData = options.panelData;
  1058. self.rightAlignIcon = !!options.rightAlignIcon;
  1059. self.iconSvg = options.iconSvg;
  1060. self.visible = ko.observable(options.visible || true);
  1061. options.apiHelper.withTotalStorage('assist', 'showingPanel_' + self.type, self.visible, false, options.visible);
  1062. self.templateName = 'assist-' + self.type + '-inner-panel';
  1063. var loadWhenVisible = function () {
  1064. if (! self.visible()) {
  1065. return;
  1066. }
  1067. if (self.type === 'documents' && !self.panelData.activeEntry().loaded()) {
  1068. self.panelData.activeEntry().load();
  1069. }
  1070. };
  1071. self.visible.subscribe(loadWhenVisible);
  1072. loadWhenVisible();
  1073. }
  1074. /**
  1075. * @param {Object} options
  1076. * @param {ApiHelper} options.apiHelper
  1077. * @param {Object} options.i18n
  1078. * @param {Object[]} options.sourceTypes - All the available SQL source types
  1079. * @param {string} options.sourceTypes[].name - Example: Hive SQL
  1080. * @param {string} options.sourceTypes[].type - Example: hive
  1081. * @param {string} [options.activeSourceType] - Example: hive
  1082. * @param {Object} options.navigationSettings - enable/disable the links
  1083. * @param {boolean} options.navigationSettings.openItem
  1084. * @param {boolean} options.navigationSettings.showStats
  1085. * @param {boolean} options.navigationSettings.pinEnabled
  1086. * @constructor
  1087. **/
  1088. function AssistDbPanel(options) {
  1089. var self = this;
  1090. self.options = options;
  1091. self.apiHelper = options.apiHelper;
  1092. self.i18n = options.i18n;
  1093. self.initialized = false;
  1094. self.initalizing = false;
  1095. if (typeof options.sourceTypes === 'undefined') {
  1096. options.sourceTypes = [];
  1097. if (options.isSolr) {
  1098. options.sourceTypes = [{
  1099. type: 'solr',
  1100. name: 'solr'
  1101. }];
  1102. } else if (options.isKafka) {
  1103. options.sourceTypes = [{
  1104. type: 'kafka',
  1105. name: 'kafka'
  1106. }];
  1107. } else {
  1108. % for interpreter in get_ordered_interpreters(request.user):
  1109. % if interpreter["is_sql"]:
  1110. options.sourceTypes.push({
  1111. type: '${ interpreter["type"] }',
  1112. name: '${ interpreter["name"] }'
  1113. });
  1114. % endif
  1115. % endfor
  1116. }
  1117. }
  1118. self.sources = ko.observableArray();
  1119. self.sourceIndex = {};
  1120. self.selectedSource = ko.observable(null);
  1121. self.setDatabaseWhenLoaded = function (namespace, databaseName) {
  1122. self.selectedSource().whenLoaded(function () {
  1123. if (self.selectedSource().selectedNamespace() && self.selectedSource().selectedNamespace().namespace.id !== namespace.id) {
  1124. self.selectedSource().namespaces().some(function (otherNamespace) {
  1125. if (otherNamespace.namespace.id === namespace.id) {
  1126. self.selectedSource().selectedNamespace(otherNamespace);
  1127. return true;
  1128. }
  1129. })
  1130. }
  1131. if (self.selectedSource().selectedNamespace()) {
  1132. self.selectedSource().selectedNamespace().whenLoaded(function () {
  1133. self.selectedSource().selectedNamespace().setDatabase(databaseName);
  1134. })
  1135. }
  1136. });
  1137. };
  1138. options.sourceTypes.forEach(function (sourceType) {
  1139. self.sourceIndex[sourceType.type] = new AssistDbSource({
  1140. apiHelper: self.apiHelper,
  1141. i18n: self.i18n,
  1142. type: sourceType.type,
  1143. name: sourceType.name,
  1144. navigationSettings: options.navigationSettings
  1145. });
  1146. self.sources.push(self.sourceIndex[sourceType.type]);
  1147. });
  1148. huePubSub.subscribe('assist.collections.refresh', function() {
  1149. DataCatalog.getEntry({ sourceType: 'solr', namespace: self.sourceIndex['solr'].activeNamespace(), compute: self.sourceIndex['solr'].activeCompute(), path: [] }).done(function (entry) {
  1150. entry.clearCache({ cascade: true });
  1151. });
  1152. });
  1153. huePubSub.subscribe('assist.db.highlight', function (location) {
  1154. huePubSub.publish('left.assist.show');
  1155. if (location.sourceType === 'solr') {
  1156. huePubSub.publish('assist.show.solr');
  1157. }
  1158. else {
  1159. huePubSub.publish('assist.show.sql');
  1160. }
  1161. huePubSub.publish('context.popover.hide');
  1162. window.setTimeout(function () {
  1163. var foundSource;
  1164. $.each(self.sources(), function (idx, source) {
  1165. if (source.sourceType === location.sourceType) {
  1166. foundSource = source;
  1167. return false;
  1168. }
  1169. });
  1170. if (foundSource) {
  1171. var whenLoaded = function () {
  1172. if (self.selectedSource() !== foundSource) {
  1173. self.selectedSource(foundSource);
  1174. }
  1175. foundSource.highlightInside(location.path);
  1176. };
  1177. if (foundSource.hasEntries()) {
  1178. whenLoaded();
  1179. } else {
  1180. foundSource.initDatabases(whenLoaded);
  1181. }
  1182. }
  1183. }, 0);
  1184. });
  1185. if (!options.isSolr) {
  1186. huePubSub.subscribe('assist.set.database', function (databaseDef) {
  1187. if (!databaseDef.source || !self.sourceIndex[databaseDef.source]) {
  1188. return;
  1189. }
  1190. self.selectedSource(self.sourceIndex[databaseDef.source]);
  1191. self.setDatabaseWhenLoaded(databaseDef.namespace, databaseDef.name);
  1192. });
  1193. var getSelectedDatabase = function (source) {
  1194. var deferred = $.Deferred();
  1195. var assistDbSource = self.sourceIndex[source];
  1196. if (assistDbSource) {
  1197. assistDbSource.loadedDeferred.done(function () {
  1198. if (assistDbSource.selectedNamespace()) {
  1199. assistDbSource.selectedNamespace().loadedDeferred.done(function () {
  1200. assistDbSource.selectedNamespace().namespace
  1201. if (assistDbSource.selectedNamespace().selectedDatabase()) {
  1202. deferred.resolve({
  1203. sourceType: source,
  1204. namespace: assistDbSource.selectedNamespace().namespace,
  1205. name: assistDbSource.selectedNamespace().selectedDatabase()
  1206. })
  1207. } else {
  1208. deferred.resolve({
  1209. sourceType: source,
  1210. namespace: assistDbSource.selectedNamespace().namespace,
  1211. name: 'default'
  1212. })
  1213. }
  1214. });
  1215. } else {
  1216. deferred.resolve({
  1217. sourceType: source,
  1218. namespace: { id: 'default' },
  1219. name: 'default'
  1220. });
  1221. }
  1222. })
  1223. } else {
  1224. deferred.reject()
  1225. }
  1226. return deferred;
  1227. };
  1228. huePubSub.subscribe('assist.get.database', function (source) {
  1229. getSelectedDatabase(source).done(function (databaseDef) {
  1230. huePubSub.publish('assist.database.set', databaseDef);
  1231. })
  1232. });
  1233. huePubSub.subscribe('assist.get.database.callback', function (options) {
  1234. getSelectedDatabase(options.source).done(options.callback);
  1235. });
  1236. huePubSub.subscribe('assist.get.source', function () {
  1237. huePubSub.publish('assist.source.set', self.selectedSource() ? self.selectedSource().sourceType : undefined);
  1238. });
  1239. huePubSub.subscribe('assist.set.source', function (source) {
  1240. if (self.sourceIndex[source]) {
  1241. self.selectedSource(self.sourceIndex[source]);
  1242. }
  1243. });
  1244. huePubSub.publish('assist.db.panel.ready');
  1245. huePubSub.subscribe('assist.is.db.panel.ready', function () {
  1246. huePubSub.publish('assist.db.panel.ready');
  1247. });
  1248. self.selectedSource.subscribe(function (newSource) {
  1249. if (newSource) {
  1250. if (newSource.namespaces().length === 0) {
  1251. newSource.loadNamespaces();
  1252. }
  1253. self.apiHelper.setInTotalStorage('assist', 'lastSelectedSource', newSource.sourceType);
  1254. } else {
  1255. self.apiHelper.setInTotalStorage('assist', 'lastSelectedSource');
  1256. }
  1257. });
  1258. }
  1259. self.breadcrumb = ko.computed(function () {
  1260. if (self.selectedSource()) {
  1261. if (self.selectedSource().selectedNamespace()) {
  1262. if (self.selectedSource().selectedNamespace().selectedDatabase()) {
  1263. return self.selectedSource().selectedNamespace().selectedDatabase().catalogEntry.name
  1264. }
  1265. if (self.selectedSource().namespaceRefreshEnabled() || self.selectedSource().namespaces().length > 1) {
  1266. return self.selectedSource().selectedNamespace().name
  1267. }
  1268. }
  1269. return self.selectedSource().name;
  1270. }
  1271. return null;
  1272. });
  1273. }
  1274. AssistDbPanel.prototype.back = function () {
  1275. var self = this;
  1276. if (self.selectedSource()) {
  1277. if (self.selectedSource() && self.selectedSource().selectedNamespace()) {
  1278. if (self.selectedSource().selectedNamespace().selectedDatabase()) {
  1279. self.selectedSource().selectedNamespace().selectedDatabase(null);
  1280. } else if (self.selectedSource().namespaceRefreshEnabled() || self.selectedSource().namespaces().length > 1) {
  1281. self.selectedSource().selectedNamespace(null)
  1282. } else {
  1283. self.selectedSource(null);
  1284. }
  1285. } else {
  1286. self.selectedSource(null);
  1287. }
  1288. }
  1289. };
  1290. AssistDbPanel.prototype.init = function () {
  1291. var self = this;
  1292. if (self.initialized) {
  1293. return;
  1294. }
  1295. if (self.options.isSolr) {
  1296. self.selectedSource(self.sourceIndex['solr']);
  1297. } else {
  1298. var storageSourceType = self.apiHelper.getFromTotalStorage('assist', 'lastSelectedSource');
  1299. if (!self.selectedSource()) {
  1300. if (self.options.activeSourceType) {
  1301. self.selectedSource(self.sourceIndex[self.options.activeSourceType]);
  1302. } else if (storageSourceType && self.sourceIndex[storageSourceType]) {
  1303. self.selectedSource(self.sourceIndex[storageSourceType]);
  1304. }
  1305. }
  1306. }
  1307. self.initialized = true;
  1308. };
  1309. /**
  1310. * @param {Object} options
  1311. * @param {ApiHelper} options.apiHelper
  1312. * @param {string} options.user
  1313. * @constructor
  1314. **/
  1315. function AssistDocumentsPanel (options) {
  1316. var self = this;
  1317. self.apiHelper = options.apiHelper;
  1318. self.user = options.user;
  1319. self.activeEntry = ko.observable();
  1320. self.activeSort = ko.observable('defaultAsc');
  1321. self.typeFilter = ko.observable(DOCUMENT_TYPES[0]); // all is first
  1322. self.highlightTypeFilter = ko.observable(false);
  1323. var lastOpenedUuid = self.apiHelper.getFromTotalStorage('assist', 'last.opened.assist.doc.uuid');
  1324. if (lastOpenedUuid) {
  1325. self.activeEntry(new HueFileEntry({
  1326. activeEntry: self.activeEntry,
  1327. trashEntry: ko.observable(),
  1328. apiHelper: self.apiHelper,
  1329. app: 'documents',
  1330. user: self.user,
  1331. activeSort: self.activeSort,
  1332. typeFilter: self.typeFilter,
  1333. definition: {
  1334. uuid: lastOpenedUuid,
  1335. type: 'directory'
  1336. }
  1337. }))
  1338. } else {
  1339. self.fallbackToRoot();
  1340. }
  1341. self.activeEntry.subscribe(function (newEntry) {
  1342. if (!newEntry.loaded()) {
  1343. var loadedSub = newEntry.loaded.subscribe(function (loaded) {
  1344. if (loaded && !newEntry.hasErrors() && newEntry.definition() && newEntry.definition().uuid) {
  1345. self.apiHelper.setInTotalStorage('assist', 'last.opened.assist.doc.uuid', newEntry.definition().uuid);
  1346. }
  1347. loadedSub.dispose();
  1348. })
  1349. } else if (!newEntry.hasErrors() && newEntry.definition() && newEntry.definition().uuid) {
  1350. self.apiHelper.setInTotalStorage('assist', 'last.opened.assist.doc.uuid', newEntry.definition().uuid);
  1351. }
  1352. });
  1353. self.reload = function () {
  1354. self.activeEntry().load(function () {}, function () {
  1355. self.fallbackToRoot();
  1356. });
  1357. };
  1358. huePubSub.subscribe('assist.document.refresh', function () {
  1359. huePubSub.publish('assist.clear.document.cache');
  1360. self.reload();
  1361. });
  1362. huePubSub.subscribe('assist.doc.highlight', function (details) {
  1363. huePubSub.publish('assist.show.documents');
  1364. huePubSub.publish('context.popover.hide');
  1365. var whenLoaded = $.Deferred().done(function () {
  1366. self.activeEntry().highlightInside(details.docUuid);
  1367. });
  1368. if (self.activeEntry() && self.activeEntry().definition() && self.activeEntry().definition().uuid === details.parentUuid) {
  1369. if (self.activeEntry().loaded() && !self.activeEntry().hasErrors()) {
  1370. whenLoaded.resolve();
  1371. } else {
  1372. var loadedSub = self.activeEntry().loaded.subscribe(function (newVal) {
  1373. if (newVal) {
  1374. if (!self.activeEntry().hasErrors()) {
  1375. whenLoaded.resolve();
  1376. }
  1377. whenLoaded.reject();
  1378. loadedSub.remove();
  1379. }
  1380. })
  1381. }
  1382. self.activeEntry().highlight(details.docUuid);
  1383. } else {
  1384. self.activeEntry(new HueFileEntry({
  1385. activeEntry: self.activeEntry,
  1386. trashEntry: ko.observable(),
  1387. apiHelper: self.apiHelper,
  1388. app: 'documents',
  1389. user: self.user,
  1390. activeSort: self.activeSort,
  1391. typeFilter: self.typeFilter,
  1392. definition: {
  1393. uuid: details.parentUuid,
  1394. type: 'directory'
  1395. }
  1396. }));
  1397. self.activeEntry().load(function() {
  1398. whenLoaded.resolve();
  1399. }, function () {
  1400. whenLoaded.reject();
  1401. self.fallbackToRoot();
  1402. });
  1403. }
  1404. });
  1405. }
  1406. AssistDocumentsPanel.prototype.setTypeFilter = function (newType) {
  1407. var self = this;
  1408. DOCUMENT_TYPES.some(function (docType) {
  1409. if (docType.type === newType) {
  1410. self.typeFilter(docType);
  1411. return true;
  1412. }
  1413. });
  1414. self.highlightTypeFilter(true);
  1415. window.setTimeout(function () {
  1416. self.highlightTypeFilter(false);
  1417. }, 600)
  1418. };
  1419. AssistDocumentsPanel.prototype.fallbackToRoot = function () {
  1420. var self = this;
  1421. if (!self.activeEntry() || self.activeEntry().definition() && (self.activeEntry().definition().path !== '/' || self.activeEntry().definition().uuid)) {
  1422. self.apiHelper.setInTotalStorage('assist', 'last.opened.assist.doc.uuid', null);
  1423. self.activeEntry(new HueFileEntry({
  1424. activeEntry: self.activeEntry,
  1425. trashEntry: ko.observable(),
  1426. apiHelper: self.apiHelper,
  1427. app: 'documents',
  1428. user: self.user,
  1429. activeSort: self.activeSort,
  1430. typeFilter: self.typeFilter,
  1431. definition: {
  1432. name: '/',
  1433. type: 'directory'
  1434. }
  1435. }));
  1436. self.activeEntry().load();
  1437. }
  1438. };
  1439. AssistDocumentsPanel.prototype.init = function () {
  1440. var self = this;
  1441. if (! self.activeEntry().loaded()) {
  1442. self.activeEntry().load(function () {}, function () {
  1443. self.fallbackToRoot();
  1444. }, true);
  1445. }
  1446. };
  1447. /**
  1448. * @param {Object} options
  1449. * @param {ApiHelper} options.apiHelper
  1450. * @constructor
  1451. **/
  1452. function AssistHdfsPanel (options) {
  1453. var self = this;
  1454. self.apiHelper = options.apiHelper;
  1455. self.selectedHdfsEntry = ko.observable();
  1456. self.loading = ko.observable();
  1457. self.initialized = false;
  1458. var loadPath = function (path) {
  1459. self.loading(true);
  1460. var parts = path.split('/');
  1461. parts.shift();
  1462. var currentEntry = new AssistStorageEntry({
  1463. type: 'hdfs',
  1464. definition: {
  1465. name: '/',
  1466. type: 'dir'
  1467. },
  1468. parent: null,
  1469. apiHelper: self.apiHelper
  1470. });
  1471. currentEntry.loadDeep(parts, function (entry) {
  1472. self.selectedHdfsEntry(entry);
  1473. entry.open(true);
  1474. self.loading(false);
  1475. });
  1476. };
  1477. self.reload = function () {
  1478. loadPath(self.apiHelper.getFromTotalStorage('assist', 'currentHdfsPath', '${ home_dir }'));
  1479. };
  1480. huePubSub.subscribe('assist.hdfs.go.home', function () {
  1481. loadPath('${ home_dir }');
  1482. self.apiHelper.setInTotalStorage('assist', 'currentHdfsPath', '${ home_dir }');
  1483. });
  1484. huePubSub.subscribe('assist.selectHdfsEntry', function (entry) {
  1485. self.selectedHdfsEntry(entry);
  1486. self.apiHelper.setInTotalStorage('assist', 'currentHdfsPath', entry.path);
  1487. });
  1488. huePubSub.subscribe('assist.hdfs.refresh', function () {
  1489. huePubSub.publish('assist.clear.hdfs.cache');
  1490. self.reload();
  1491. });
  1492. }
  1493. AssistHdfsPanel.prototype.init = function () {
  1494. var self = this;
  1495. if (self.initialized) {
  1496. return;
  1497. }
  1498. self.reload();
  1499. self.initialized = true;
  1500. };
  1501. function AssistAdlsPanel (options) {
  1502. var self = this;
  1503. self.apiHelper = options.apiHelper;
  1504. self.selectedAdlsEntry = ko.observable();
  1505. self.loading = ko.observable();
  1506. self.initialized = false;
  1507. var loadPath = function (path) {
  1508. self.loading(true);
  1509. var parts = path.split('/');
  1510. parts.shift();
  1511. var currentEntry = new AssistStorageEntry({
  1512. type: 'adls',
  1513. definition: {
  1514. name: '/',
  1515. type: 'dir'
  1516. },
  1517. parent: null,
  1518. apiHelper: self.apiHelper
  1519. });
  1520. currentEntry.loadDeep(parts, function (entry) {
  1521. self.selectedAdlsEntry(entry);
  1522. entry.open(true);
  1523. self.loading(false);
  1524. });
  1525. };
  1526. self.reload = function () {
  1527. loadPath(self.apiHelper.getFromTotalStorage('assist', 'currentAdlsPath', '/'));
  1528. };
  1529. huePubSub.subscribe('assist.adls.go.home', function () {
  1530. loadPath('${ home_dir }');
  1531. self.apiHelper.setInTotalStorage('assist', 'currentAdlsPath', '${ home_dir }');
  1532. });
  1533. huePubSub.subscribe('assist.selectAdlsEntry', function (entry) {
  1534. self.selectedAdlsEntry(entry);
  1535. self.apiHelper.setInTotalStorage('assist', 'currentAdlsPath', entry.path);
  1536. });
  1537. huePubSub.subscribe('assist.adls.refresh', function () {
  1538. huePubSub.publish('assist.clear.adls.cache');
  1539. self.reload();
  1540. });
  1541. }
  1542. AssistAdlsPanel.prototype.init = function () {
  1543. var self = this;
  1544. if (self.initialized) {
  1545. return;
  1546. }
  1547. self.reload();
  1548. self.initialized = true;
  1549. };
  1550. /**
  1551. * @param {Object} options
  1552. * @param {ApiHelper} options.apiHelper
  1553. * @constructor
  1554. **/
  1555. function AssistGitPanel (options) {
  1556. var self = this;
  1557. self.apiHelper = ApiHelper.getInstance();
  1558. self.selectedGitEntry = ko.observable();
  1559. self.reload = function () {
  1560. var lastKnownPath = self.apiHelper.getFromTotalStorage('assist', 'currentGitPath', '${ home_dir }');
  1561. var parts = lastKnownPath.split('/');
  1562. parts.shift();
  1563. var currentEntry = new AssistGitEntry({
  1564. definition: {
  1565. name: '/',
  1566. type: 'dir'
  1567. },
  1568. parent: null,
  1569. apiHelper: self.apiHelper
  1570. });
  1571. currentEntry.loadDeep(parts, function (entry) {
  1572. self.selectedGitEntry(entry);
  1573. entry.open(true);
  1574. });
  1575. };
  1576. huePubSub.subscribe('assist.selectGitEntry', function (entry) {
  1577. self.selectedGitEntry(entry);
  1578. self.apiHelper.setInTotalStorage('assist', 'currentGitPath', entry.path);
  1579. });
  1580. huePubSub.subscribe('assist.git.refresh', function () {
  1581. huePubSub.publish('assist.clear.git.cache');
  1582. self.reload();
  1583. });
  1584. }
  1585. AssistGitPanel.prototype.init = function () {
  1586. this.reload();
  1587. };
  1588. /**
  1589. * @param {Object} options
  1590. * @param {ApiHelper} options.apiHelper
  1591. * @constructor
  1592. **/
  1593. function AssistS3Panel (options) {
  1594. var self = this;
  1595. self.apiHelper = options.apiHelper;
  1596. self.selectedS3Entry = ko.observable();
  1597. self.loading = ko.observable();
  1598. self.initialized = false;
  1599. self.reload = function () {
  1600. self.loading(true);
  1601. var lastKnownPath = self.apiHelper.getFromTotalStorage('assist', 'currentS3Path', '/');
  1602. var parts = lastKnownPath.split('/');
  1603. parts.shift();
  1604. var currentEntry = new AssistStorageEntry({
  1605. type: 's3',
  1606. definition: {
  1607. name: '/',
  1608. type: 'dir'
  1609. },
  1610. parent: null,
  1611. apiHelper: self.apiHelper
  1612. });
  1613. currentEntry.loadDeep(parts, function (entry) {
  1614. self.selectedS3Entry(entry);
  1615. entry.open(true);
  1616. self.loading(false);
  1617. });
  1618. };
  1619. huePubSub.subscribe('assist.selectS3Entry', function (entry) {
  1620. self.selectedS3Entry(entry);
  1621. self.apiHelper.setInTotalStorage('assist', 'currentS3Path', entry.path);
  1622. });
  1623. huePubSub.subscribe('assist.s3.refresh', function () {
  1624. huePubSub.publish('assist.clear.s3.cache');
  1625. self.reload();
  1626. });
  1627. }
  1628. AssistS3Panel.prototype.init = function () {
  1629. var self = this;
  1630. if (self.initialized) {
  1631. return;
  1632. }
  1633. self.reload();
  1634. self.initialized = true;
  1635. };
  1636. /**
  1637. * @param {Object} options
  1638. * @param {ApiHelper} options.apiHelper
  1639. * @constructor
  1640. **/
  1641. function AssistHBasePanel(options) {
  1642. var self = this;
  1643. self.apiHelper = options.apiHelper;
  1644. self.initialized = false;
  1645. var root = new AssistHBaseEntry({
  1646. definition: {
  1647. host: '',
  1648. name: '',
  1649. port: 0
  1650. },
  1651. apiHelper: self.apiHelper
  1652. });
  1653. self.selectedHBaseEntry = ko.observable();
  1654. self.reload = function () {
  1655. self.selectedHBaseEntry(root);
  1656. root.loadEntries(function () {
  1657. var lastOpenendPath = self.apiHelper.getFromTotalStorage('assist', 'last.opened.hbase.entry', null);
  1658. if (lastOpenendPath) {
  1659. root.entries().every(function (entry) {
  1660. if (entry.path === lastOpenendPath) {
  1661. entry.open();
  1662. return false;
  1663. }
  1664. return true;
  1665. })
  1666. }
  1667. });
  1668. };
  1669. self.selectedHBaseEntry.subscribe(function (newEntry) {
  1670. if (newEntry !== root || (newEntry === root && newEntry.loaded)) {
  1671. self.apiHelper.setInTotalStorage('assist', 'last.opened.hbase.entry', newEntry.path);
  1672. }
  1673. });
  1674. huePubSub.subscribe('assist.clickHBaseItem', function (entry) {
  1675. if (entry.definition.host) {
  1676. entry.loadEntries();
  1677. self.selectedHBaseEntry(entry);
  1678. }
  1679. else {
  1680. huePubSub.publish('assist.dblClickHBaseItem', entry);
  1681. }
  1682. });
  1683. huePubSub.subscribe('assist.clickHBaseRootItem', function (entry) {
  1684. self.reload();
  1685. });
  1686. var delayChangeHash = function (hash) {
  1687. window.setTimeout(function () {
  1688. window.location.hash = hash;
  1689. }, 0);
  1690. }
  1691. self.lastClickeHBaseEntry = null;
  1692. self.HBaseLoaded = false;
  1693. huePubSub.subscribeOnce('hbase.app.loaded', function() {
  1694. if (self.selectedHBaseEntry() && self.lastClickeHBaseEntry) {
  1695. delayChangeHash(self.selectedHBaseEntry().definition.name + '/' + self.lastClickeHBaseEntry.definition.name);
  1696. }
  1697. self.HBaseLoaded = true;
  1698. });
  1699. huePubSub.subscribe('assist.dblClickHBaseItem', function (entry) {
  1700. var hash = self.selectedHBaseEntry().definition.name + '/' + entry.definition.name;
  1701. if (IS_HUE_4) {
  1702. if (window.location.pathname.startsWith('/hue/hbase')) {
  1703. window.location.hash = hash;
  1704. }
  1705. else {
  1706. self.lastClickeHBaseEntry = entry;
  1707. huePubSub.subscribeOnce('app.gained.focus', function (app) {
  1708. if (app === 'hbase' && self.HBaseLoaded) {
  1709. delayChangeHash(hash);
  1710. }
  1711. });
  1712. huePubSub.publish('open.link', '/hbase');
  1713. }
  1714. }
  1715. else {
  1716. window.open('/hbase/#' + hash);
  1717. }
  1718. });
  1719. huePubSub.subscribe('assist.hbase.refresh', function () {
  1720. huePubSub.publish('assist.clear.hbase.cache');
  1721. self.reload();
  1722. });
  1723. }
  1724. AssistHBasePanel.prototype.init = function () {
  1725. var self = this;
  1726. if (self.initialized) {
  1727. return;
  1728. }
  1729. self.reload();
  1730. self.initialized = true;
  1731. };
  1732. var NAV_FACET_ICON = 'fa-tags';
  1733. var NAV_TYPE_ICONS = {
  1734. 'DATABASE': 'fa-database',
  1735. 'TABLE': 'fa-table',
  1736. 'VIEW': 'fa-eye',
  1737. 'FIELD': 'fa-columns',
  1738. 'PARTITION': 'fa-th',
  1739. 'SOURCE': 'fa-server',
  1740. 'OPERATION': 'fa-cogs',
  1741. 'OPERATION_EXECUTION': 'fa-cog',
  1742. 'DIRECTORY': 'fa-folder-o',
  1743. 'FILE': 'fa-file-o',
  1744. 'S3BUCKET': 'fa-cubes',
  1745. 'SUB_OPERATION': 'fa-code-fork',
  1746. 'COLLECTION': 'fa-search',
  1747. 'HBASE': 'fa-th-large',
  1748. 'HUE': 'fa-file-o'
  1749. };
  1750. /**
  1751. * @param {Object} params
  1752. * @param {string} params.user
  1753. * @param {boolean} params.onlySql - For the old query editors
  1754. * @param {string[]} params.visibleAssistPanels - Panels that will initially be shown regardless of total storage
  1755. * @param {Object} params.sql
  1756. * @param {Object[]} params.sql.sourceTypes - All the available SQL source types
  1757. * @param {string} params.sql.sourceTypes[].name - Example: Hive SQL
  1758. * @param {string} params.sql.sourceTypes[].type - Example: hive
  1759. * @param {string} [params.sql.activeSourceType] - Example: hive
  1760. * @param {Object} params.sql.navigationSettings - enable/disable the links
  1761. * @param {boolean} params.sql.navigationSettings.openItem - Example: true
  1762. * @param {boolean} params.sql.navigationSettings.showStats - Example: true
  1763. * @constructor
  1764. */
  1765. function AssistPanel (params) {
  1766. var self = this;
  1767. var i18n = {
  1768. errorLoadingDatabases: "${ _('There was a problem loading the databases') }",
  1769. errorLoadingTablePreview: "${ _('There was a problem loading the table preview') }"
  1770. };
  1771. var i18nCollections = {
  1772. errorLoadingDatabases: "${ _('There was a problem loading the indexes') }",
  1773. errorLoadingTablePreview: "${ _('There was a problem loading the index preview') }"
  1774. };
  1775. self.apiHelper = ApiHelper.getInstance();
  1776. self.tabsEnabled = '${ USE_NEW_SIDE_PANELS.get() }' === 'True';
  1777. self.availablePanels = ko.observableArray();
  1778. self.visiblePanel = ko.observable();
  1779. self.lastOpenPanelType = ko.observable();
  1780. self.apiHelper.withTotalStorage('assist', 'last.open.panel', self.lastOpenPanelType);
  1781. huePubSub.subscribeOnce('cluster.config.set.config', function (clusterConfig) {
  1782. if (clusterConfig && clusterConfig['app_config']) {
  1783. var panels = [];
  1784. var appConfig = clusterConfig['app_config'];
  1785. if (appConfig['editor']) {
  1786. var sqlPanel = new AssistInnerPanel({
  1787. panelData: new AssistDbPanel($.extend({
  1788. apiHelper: self.apiHelper,
  1789. i18n: i18n
  1790. }, params.sql)),
  1791. apiHelper: self.apiHelper,
  1792. name: '${ _("SQL") }',
  1793. type: 'sql',
  1794. icon: 'fa-database',
  1795. minHeight: 75
  1796. });
  1797. panels.push(sqlPanel);
  1798. huePubSub.subscribe('assist.show.sql', function () {
  1799. if (self.visiblePanel() !== sqlPanel) {
  1800. self.visiblePanel(sqlPanel);
  1801. }
  1802. });
  1803. }
  1804. if (self.tabsEnabled) {
  1805. if (appConfig['browser'] && appConfig['browser']['interpreter_names'].indexOf('hdfs') != -1) {
  1806. panels.push(new AssistInnerPanel({
  1807. panelData: new AssistHdfsPanel({
  1808. apiHelper: self.apiHelper
  1809. }),
  1810. apiHelper: self.apiHelper,
  1811. name: '${ _("HDFS") }',
  1812. type: 'hdfs',
  1813. icon: 'fa-files-o',
  1814. minHeight: 50
  1815. }));
  1816. }
  1817. if (appConfig['browser'] && appConfig['browser']['interpreter_names'].indexOf('s3') != -1) {
  1818. panels.push(new AssistInnerPanel({
  1819. panelData: new AssistS3Panel({
  1820. apiHelper: self.apiHelper
  1821. }),
  1822. apiHelper: self.apiHelper,
  1823. name: '${ _("S3") }',
  1824. type: 's3',
  1825. icon: 'fa-cubes',
  1826. minHeight: 50
  1827. }));
  1828. }
  1829. if (appConfig['browser'] && appConfig['browser']['interpreter_names'].indexOf('adls') != -1) {
  1830. panels.push(new AssistInnerPanel({
  1831. panelData: new AssistAdlsPanel({
  1832. apiHelper: self.apiHelper
  1833. }),
  1834. apiHelper: self.apiHelper,
  1835. name: '${ _("ADLS") }',
  1836. type: 'adls',
  1837. icon: 'fa-windows',
  1838. iconSvg: '#hi-adls',
  1839. minHeight: 50
  1840. }));
  1841. }
  1842. if (appConfig['browser'] && appConfig['browser']['interpreter_names'].indexOf('indexes') != -1) {
  1843. var solrPanel = new AssistInnerPanel({
  1844. panelData: new AssistDbPanel($.extend({
  1845. apiHelper: self.apiHelper,
  1846. i18n: i18nCollections,
  1847. isSolr: true
  1848. }, params.sql)),
  1849. apiHelper: self.apiHelper,
  1850. name: '${ _("Indexes") }',
  1851. type: 'solr',
  1852. icon: 'fa-search-plus',
  1853. minHeight: 75
  1854. });
  1855. panels.push(solrPanel);
  1856. huePubSub.subscribe('assist.show.solr', function () {
  1857. if (self.visiblePanel() !== solrPanel) {
  1858. self.visiblePanel(solrPanel);
  1859. }
  1860. });
  1861. }
  1862. if (appConfig['browser'] && appConfig['browser']['interpreter_names'].indexOf('kafka') != -1) {
  1863. var kafkaPanel = new AssistInnerPanel({
  1864. panelData: new AssistDbPanel($.extend({
  1865. apiHelper: self.apiHelper,
  1866. i18n: i18nCollections,
  1867. isKafka: true
  1868. }, params.sql)),
  1869. apiHelper: self.apiHelper,
  1870. name: '${ _("Streams") }',
  1871. type: 'solr',
  1872. icon: 'fa-sitemap',
  1873. minHeight: 75
  1874. });
  1875. panels.push(kafkaPanel);
  1876. }
  1877. if (appConfig['browser'] && appConfig['browser']['interpreter_names'].indexOf('hbase') != -1) {
  1878. panels.push(new AssistInnerPanel({
  1879. panelData: new AssistHBasePanel({
  1880. apiHelper: self.apiHelper
  1881. }),
  1882. apiHelper: self.apiHelper,
  1883. name: '${ _("HBase") }',
  1884. type: 'hbase',
  1885. icon: 'fa-th-large',
  1886. minHeight: 50
  1887. }));
  1888. }
  1889. % if not IS_EMBEDDED.get():
  1890. var documentsPanel = new AssistInnerPanel({
  1891. panelData: new AssistDocumentsPanel({
  1892. user: params.user,
  1893. apiHelper: self.apiHelper
  1894. }),
  1895. apiHelper: self.apiHelper,
  1896. name: '${ _("Documents") }',
  1897. type: 'documents',
  1898. icon: 'fa-files-o',
  1899. iconSvg: '#hi-documents',
  1900. minHeight: 50,
  1901. rightAlignIcon: true,
  1902. visible: params.visibleAssistPanels && params.visibleAssistPanels.indexOf('documents') !== -1
  1903. });
  1904. panels.push(documentsPanel);
  1905. huePubSub.subscribe('assist.show.documents', function (docType) {
  1906. huePubSub.publish('left.assist.show');
  1907. if (self.visiblePanel() !== documentsPanel) {
  1908. self.visiblePanel(documentsPanel);
  1909. }
  1910. if (docType) {
  1911. documentsPanel.panelData.setTypeFilter(docType);
  1912. }
  1913. });
  1914. % endif
  1915. var vcsKeysLength = ${ len(VCS.keys()) };
  1916. if (vcsKeysLength > 0) {
  1917. panels.push(new AssistInnerPanel({
  1918. panelData: new AssistGitPanel({
  1919. apiHelper: self.apiHelper
  1920. }),
  1921. apiHelper: self.apiHelper,
  1922. name: '${ _("Git") }',
  1923. type: 'git',
  1924. icon: 'fa-github',
  1925. minHeight: 50,
  1926. rightAlignIcon: true
  1927. }));
  1928. }
  1929. }
  1930. self.availablePanels(panels);
  1931. } else {
  1932. self.availablePanels([new AssistInnerPanel({
  1933. panelData: new AssistDbPanel($.extend({
  1934. apiHelper: self.apiHelper,
  1935. i18n: i18n
  1936. }, params.sql)),
  1937. apiHelper: self.apiHelper,
  1938. name: '${ _("SQL") }',
  1939. type: 'sql',
  1940. icon: 'fa-database',
  1941. minHeight: 75
  1942. })]);
  1943. }
  1944. if (!self.lastOpenPanelType()) {
  1945. self.lastOpenPanelType(self.availablePanels()[0].type);
  1946. }
  1947. var lastFoundPanel = self.availablePanels().filter(function (panel) { return panel.type === self.lastOpenPanelType() });
  1948. // always forces the db panel to load
  1949. var dbPanel = self.availablePanels().filter(function (panel) { return panel.type === 'sql' });
  1950. if (dbPanel.length > 0) {
  1951. dbPanel[0].panelData.init();
  1952. }
  1953. self.visiblePanel.subscribe(function(newValue) {
  1954. self.lastOpenPanelType(newValue.type);
  1955. if (newValue.type !== 'sql' && !newValue.panelData.initialized) {
  1956. newValue.panelData.init();
  1957. }
  1958. });
  1959. self.visiblePanel(lastFoundPanel.length === 1 ? lastFoundPanel[0] : self.availablePanels()[0]);
  1960. });
  1961. window.setTimeout(function () {
  1962. // Main initialization trigger in hue.mako, this is for Hue 3
  1963. if (self.availablePanels().length === 0) {
  1964. huePubSub.publish('cluster.config.get.config');
  1965. }
  1966. }, 0);
  1967. }
  1968. ko.components.register('assist-panel', {
  1969. viewModel: AssistPanel,
  1970. template: { element: 'assist-panel-template' }
  1971. });
  1972. })();
  1973. </script>
  1974. <script type="text/html" id="functions-panel-template">
  1975. <div class="assist-inner-panel">
  1976. <div class="assist-flex-panel">
  1977. <div class="assist-flex-header">
  1978. <div class="assist-inner-header">
  1979. <div class="function-dialect-dropdown" data-bind="component: { name: 'hue-drop-down', params: { fixedPosition: true, value: activeType, entries: availableTypes, linkTitle: '${ _ko('Selected dialect') }' } }" style="display: inline-block"></div>
  1980. </div>
  1981. </div>
  1982. <div class="assist-flex-search">
  1983. <div class="assist-filter">
  1984. <input class="clearable" type="text" placeholder="Filter..." data-bind="clearable: query, value: query, valueUpdate: 'afterkeydown'">
  1985. </div>
  1986. </div>
  1987. <div data-bind="css: { 'assist-flex-fill': !selectedFunction(), 'assist-flex-half': selectedFunction() }">
  1988. <!-- ko ifnot: query -->
  1989. <ul class="assist-function-categories" data-bind="foreach: activeCategories">
  1990. <li>
  1991. <a class="black-link" href="javascript: void(0);" data-bind="toggle: open"><i class="fa fa-fw" data-bind="css: { 'fa-chevron-right': !open(), 'fa-chevron-down': open }"></i> <span data-bind="text: name"></span></a>
  1992. <ul class="assist-functions" data-bind="slideVisible: open, foreach: functions">
  1993. <li data-bind="tooltip: { title: description, placement: 'left', delay: 1000 }">
  1994. <a class="assist-field-link" href="javascript: void(0);" data-bind="draggableText: { text: draggable, meta: { type: 'function' } }, css: { 'blue': $parents[1].selectedFunction() === $data }, multiClick: { click: function () { $parents[1].selectedFunction($data); }, dblClick: function () { huePubSub.publish('editor.insert.at.cursor', draggable); } }, text: signature"></a>
  1995. </li>
  1996. </ul>
  1997. </li>
  1998. </ul>
  1999. <!-- /ko -->
  2000. <!-- ko if: query -->
  2001. <!-- ko if: filteredFunctions().length > 0 -->
  2002. <ul class="assist-functions" data-bind="foreach: filteredFunctions">
  2003. <li data-bind="tooltip: { title: description, placement: 'left', delay: 1000 }">
  2004. <a class="assist-field-link" href="javascript: void(0);" data-bind="draggableText: { text: draggable, meta: { type: 'function' } }, css: { 'blue': $parent.selectedFunction() === $data }, multiClick: { click: function () { $parent.selectedFunction($data); }, dblClick: function () { huePubSub.publish('editor.insert.at.cursor', draggable); } }, html: signatureMatch"></a>
  2005. </li>
  2006. </ul>
  2007. <!-- /ko -->
  2008. <!-- ko if: filteredFunctions().length === 0 -->
  2009. <ul class="assist-functions">
  2010. <li class="assist-no-entries">${ _('No functions found. ') }</li>
  2011. </ul>
  2012. <!-- /ko -->
  2013. <!-- /ko -->
  2014. </div>
  2015. <!-- ko if: selectedFunction -->
  2016. <div class="assist-flex-half assist-function-details" data-bind="with: selectedFunction">
  2017. <div class="assist-panel-close"><button class="close" data-bind="click: function() { $parent.selectedFunction(null); }">&times;</button></div>
  2018. <div class="assist-function-signature blue" data-bind="draggableText: { text: draggable, meta: { type: 'function' } }, text: signature, event: { 'dblclick': function () { huePubSub.publish('editor.insert.at.cursor', draggable); } }"></div>
  2019. <!-- ko if: description -->
  2020. <div data-bind="html: descriptionMatch"></div>
  2021. <!-- /ko -->
  2022. </div>
  2023. <!-- /ko -->
  2024. </div>
  2025. </div>
  2026. </script>
  2027. <script type="text/javascript">
  2028. (function () {
  2029. function FunctionsPanel(params) {
  2030. var self = this;
  2031. self.categories = {};
  2032. self.disposals = [];
  2033. self.activeType = ko.observable();
  2034. self.availableTypes = ko.observableArray(['Hive', 'Impala', 'Pig']);
  2035. self.query = ko.observable().extend({ rateLimit: 400 });
  2036. self.selectedFunction = ko.observable();
  2037. self.availableTypes().forEach(function (type) {
  2038. self.initFunctions(type);
  2039. });
  2040. var selectedFunctionPerType = { 'Hive': null, 'Impala': null, 'Pig': null };
  2041. self.selectedFunction.subscribe(function (newFunction) {
  2042. if (newFunction) {
  2043. selectedFunctionPerType[self.activeType()] = newFunction;
  2044. if (!newFunction.category.open()) {
  2045. newFunction.category.open(true);
  2046. }
  2047. }
  2048. });
  2049. self.activeCategories = ko.observableArray();
  2050. self.filteredFunctions = ko.pureComputed(function () {
  2051. var result = [];
  2052. var lowerCaseQuery = self.query().toLowerCase();
  2053. var replaceRegexp = new RegExp('(' + lowerCaseQuery + ')', 'i');
  2054. self.activeCategories().forEach(function (category) {
  2055. category.functions.forEach(function (fn) {
  2056. if (fn.signature.toLowerCase().indexOf(lowerCaseQuery) === 0) {
  2057. fn.weight = 2;
  2058. fn.signatureMatch(fn.signature.replace(replaceRegexp, '<b>$1</b>'));
  2059. fn.descriptionMatch(fn.description);
  2060. result.push(fn);
  2061. } else if (fn.signature.toLowerCase().indexOf(lowerCaseQuery) !== -1) {
  2062. fn.weight = 1;
  2063. fn.signatureMatch(fn.signature.replace(replaceRegexp, '<b>$1</b>'));
  2064. fn.descriptionMatch(fn.description);
  2065. result.push(fn);
  2066. } else if ((fn.description && fn.description.toLowerCase().indexOf(lowerCaseQuery) !== -1)) {
  2067. fn.signatureMatch(fn.signature);
  2068. fn.descriptionMatch(fn.description.replace(replaceRegexp, '<b>$1</b>'));
  2069. fn.weight = 0;
  2070. result.push(fn);
  2071. } else {
  2072. if (fn.signatureMatch() !== fn.signature) {
  2073. fn.signatureMatch(fn.signature);
  2074. }
  2075. if (fn.descriptionMatch() !== fn.desciption) {
  2076. fn.descriptionMatch(fn.description);
  2077. }
  2078. }
  2079. });
  2080. });
  2081. result.sort(function (a, b) {
  2082. if (a.weight !== b.weight) {
  2083. return b.weight - a.weight;
  2084. }
  2085. return a.signature.localeCompare(b.signature);
  2086. });
  2087. return result;
  2088. });
  2089. var apiHelper = ApiHelper.getInstance();
  2090. self.activeType.subscribe(function (newType) {
  2091. self.selectedFunction(selectedFunctionPerType[newType]);
  2092. self.activeCategories(self.categories[newType]);
  2093. apiHelper.setInTotalStorage('assist', 'function.panel.active.type', newType);
  2094. });
  2095. var lastActiveType = apiHelper.getFromTotalStorage('assist', 'function.panel.active.type', self.availableTypes()[0]);
  2096. self.activeType(lastActiveType);
  2097. var updateType = function (type) {
  2098. self.availableTypes().every(function (availableType) {
  2099. if (availableType.toLowerCase() === type) {
  2100. if (self.activeType() !== availableType) {
  2101. self.activeType(availableType);
  2102. }
  2103. return false;
  2104. }
  2105. return true;
  2106. });
  2107. };
  2108. var activeSnippetTypeSub = huePubSub.subscribe('active.snippet.type.changed', updateType);
  2109. self.disposals.push(function () {
  2110. activeSnippetTypeSub.remove();
  2111. });
  2112. huePubSub.subscribeOnce('set.active.snippet.type', updateType);
  2113. huePubSub.publish('get.active.snippet.type');
  2114. }
  2115. FunctionsPanel.prototype.dispose = function () {
  2116. var self = this;
  2117. self.disposals.forEach(function (dispose) {
  2118. dispose();
  2119. })
  2120. };
  2121. FunctionsPanel.prototype.initFunctions = function (dialect) {
  2122. var self = this;
  2123. self.categories[dialect] = [];
  2124. var functions = dialect === 'Pig' ? PigFunctions.CATEGORIZED_FUNCTIONS : SqlFunctions.CATEGORIZED_FUNCTIONS[dialect.toLowerCase()];
  2125. functions.forEach(function (category) {
  2126. var koCategory = {
  2127. name: category.name,
  2128. open: ko.observable(false),
  2129. functions: $.map(category.functions, function(fn) {
  2130. return {
  2131. draggable: fn.draggable,
  2132. signature: fn.signature,
  2133. signatureMatch: ko.observable(fn.signature),
  2134. description: fn.description,
  2135. descriptionMatch: ko.observable(fn.description)
  2136. }
  2137. })
  2138. };
  2139. koCategory.functions.forEach(function (fn) {
  2140. fn.category = koCategory;
  2141. });
  2142. self.categories[dialect].push(koCategory)
  2143. });
  2144. };
  2145. ko.components.register('functions-panel', {
  2146. viewModel: FunctionsPanel,
  2147. template: { element: 'functions-panel-template' }
  2148. });
  2149. })();
  2150. </script>
  2151. <script type="text/html" id="editor-assistant-panel-template">
  2152. <div class="assist-inner-panel assist-assistant-panel">
  2153. <div class="assist-flex-panel">
  2154. <div class="assist-flex-header">
  2155. <div class="assist-inner-header">
  2156. <!-- ko if: isSolr -->
  2157. ${ _('Indexes') }
  2158. <!-- /ko -->
  2159. <!-- ko ifnot: isSolr -->
  2160. ${ _('Tables') }
  2161. <!-- ko if: statementCount() > 1 -->
  2162. <div class="statement-count">${ _('Statement') } <span data-bind="text: activeStatementIndex() + '/' + statementCount()"></span></div>
  2163. <!-- /ko -->
  2164. <!-- /ko -->
  2165. </div>
  2166. </div>
  2167. <div class="assist-flex-search" data-bind="visible: activeTables().length > 0">
  2168. <div class="assist-filter">
  2169. <!-- ko component: {
  2170. name: 'inline-autocomplete',
  2171. params: {
  2172. querySpec: filter.querySpec,
  2173. facets: ['type'],
  2174. knownFacetValues: isSolr() ? SOLR_ASSIST_KNOWN_FACET_VALUES : SQL_ASSIST_KNOWN_FACET_VALUES,
  2175. autocompleteFromEntries: $component.autocompleteFromEntries
  2176. }
  2177. } --><!-- /ko -->
  2178. </div>
  2179. </div>
  2180. <div class="assist-flex-half assist-db-scrollable" data-bind="delayedOverflow">
  2181. <!-- ko if: filteredTables().length === 0 && (!filter.querySpec() || filter.querySpec().query === '') -->
  2182. <div class="assist-no-entries">
  2183. <!-- ko if: isSolr -->
  2184. ${ _('No indexes selected.') }
  2185. <!-- /ko -->
  2186. <!-- ko ifnot: isSolr -->
  2187. ${ _('No tables identified.') }
  2188. <!-- /ko -->
  2189. </div>
  2190. <!-- /ko -->
  2191. <!-- ko if: filteredTables().length === 0 && filter.querySpec() && filter.querySpec().query !== '' && !someLoading() -->
  2192. <div class="assist-no-entries">${ _('No entries found.') }</div>
  2193. <!-- /ko -->
  2194. <!-- ko if: filteredTables().length > 0 -->
  2195. <ul class="database-tree assist-tables" data-bind="foreachVisible: { data: filteredTables, minHeight: 22, container: '.assist-db-scrollable', skipScrollEvent: true }">
  2196. <!-- ko if: hasErrors -->
  2197. <li class="assist-table hue-warning" data-bind="attr: { 'title': $parent.isSolr() ? '${ _ko('Error loading index details.') }' : '${ _ko('Error loading table details.') }'}">
  2198. <span class="assist-entry">
  2199. <i class="hue-warning fa fa-fw muted valign-middle fa-warning"></i>
  2200. <!-- ko with: catalogEntry -->
  2201. <!-- ko if: typeof reload !== 'undefined' -->
  2202. <span data-bind="text: getDisplayName()"></span> <a class="inactive-action" href="javascript: void(0);" data-bind="click: reload"><i class="fa fa-refresh" data-bind="css: { 'fa-spin': reloading }"></i></a>
  2203. <!-- /ko -->
  2204. <!-- /ko -->
  2205. </span>
  2206. </li>
  2207. <!-- /ko -->
  2208. <!-- ko ifnot: hasErrors -->
  2209. <!-- ko template: { if: catalogEntry.isTableOrView(), name: 'assist-table-entry' } --><!-- /ko -->
  2210. <!-- ko template: { if: catalogEntry.isField(), name: 'assist-column-entry-assistant' } --><!-- /ko -->
  2211. <!-- /ko -->
  2212. </ul>
  2213. <!-- /ko -->
  2214. <!-- ko hueSpinner: { spin: filter.querySpec() && filter.querySpec().query !== '' && someLoading(), inline: true, center: true} --><!-- /ko -->
  2215. </div>
  2216. <!-- ko if: HAS_OPTIMIZER && !isSolr() -->
  2217. <div class="assist-flex-header assist-divider"><div class="assist-inner-header">${ _('Suggestions') }</div></div>
  2218. <div class="assist-flex-half">
  2219. <!-- ko if: ! activeRisks().hints -->
  2220. <div class="assist-no-entries">${ _('Select a query or start typing to get optimization hints.') }</div>
  2221. <!-- /ko -->
  2222. <!-- ko if: activeRisks().hints && activeRisks().hints.length === 0 -->
  2223. <div class="assist-no-entries">${ _('No optimizations identified.') }</div>
  2224. <!-- /ko -->
  2225. <!-- ko if: activeRisks().hints && activeRisks().hints.length > 0 -->
  2226. <ul class="risk-list" data-bind="foreach: activeRisks().hints">
  2227. <li>
  2228. <div class="risk-list-title" data-bind="css: { 'risk-list-high' : risk === 'high', 'risk-list-normal': risk !== 'high' }, tooltip: { title: risk + ' ' + riskTables }"><span data-bind="text: riskAnalysis"></span></div>
  2229. <div class="risk-list-description" data-bind="text: riskRecommendation"></div>
  2230. <div class="risk-quickfix" data-bind="visible: (riskId === 17 || riskId === 22) && $parent.activeEditor() && $parent.activeLocations()" style="display:none;">
  2231. <a href="javascript:void(0);" data-bind="click: function () { $parent.addFilter(riskId); hueAnalytics.convert('optimizer', 'addFilter/' + riskId); }">${ _('Add filter') }</a>
  2232. </div>
  2233. </li>
  2234. </ul>
  2235. <!-- /ko -->
  2236. <!-- ko if: hasMissingRisks() -->
  2237. <div class="margin-top-20">
  2238. <!-- ko hueSpinner: { spin: uploadingTableStats, inline: true} --><!-- /ko -->
  2239. <!-- ko ifnot: uploadingTableStats -->
  2240. <a href="javascript:void(0)" data-bind="visible: activeTables().length > 0, click: function() { uploadTableStats(true) }, attr: { 'title': ('${ _("Add table ") }' + (isMissingDDL() ? 'DDL' : '') + (isMissingDDL() && isMissingStats() ? ' ${ _("and") } ' : '') + (isMissingStats() ? 'stats' : '')) }">
  2241. <i class="fa fa-fw fa-plus-circle"></i> ${_('Improve Analysis')}
  2242. </a>
  2243. <!-- /ko -->
  2244. </div>
  2245. <!-- /ko -->
  2246. </div>
  2247. <!-- /ko -->
  2248. </div>
  2249. </div>
  2250. </script>
  2251. <script type="text/javascript">
  2252. var AssistantUtils = (function () {
  2253. return {
  2254. getFilteredTablesPureComputed: function (vm) {
  2255. var openedByFilter = [];
  2256. return ko.pureComputed(function () {
  2257. if (vm.filter === null || !vm.filter.querySpec() || ((!vm.filter.querySpec().facets || Object.keys(vm.filter.querySpec().facets).length === 0) && (!vm.filter.querySpec().text || vm.filter.querySpec().text.length === 0))) {
  2258. while (openedByFilter.length) {
  2259. openedByFilter.pop().open(false);
  2260. }
  2261. return vm.activeTables();
  2262. }
  2263. var facets = vm.filter.querySpec().facets;
  2264. var result = [];
  2265. $.each(vm.activeTables(), function (index, entry) {
  2266. var facetMatch = !facets || !facets['type'] || (!facets['type']['table'] && !facets['type']['view']);
  2267. if (!facetMatch && facets['type']['table']) {
  2268. facetMatch = entry.catalogEntry.isTable();
  2269. }
  2270. if (!facetMatch && facets['type']['view']) {
  2271. facetMatch = entry.catalogEntry.isView();
  2272. }
  2273. var textMatch = !vm.filter.querySpec().text || vm.filter.querySpec().text.length === 0;
  2274. if (!textMatch) {
  2275. var nameLower = entry.catalogEntry.name.toLowerCase();
  2276. textMatch = vm.filter.querySpec().text.every(function (text) {
  2277. return nameLower.indexOf(text.toLowerCase()) !== -1;
  2278. });
  2279. }
  2280. entry.filterColumnNames(!textMatch);
  2281. if ((facetMatch && textMatch) || entry.filteredEntries().length > 0) {
  2282. if (!entry.open()) {
  2283. entry.open(true);
  2284. openedByFilter.push(entry);
  2285. }
  2286. result.push(entry);
  2287. }
  2288. });
  2289. return result;
  2290. });
  2291. }
  2292. }
  2293. })();
  2294. (function () {
  2295. function EditorAssistantPanel(params) {
  2296. var self = this;
  2297. self.disposals = [];
  2298. self.isSolr = ko.observable(false);
  2299. self.activeTab = params.activeTab;
  2300. self.uploadingTableStats = ko.observable(false);
  2301. self.activeStatement = ko.observable();
  2302. self.activeTables = ko.observableArray();
  2303. self.activeRisks = ko.observable({});
  2304. self.activeEditor = ko.observable();
  2305. self.activeRisks.subscribe(function() {
  2306. if (self.isMissingDDL()) {
  2307. self.uploadTableStats(false);
  2308. }
  2309. });
  2310. self.activeLocations = ko.observable();
  2311. self.statementCount = ko.observable(0);
  2312. self.activeStatementIndex = ko.observable(0);
  2313. self.hasActiveRisks = ko.pureComputed(function () {
  2314. return self.activeRisks().hints && self.activeRisks().hints.length > 0;
  2315. });
  2316. self.hasMissingRisks = ko.pureComputed(function () {
  2317. return self.isMissingDDL() || self.isMissingStats();
  2318. });
  2319. self.isMissingDDL = ko.pureComputed(function () {
  2320. return self.activeRisks().noDDL && self.activeRisks().noDDL.length > 0
  2321. });
  2322. self.isMissingStats = ko.pureComputed(function () {
  2323. % if OPTIMIZER.AUTO_UPLOAD_STATS.get():
  2324. return self.activeRisks().noStats && self.activeRisks().noStats.length > 0;
  2325. % else:
  2326. return false;
  2327. % endif
  2328. });
  2329. self.someLoading = ko.pureComputed(function () {
  2330. return self.activeTables().some(function (table) {
  2331. return table.loading() || (!table.hasEntries() && !table.hasErrors());
  2332. });
  2333. });
  2334. var createQualifiedIdentifier = function (identifierChain, defaultDatabase) {
  2335. if (identifierChain.length === 1) {
  2336. return defaultDatabase + '.' + identifierChain[0].name;
  2337. }
  2338. return $.map(identifierChain, function (identifier) {
  2339. return identifier.name;
  2340. }).join('.').toLowerCase();
  2341. };
  2342. self.filter = {
  2343. querySpec: ko.observable({
  2344. query: '',
  2345. facets: {},
  2346. text: []
  2347. }).extend({ rateLimit: 300 })
  2348. };
  2349. self.filteredTables = AssistantUtils.getFilteredTablesPureComputed(self);
  2350. var navigationSettings = {
  2351. showStats: true,
  2352. rightAssist: true
  2353. };
  2354. var i18n = {};
  2355. var sources = {};
  2356. var loadEntriesTimeout = -1;
  2357. // This fetches the columns for each table synchronously with 2 second in between.
  2358. var loadEntries = function (currentCount) {
  2359. var count = currentCount || 0;
  2360. count++;
  2361. if (count > 10) {
  2362. return;
  2363. }
  2364. window.clearTimeout(loadEntriesTimeout);
  2365. if (self.activeTables().length === 1) {
  2366. self.activeTables()[0].open(true);
  2367. } else {
  2368. loadEntriesTimeout = window.setTimeout(function () {
  2369. self.activeTables().every(function (table) {
  2370. if (!table.loaded && !table.hasErrors() && !table.loading()) {
  2371. table.loadEntries(function () {
  2372. loadEntries(count);
  2373. });
  2374. return false;
  2375. }
  2376. return !table.loading();
  2377. })
  2378. }, 2000);
  2379. }
  2380. };
  2381. self.autocompleteFromEntries = function (nonPartial, partial) {
  2382. var added = {};
  2383. var result = [];
  2384. var partialLower = partial.toLowerCase();
  2385. self.filteredTables().forEach(function (table) {
  2386. if (!added[table.catalogEntry.name] && table.catalogEntry.name.toLowerCase().indexOf(partialLower) === 0) {
  2387. added[table.catalogEntry.name] = true;
  2388. result.push(nonPartial + partial + table.catalogEntry.name.substring(partial.length))
  2389. }
  2390. table.entries().forEach(function (col) {
  2391. if (!added[col.catalogEntry.name] && col.catalogEntry.name.toLowerCase().indexOf(partialLower) === 0) {
  2392. added[col.catalogEntry.name] = true;
  2393. result.push(nonPartial + partial + col.catalogEntry.name.substring(partial.length))
  2394. }
  2395. })
  2396. });
  2397. return result;
  2398. };
  2399. var activeTablesSub = self.activeTables.subscribe(loadEntries);
  2400. self.disposals.push(function () {
  2401. window.clearTimeout(loadEntriesTimeout);
  2402. activeTablesSub.dispose();
  2403. });
  2404. var updateOnVisible = false;
  2405. var runningPromises = [];
  2406. var handleLocationUpdate = function (activeLocations) {
  2407. while (runningPromises.length) {
  2408. var promise = runningPromises.pop();
  2409. if (promise.cancel) {
  2410. promise.cancel();
  2411. }
  2412. }
  2413. updateOnVisible = false;
  2414. if (!sources[activeLocations.type]) {
  2415. sources[activeLocations.type] = {
  2416. assistDbSource: new AssistDbSource({
  2417. i18n: i18n,
  2418. initialNamespace: activeLocations.namespace,
  2419. type: activeLocations.type,
  2420. name: activeLocations.type,
  2421. navigationSettings: navigationSettings
  2422. }),
  2423. databaseIndex: {},
  2424. activeTableIndex: {}
  2425. }
  2426. }
  2427. var assistDbSource = sources[activeLocations.type].assistDbSource;
  2428. var databaseIndex = sources[activeLocations.type].databaseIndex;
  2429. var activeTableIndex = sources[activeLocations.type].activeTableIndex;
  2430. if (!activeLocations) {
  2431. self.activeLocations(undefined);
  2432. return;
  2433. }
  2434. self.activeLocations(activeLocations);
  2435. self.statementCount(activeLocations.totalStatementCount);
  2436. self.activeStatementIndex(activeLocations.activeStatementIndex);
  2437. if (activeLocations.activeStatementLocations) {
  2438. var updateTables = false;
  2439. var tableQidIndex = {};
  2440. var ctes = {};
  2441. activeLocations.activeStatementLocations.forEach(function (location) {
  2442. if (location.type === 'alias' && location.source === 'cte') {
  2443. ctes[location.alias.toLowerCase()] = true;
  2444. }
  2445. });
  2446. activeLocations.activeStatementLocations.forEach(function (location) {
  2447. if (location.type === 'table' && (location.identifierChain.length !== 1 || !ctes[location.identifierChain[0].name.toLowerCase()])) {
  2448. var tableDeferred = $.Deferred();
  2449. var dbDeferred = $.Deferred();
  2450. runningPromises.push(tableDeferred);
  2451. runningPromises.push(dbDeferred);
  2452. var qid = createQualifiedIdentifier(location.identifierChain, activeLocations.defaultDatabase);
  2453. if (activeTableIndex[qid]) {
  2454. tableQidIndex[qid] = true;
  2455. tableDeferred.resolve(activeTableIndex[qid]);
  2456. dbDeferred.resolve(activeTableIndex[qid].parent);
  2457. } else {
  2458. var database = location.identifierChain.length === 2 ? location.identifierChain[0].name : activeLocations.defaultDatabase;
  2459. database = database.toLowerCase();
  2460. if (databaseIndex[database]) {
  2461. dbDeferred.resolve(databaseIndex[database]);
  2462. } else {
  2463. DataCatalog.getEntry({
  2464. sourceType: activeLocations.type,
  2465. namespace: activeLocations.namespace,
  2466. compute: activeLocations.compute,
  2467. path: [ database ],
  2468. definition: { type: 'database' }
  2469. }).done(function (catalogEntry) {
  2470. databaseIndex[database] = new AssistDbEntry(catalogEntry, null, assistDbSource, self.filter, i18n,navigationSettings);
  2471. updateTables = true;
  2472. dbDeferred.resolve(databaseIndex[database])
  2473. }).fail(function () {
  2474. console.log('reject 1');
  2475. dbDeferred.reject();
  2476. });
  2477. }
  2478. dbDeferred.done(function (dbEntry) {
  2479. dbEntry.catalogEntry.getChildren({ silenceErrors: true }).done(function (tableEntries) {
  2480. var tableName = location.identifierChain[location.identifierChain.length - 1].name;
  2481. var found = tableEntries.some(function (tableEntry) {
  2482. if (tableEntry.name === tableName) {
  2483. var assistTableEntry = new AssistDbEntry(
  2484. tableEntry,
  2485. dbEntry,
  2486. assistDbSource,
  2487. self.filter,
  2488. i18n,
  2489. navigationSettings
  2490. );
  2491. activeTableIndex[createQualifiedIdentifier(location.identifierChain, activeLocations.defaultDatabase)] = assistTableEntry;
  2492. tableQidIndex[qid] = true;
  2493. updateTables = true;
  2494. tableDeferred.resolve(assistTableEntry);
  2495. return true;
  2496. }
  2497. });
  2498. if (!found) {
  2499. var missingEntry = new AssistDbEntry(
  2500. {
  2501. path: [dbEntry.catalogEntry.name, tableName],
  2502. name: tableName,
  2503. isTableOrView: function () { return true; },
  2504. getType: function () { return 'table' },
  2505. hasPossibleChildren: function () { return true; },
  2506. getSourceMeta: function () { return $.Deferred().resolve({ notFound: true }).promise() },
  2507. getDisplayName: function () { return dbEntry.catalogEntry.name + '.' + tableName },
  2508. reloading: ko.observable(false),
  2509. reload: function () {
  2510. var self = this;
  2511. if (self.reloading()) {
  2512. return;
  2513. }
  2514. self.reloading(true);
  2515. huePubSub.subscribeOnce('data.catalog.entry.refreshed', function (data) {
  2516. data.entry.getSourceMeta({ silenceErrors: true }).always(function () {
  2517. self.reloading(false)
  2518. })
  2519. });
  2520. DataCatalog.getEntry({ sourceType: activeLocations.type, namespace: activeLocations.namespace, compute: activeLocations.compute, path: [] }).done(function (sourceEntry) {
  2521. sourceEntry.getChildren().done(function (dbEntries) {
  2522. var clearPromise;
  2523. // Clear the database first if it exists without cascade
  2524. var hasDb = dbEntries.some(function (dbEntry) {
  2525. if (dbEntry.name.toLowerCase() === self.path[0].toLowerCase()) {
  2526. clearPromise = dbEntry.clearCache({ invalidate: 'invalidate', cascade: false });
  2527. return true;
  2528. }
  2529. });
  2530. if (!hasDb) {
  2531. // If the database is missing clear the source without cascade
  2532. clearPromise = sourceEntry.clearCache({ invalidate: 'invalidate', cascade: false });
  2533. }
  2534. clearPromise.fail(function () {
  2535. self.reloading(false);
  2536. });
  2537. }).fail(function () {
  2538. self.reloading(false);
  2539. })
  2540. }).fail(function () {
  2541. self.reloading(false);
  2542. });
  2543. }
  2544. },
  2545. dbEntry,
  2546. assistDbSource,
  2547. self.filter,
  2548. i18n,
  2549. navigationSettings
  2550. );
  2551. activeTableIndex[createQualifiedIdentifier(location.identifierChain, activeLocations.defaultDatabase)] = missingEntry;
  2552. tableQidIndex[qid] = true;
  2553. updateTables = true;
  2554. missingEntry.hasErrors(true);
  2555. tableDeferred.resolve(missingEntry);
  2556. }
  2557. }).fail(tableDeferred.reject);
  2558. }).fail(tableDeferred.reject);
  2559. }
  2560. }
  2561. });
  2562. $.when.apply($, runningPromises).always(function () {
  2563. runningPromises.length = 0;
  2564. Object.keys(activeTableIndex).forEach(function (key) {
  2565. if (!tableQidIndex[key]) {
  2566. delete activeTableIndex[key];
  2567. updateTables = true;
  2568. }
  2569. });
  2570. if (updateTables) {
  2571. var tables = [];
  2572. Object.keys(activeTableIndex).forEach(function (key) {
  2573. tables.push(activeTableIndex[key]);
  2574. });
  2575. tables.sort(function (a, b) {
  2576. return a.catalogEntry.name.localeCompare(b.catalogEntry.name);
  2577. });
  2578. self.activeTables(tables);
  2579. }
  2580. });
  2581. }
  2582. };
  2583. huePubSub.subscribe('data.catalog.entry.refreshed', function (details) {
  2584. var sourceType = details.entry.getSourceType();
  2585. if (sources[sourceType]) {
  2586. var completeRefresh = false;
  2587. if (details.entry.isSource()) {
  2588. sources[sourceType].databaseIndex = {};
  2589. sources[sourceType].activeTableIndex = {};
  2590. completeRefresh = true;
  2591. } else if (details.entry.isDatabase() && sources[sourceType].databaseIndex[details.entry.name]) {
  2592. var dbEntry = sources[sourceType].databaseIndex[details.entry.name];
  2593. var activeTableIndex = sources[sourceType].activeTableIndex;
  2594. Object.keys(activeTableIndex).forEach(function (tableKey) {
  2595. var tableEntry = activeTableIndex[tableKey];
  2596. if (tableEntry.parent === dbEntry) {
  2597. delete activeTableIndex[tableKey];
  2598. completeRefresh = true;
  2599. }
  2600. });
  2601. } else if (details.entry.isTableOrView()) {
  2602. var activeTableIndex = sources[sourceType].activeTableIndex;
  2603. if (activeTableIndex[details.entry.getQualifiedPath()]) {
  2604. delete activeTableIndex[details.entry.getQualifiedPath()];
  2605. completeRefresh = true;
  2606. }
  2607. }
  2608. if (completeRefresh) {
  2609. handleLocationUpdate(self.activeLocations());
  2610. }
  2611. }
  2612. });
  2613. if (self.activeTab() === 'editorAssistant') {
  2614. huePubSub.publish('get.active.editor.locations', handleLocationUpdate);
  2615. } else {
  2616. updateOnVisible = true;
  2617. }
  2618. var activeTabSub = self.activeTab.subscribe(function (activeTab) {
  2619. if (activeTab === 'editorAssistant' && updateOnVisible) {
  2620. huePubSub.publish('get.active.editor.locations', handleLocationUpdate);
  2621. }
  2622. });
  2623. self.disposals.push(function () {
  2624. activeTabSub.dispose();
  2625. });
  2626. var activeLocationsSub = huePubSub.subscribe('editor.active.locations', function (activeLocations) {
  2627. if (self.activeTab() === 'editorAssistant') {
  2628. handleLocationUpdate(activeLocations);
  2629. } else {
  2630. updateOnVisible = true;
  2631. }
  2632. });
  2633. var activeRisksSub = huePubSub.subscribe('editor.active.risks', function (details) {
  2634. if (details.risks !== self.activeRisks()) {
  2635. self.activeRisks(details.risks);
  2636. self.activeEditor(details.editor);
  2637. }
  2638. });
  2639. huePubSub.publish('editor.get.active.risks', function (details) {
  2640. self.activeRisks(details.risks);
  2641. self.activeEditor(details.editor);
  2642. });
  2643. self.disposals.push(function () {
  2644. activeLocationsSub.remove();
  2645. activeRisksSub.remove();
  2646. });
  2647. }
  2648. EditorAssistantPanel.prototype.addFilter = function (riskId) {
  2649. var self = this;
  2650. if (self.activeLocations() && self.activeEditor()) {
  2651. self.activeLocations().activeStatementLocations.every(function (location) {
  2652. var isLowerCase = false;
  2653. if (self.activeLocations().activeStatementLocations && self.activeLocations().activeStatementLocations.length > 0) {
  2654. var firstToken = self.activeLocations().activeStatementLocations[0].firstToken;
  2655. isLowerCase = firstToken === firstToken.toLowerCase();
  2656. }
  2657. if (location.type === 'whereClause' && !location.subquery && (location.missing || riskId === 22 )) {
  2658. self.activeEditor().moveCursorToPosition({
  2659. row: location.location.last_line - 1,
  2660. column: location.location.last_column - 1
  2661. });
  2662. self.activeEditor().clearSelection();
  2663. if (/\S$/.test(self.activeEditor().getTextBeforeCursor())) {
  2664. self.activeEditor().session.insert(self.activeEditor().getCursorPosition(), ' ');
  2665. }
  2666. var operation = location.missing ? 'WHERE ' : 'AND ';
  2667. self.activeEditor().session.insert(self.activeEditor().getCursorPosition(), isLowerCase ? operation.toLowerCase() : operation);
  2668. self.activeEditor().focus();
  2669. if (riskId === 22) {
  2670. huePubSub.publish('editor.autocomplete.temporary.sort.override', { partitionColumnsFirst: true });
  2671. }
  2672. window.setTimeout(function () {
  2673. self.activeEditor().execCommand("startAutocomplete");
  2674. }, 1);
  2675. return false;
  2676. }
  2677. return true;
  2678. })
  2679. }
  2680. };
  2681. EditorAssistantPanel.prototype.uploadTableStats = function (showProgress) {
  2682. var self = this;
  2683. if (self.uploadingTableStats()) {
  2684. return;
  2685. }
  2686. self.uploadingTableStats(true);
  2687. huePubSub.publish('editor.upload.table.stats', {
  2688. activeTables: self.activeTables(),
  2689. showProgress: showProgress,
  2690. callback: function () {
  2691. self.uploadingTableStats(false);
  2692. }
  2693. });
  2694. };
  2695. EditorAssistantPanel.prototype.dispose = function () {
  2696. var self = this;
  2697. self.disposals.forEach(function (dispose) {
  2698. dispose();
  2699. })
  2700. };
  2701. ko.components.register('editor-assistant-panel', {
  2702. viewModel: EditorAssistantPanel,
  2703. template: { element: 'editor-assistant-panel-template' }
  2704. });
  2705. })();
  2706. </script>
  2707. <script type="text/html" id="schedule-panel-template">
  2708. <div class="assist-inner-panel">
  2709. <div class="assist-flex-panel">
  2710. <!-- ko if: selectedNotebook() && selectedNotebook().isBatchable() -->
  2711. <!-- ko with: selectedNotebook() -->
  2712. <div class="tab-pane" id="scheduleTab">
  2713. <!-- ko ifnot: isSaved() && ! isHistory() -->
  2714. ${ _('Query needs to be saved.') }
  2715. <!-- /ko -->
  2716. <!-- ko if: isSaved() && ! isHistory() -->
  2717. <!-- ko if: schedulerViewModelIsLoaded() && schedulerViewModel.coordinator.isDirty() -->
  2718. <a data-bind="click: saveScheduler" href="javascript: void(0);">${ _('Save changes') }</a>
  2719. <!-- /ko -->
  2720. <!-- ko if: schedulerViewModelIsLoaded() && ! schedulerViewModel.coordinator.isDirty() && (! viewSchedulerId() || isSchedulerJobRunning() == false )-->
  2721. <a data-bind="click: showSubmitPopup" href="javascript: void(0);">${ _('Start') }</a>
  2722. <!-- /ko -->
  2723. <!-- ko if: schedulerViewModelIsLoaded() && viewSchedulerId()-->
  2724. <a data-bind="click: function() { huePubSub.publish('show.jobs.panel', {id: viewSchedulerId(), interface: 'schedules'}) }, clickBubble: false" href="javascript: void(0);">
  2725. ${ _('View') }
  2726. </a>
  2727. <!-- ko if: isSchedulerJobRunning() -->
  2728. ${ _("Running")}
  2729. <!-- /ko -->
  2730. <!-- ko if: isSchedulerJobRunning() == false -->
  2731. ${ _("Stopped")}
  2732. <!-- /ko -->
  2733. <!-- /ko -->
  2734. <!-- /ko -->
  2735. <br>
  2736. <br>
  2737. <div id="schedulerEditor"></div>
  2738. </div>
  2739. <!-- /ko -->
  2740. <!-- /ko -->
  2741. </div>
  2742. </div>
  2743. </script>
  2744. <script type="text/javascript">
  2745. (function () {
  2746. function SchedulePanel(params) {
  2747. var self = this;
  2748. self.disposals = [];
  2749. self.selectedNotebook = ko.observable();
  2750. // TODO: Move all the scheduler logic out of the notebook to here.
  2751. var selectedNotebookSub = self.selectedNotebook.subscribe(function (notebook) { // Happening 4 times for each notebook loaded
  2752. if (notebook && notebook.schedulerViewModel == null && notebook.isSaved() && ! notebook.isHistory()) {
  2753. notebook.loadScheduler();
  2754. if (notebook.viewSchedulerId()) {
  2755. huePubSub.publish('check.schedules.browser');
  2756. }
  2757. }
  2758. });
  2759. self.disposals.push(selectedNotebookSub.dispose.bind(selectedNotebookSub));
  2760. var setSelectedNotebookSub = huePubSub.subscribe('jobbrowser.schedule.data', function (jobs) {
  2761. if (self.selectedNotebook() && self.selectedNotebook().viewSchedulerId()) {
  2762. var _job = $.grep(jobs, function (job) {
  2763. return self.selectedNotebook().viewSchedulerId() == job.id;
  2764. });
  2765. self.selectedNotebook().isSchedulerJobRunning(_job.length > 0 && _job[0].apiStatus == 'RUNNING');
  2766. }
  2767. });
  2768. self.disposals.push(setSelectedNotebookSub.remove.bind(setSelectedNotebookSub));
  2769. // Hue 3
  2770. var setSelectedNotebookSub = huePubSub.subscribe('set.selected.notebook', self.selectedNotebook);
  2771. self.disposals.push(setSelectedNotebookSub.remove.bind(setSelectedNotebookSub));
  2772. var selectedNotebookChangedSub = huePubSub.subscribe('selected.notebook.changed', self.selectedNotebook);
  2773. self.disposals.push(selectedNotebookChangedSub.remove.bind(selectedNotebookChangedSub));
  2774. huePubSub.publish('get.selected.notebook');
  2775. // Hue 4
  2776. var currentAppSub = huePubSub.subscribe('set.current.app.view.model', function (viewModel) {
  2777. if (viewModel.selectedNotebook) {
  2778. if (viewModel.selectedNotebook()) {
  2779. self.selectedNotebook(viewModel.selectedNotebook());
  2780. } else {
  2781. var subscription = viewModel.selectedNotebook.subscribe(function (notebook) {
  2782. self.selectedNotebook(notebook);
  2783. subscription.dispose();
  2784. });
  2785. }
  2786. } else {
  2787. self.selectedNotebook(null);
  2788. }
  2789. });
  2790. self.disposals.push(currentAppSub.remove.bind(currentAppSub));
  2791. }
  2792. SchedulePanel.prototype.dispose = function () {
  2793. var self = this;
  2794. self.disposals.forEach(function (dispose) {
  2795. dispose();
  2796. })
  2797. };
  2798. ko.components.register('schedule-panel', {
  2799. viewModel: SchedulePanel,
  2800. template: { element: 'schedule-panel-template' }
  2801. });
  2802. })();
  2803. </script>
  2804. <script type="text/javascript">
  2805. (function () {
  2806. function DashboardAssistantPanel(params) {
  2807. var self = this;
  2808. self.disposals = [];
  2809. self.isSolr = ko.observable(true);
  2810. self.filter = {
  2811. querySpec: ko.observable({
  2812. query: '',
  2813. facets: {},
  2814. text: []
  2815. }).extend({ rateLimit: 300 })
  2816. };
  2817. self.activeTables = ko.observableArray();
  2818. self.filteredTables = AssistantUtils.getFilteredTablesPureComputed(self);
  2819. self.someLoading = ko.pureComputed(function () {
  2820. return self.activeTables().some(function (table) {
  2821. return table.loading() || (!table.hasEntries() && !table.hasErrors());
  2822. });
  2823. });
  2824. var navigationSettings = {
  2825. showStats: true,
  2826. rightAssist: true
  2827. };
  2828. var i18n = {};
  2829. var activeDashboardCollection = huePubSub.subscribe('set.active.dashboard.collection', function(collection) {
  2830. var collectionName = collection.name();
  2831. if (!collectionName) {
  2832. return;
  2833. }
  2834. var assistDbSource = new AssistDbSource({
  2835. i18n : i18n,
  2836. initialNamespace: collection.activeNamespace,
  2837. initialCompute: collection.activeCompute,
  2838. type: collection.engine(),
  2839. name: collection.engine(),
  2840. navigationSettings: navigationSettings
  2841. });
  2842. var fakeParentName = collectionName.indexOf('.') > -1 ? collectionName.split('.')[0] : 'default';
  2843. var sourceType = collection.source() === 'query' ? collection.engine() + '-query' : collection.engine();
  2844. DataCatalog.getEntry({
  2845. sourceType: sourceType,
  2846. namespace: collection.activeNamespace,
  2847. compute: collection.activeCompute,
  2848. path: [ fakeParentName ],
  2849. definition: { type: 'database' }
  2850. }).done(function (fakeDbCatalogEntry) {
  2851. var assistFakeDb = new AssistDbEntry(fakeDbCatalogEntry, null, assistDbSource, self.filter, i18n, navigationSettings);
  2852. DataCatalog.getEntry({
  2853. sourceType: sourceType,
  2854. namespace: collection.activeNamespace,
  2855. compute: collection.activeCompute,
  2856. path: [fakeParentName, collectionName.indexOf('.') > -1 ? collectionName.split('.')[1] : collectionName],
  2857. definition: { type: 'table' }
  2858. }).done(function (collectionCatalogEntry) {
  2859. var collectionEntry = new AssistDbEntry(collectionCatalogEntry, assistFakeDb, assistDbSource, self.filter, i18n, navigationSettings);
  2860. self.activeTables([collectionEntry]);
  2861. if (!collectionEntry.loaded && !collectionEntry.hasErrors() && !collectionEntry.loading()) {
  2862. collectionEntry.loadEntries(function() { collectionEntry.toggleOpen(); });
  2863. }
  2864. });
  2865. });
  2866. self.autocompleteFromEntries = function (nonPartial, partial) {
  2867. var added = {};
  2868. var result = [];
  2869. var partialLower = partial.toLowerCase();
  2870. self.activeTables().forEach(function (table) {
  2871. if (!added[table.catalogEntry.name] && table.catalogEntry.name.toLowerCase().indexOf(partialLower) === 0) {
  2872. added[table.catalogEntry.name] = true;
  2873. result.push(nonPartial + partial + table.catalogEntry.name.substring(partial.length))
  2874. }
  2875. table.entries().forEach(function (col) {
  2876. if (!added[col.catalogEntry.name] && col.catalogEntry.name.toLowerCase().indexOf(partialLower) === 0) {
  2877. added[col.catalogEntry.name] = true;
  2878. result.push(nonPartial + partial + col.catalogEntry.name.substring(partial.length))
  2879. }
  2880. })
  2881. });
  2882. return result;
  2883. };
  2884. });
  2885. self.disposals.push(function () {
  2886. activeDashboardCollection.remove();
  2887. });
  2888. }
  2889. DashboardAssistantPanel.prototype.dispose = function () {
  2890. var self = this;
  2891. self.disposals.forEach(function (dispose) {
  2892. dispose();
  2893. })
  2894. };
  2895. ko.components.register('dashboard-assistant-panel', {
  2896. viewModel: DashboardAssistantPanel,
  2897. template: { element: 'editor-assistant-panel-template' }
  2898. });
  2899. })();
  2900. </script>
  2901. <script type="text/html" id="right-assist-panel-template">
  2902. <div style="height: 100%; width: 100%; position: relative;">
  2903. <ul class="right-panel-tabs nav nav-pills">
  2904. <li data-bind="css: { 'active' : activeTab() === 'editorAssistant' }, visible: editorAssistantTabAvailable" style="display:none;"><a href="javascript: void(0);" data-bind="click: function() { lastActiveTabEditor('editorAssistant'); activeTab('editorAssistant'); }">${ _('Assistant') }</a></li>
  2905. <li data-bind="css: { 'active' : activeTab() === 'functions' }, visible: functionsTabAvailable" style="display:none;"><a href="javascript: void(0);" data-bind="click: function() { lastActiveTabEditor('functions'); activeTab('functions'); }">${ _('Functions') }</a></li>
  2906. <li data-bind="css: { 'active' : activeTab() === 'schedules' }, visible: schedulesTabAvailable" style="display:none;"><a href="javascript: void(0);" data-bind="click: function() { lastActiveTabEditor('schedules'); activeTab('schedules'); }">${ _('Schedule') }</a></li>
  2907. <li data-bind="css: { 'active' : activeTab() === 'dashboardAssistant' }, visible: dashboardAssistantTabAvailable" style="display:none;"><a href="javascript: void(0);" data-bind="click: function() { lastActiveTabDashboard('dashboardAssistant'); activeTab('dashboardAssistant'); }">${ _('Assistant') }</a></li>
  2908. </ul>
  2909. <div class="right-panel-tab-content tab-content">
  2910. <!-- ko if: editorAssistantTabAvailable-->
  2911. <div data-bind="component: { name: 'editor-assistant-panel', params: { activeTab: activeTab } }, visible: activeTab() === 'editorAssistant'"></div>
  2912. <!-- /ko -->
  2913. <!-- ko if: functionsTabAvailable -->
  2914. <div data-bind="component: { name: 'functions-panel' }, visible: activeTab() === 'functions'"></div>
  2915. <!-- /ko -->
  2916. <!-- ko if: dashboardAssistantTabAvailable -->
  2917. <div data-bind="component: { name: 'dashboard-assistant-panel' }, visible: activeTab() === 'dashboardAssistant'"></div>
  2918. <!-- /ko -->
  2919. ## TODO: Switch to if: when loadSchedules from notebook.ko.js has been moved to the schedule-panel component
  2920. <div data-bind="component: { name: 'schedule-panel' }, visible: activeTab() === 'schedules'" style="display:none;"></div>
  2921. </div>
  2922. </div>
  2923. </script>
  2924. <script type="text/javascript">
  2925. (function () {
  2926. var EDITOR_ASSISTANT_TAB = 'editorAssistant';
  2927. var DASHBOARD_ASSISTANT_TAB = 'dashboardAssistant';
  2928. var FUNCTIONS_TAB = 'functions';
  2929. var SCHEDULES_TAB = 'schedules';
  2930. function RightAssistPanel(params) {
  2931. var self = this;
  2932. self.disposals = [];
  2933. self.activeTab = ko.observable();
  2934. self.editorAssistantTabAvailable = ko.observable(false);
  2935. self.dashboardAssistantTabAvailable = ko.observable(false);
  2936. self.functionsTabAvailable = ko.observable(false);
  2937. self.schedulesTabAvailable = ko.observable(false);
  2938. var apiHelper = ApiHelper.getInstance();
  2939. self.lastActiveTabEditor = apiHelper.withTotalStorage('assist', 'last.open.right.panel', ko.observable(), EDITOR_ASSISTANT_TAB);
  2940. self.lastActiveTabDashboard = apiHelper.withTotalStorage('assist', 'last.open.right.panel.dashboard', ko.observable(), DASHBOARD_ASSISTANT_TAB);
  2941. var assistEnabledApp = false;
  2942. huePubSub.subscribe('assist.highlight.risk.suggestions', function () {
  2943. if (self.editorAssistantTabAvailable() && self.activeTab() !== EDITOR_ASSISTANT_TAB) {
  2944. self.activeTab(EDITOR_ASSISTANT_TAB);
  2945. }
  2946. });
  2947. var updateTabs = function () {
  2948. if (!assistEnabledApp) {
  2949. params.rightAssistAvailable(false);
  2950. return;
  2951. }
  2952. var rightAssistAvailable = true;
  2953. if (self.lastActiveTabEditor() === FUNCTIONS_TAB && self.functionsTabAvailable()) {
  2954. self.activeTab(FUNCTIONS_TAB);
  2955. } else if (self.lastActiveTabEditor() === SCHEDULES_TAB && self.schedulesTabAvailable()) {
  2956. self.activeTab(SCHEDULES_TAB);
  2957. } else if (self.editorAssistantTabAvailable()) {
  2958. self.activeTab(EDITOR_ASSISTANT_TAB);
  2959. } else if (self.functionsTabAvailable()) {
  2960. self.activeTab(FUNCTIONS_TAB);
  2961. } else if (self.schedulesTabAvailable()) {
  2962. self.activeTab(SCHEDULES_TAB);
  2963. } else if (self.dashboardAssistantTabAvailable()) {
  2964. self.activeTab(DASHBOARD_ASSISTANT_TAB);
  2965. } else {
  2966. self.activeTab(null);
  2967. rightAssistAvailable = false;
  2968. }
  2969. params.rightAssistAvailable(rightAssistAvailable);
  2970. };
  2971. var updateContentsForType = function (type) {
  2972. self.functionsTabAvailable(type === 'hive' || type === 'impala' || type === 'pig');
  2973. self.editorAssistantTabAvailable(type === 'hive' || type === 'impala');
  2974. self.dashboardAssistantTabAvailable(type === 'dashboard');
  2975. self.schedulesTabAvailable(false);
  2976. if (type !== 'dashboard') {
  2977. if ('${ ENABLE_QUERY_SCHEDULING.get() }' === 'True' && IS_HUE_4) {
  2978. huePubSub.subscribeOnce('set.current.app.view.model', function (viewModel) {
  2979. // Async
  2980. self.schedulesTabAvailable(!!viewModel.selectedNotebook);
  2981. updateTabs();
  2982. });
  2983. huePubSub.publish('get.current.app.view.model');
  2984. } else {
  2985. // Right assist is only available in the Hue 3 editor and notebook.
  2986. self.schedulesTabAvailable('${ ENABLE_QUERY_SCHEDULING.get() }' === 'True');
  2987. }
  2988. }
  2989. updateTabs();
  2990. };
  2991. var snippetTypeSub = huePubSub.subscribe('active.snippet.type.changed', updateContentsForType);
  2992. self.disposals.push(snippetTypeSub.remove.bind(snippetTypeSub));
  2993. if (IS_HUE_4) {
  2994. huePubSub.subscribe('set.current.app.name', function (appName) {
  2995. assistEnabledApp = appName === 'editor' || appName === 'notebook' || appName === 'dashboard';
  2996. if (!assistEnabledApp) {
  2997. params.rightAssistAvailable(false);
  2998. }
  2999. if (appName === 'dashboard') {
  3000. updateContentsForType(appName);
  3001. }
  3002. });
  3003. huePubSub.publish('get.current.app.name');
  3004. } else {
  3005. assistEnabledApp = true;
  3006. }
  3007. updateTabs();
  3008. }
  3009. RightAssistPanel.prototype.dispose = function () {
  3010. var self = this;
  3011. self.disposals.forEach(function (dispose) {
  3012. dispose();
  3013. })
  3014. };
  3015. ko.components.register('right-assist-panel', {
  3016. viewModel: RightAssistPanel,
  3017. template: { element: 'right-assist-panel-template' }
  3018. });
  3019. })();
  3020. </script>
  3021. </%def>