assist.mako 137 KB

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