assist.mako 87 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024
  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 desktop import conf
  18. from desktop.conf import USE_NEW_SIDE_PANELS
  19. from desktop.lib.i18n import smart_unicode
  20. from desktop.views import _ko
  21. from django.utils.translation import ugettext as _
  22. from metadata.conf import has_navigator
  23. %>
  24. <%def name="assistJSModels()">
  25. <script src="${ static('desktop/js/assist/assistDbEntry.js') }"></script>
  26. <script src="${ static('desktop/js/assist/assistDbSource.js') }"></script>
  27. <script src="${ static('desktop/js/assist/assistHdfsEntry.js') }"></script>
  28. <script src="${ static('desktop/js/assist/assistS3Entry.js') }"></script>
  29. <script src="${ static('desktop/js/assist/assistCollectionEntry.js') }"></script>
  30. <script src="${ static('desktop/js/assist/assistHBaseEntry.js') }"></script>
  31. <script src="${ static('desktop/js/document/hueDocument.js') }"></script>
  32. <script src="${ static('desktop/js/document/hueFileEntry.js') }"></script>
  33. </%def>
  34. <%def name="assistPanel(is_s3_enabled=False)">
  35. <%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
  36. <%namespace name="nav_components" file="/nav_components.mako" />
  37. ${ sqlContextPopover.sqlContextPopover() }
  38. ${ nav_components.nav_tags(readOnly=not user.has_hue_permission(action="write", app="metadata")) }
  39. <style>
  40. .assist-icon {
  41. width: 16px;
  42. height: 16px;
  43. -webkit-filter: grayscale(1);
  44. filter: grayscale(1);
  45. opacity: .8;
  46. }
  47. .assist {
  48. position: relative;
  49. height: 100%;
  50. }
  51. .assist-resizer {
  52. cursor: row-resize;
  53. }
  54. .assist-spinner {
  55. font-size: 20px;
  56. color: #BBB;
  57. }
  58. .assist-header {
  59. -ms-flex: 1;
  60. flex: 1;
  61. color: #338bb8;
  62. background-color: #f9f9f9;
  63. border-top: 1px solid #f1f1f1;
  64. border-bottom: 1px solid #f1f1f1;
  65. font-weight: bold;
  66. letter-spacing: 0.035em;
  67. font-size: 0.975em;
  68. line-height: 25px;
  69. padding-left: 10px;
  70. height: 24px;
  71. margin-bottom: 8px;
  72. }
  73. .assist-inner-panel {
  74. position: absolute;
  75. overflow: hidden;
  76. padding-right: 3px;
  77. top: 10px;
  78. right: 0;
  79. bottom: 2px;
  80. left: 10px;
  81. }
  82. .assist-inner-header {
  83. width: 100%;
  84. color: #737373;
  85. margin-left:3px;
  86. margin-bottom:2px;
  87. font-weight: bold;
  88. margin-top: 0
  89. }
  90. .assist-stretchable-list {
  91. position:relative;
  92. overflow-y: auto;
  93. overflow-x: hidden;
  94. width: 100%;
  95. border: none;
  96. padding: 0;
  97. margin-bottom: 1px;
  98. margin-top:3px;
  99. }
  100. .assist-header-actions {
  101. float: right;
  102. margin-right: 3px;
  103. opacity: 0;
  104. }
  105. .assist-header-actions > div {
  106. cursor: pointer;
  107. }
  108. .assist-panel-switches {
  109. padding-left: 12px;
  110. height: 40px;
  111. border-bottom: 1px solid #f1f1f1;
  112. }
  113. .assist-type-switch {
  114. display: inline-block;
  115. font-size: 18px;
  116. margin-right: 2px;
  117. cursor: pointer;
  118. }
  119. .assist-column {
  120. position: relative;
  121. }
  122. .assist-entry,a {
  123. white-space: nowrap;
  124. }
  125. .assist-file-entry {
  126. margin-right: 15px;
  127. border: 1px solid transparent;
  128. }
  129. .assist-file-entry-drop {
  130. border: 1px solid #338BB8 !important;
  131. }
  132. .assist-tables {
  133. margin-left: 0;
  134. }
  135. .assist-tables a {
  136. text-decoration: none;
  137. }
  138. .assist-tables li {
  139. list-style: none;
  140. }
  141. .assist-breadcrumb > a:hover {
  142. color: #338bb8;
  143. }
  144. .assist-errors {
  145. padding: 4px 5px;
  146. font-style: italic;
  147. }
  148. .assist-tables > li {
  149. position: relative;
  150. padding-top: 2px;
  151. padding-bottom: 2px;
  152. padding-left: 4px;
  153. margin-right: 15px;
  154. overflow-x: hidden;
  155. }
  156. .assist-tables > li.selected {
  157. background-color: #EEE;
  158. }
  159. .assist-breadcrumb {
  160. padding-top: 0;
  161. padding-left: 0;
  162. }
  163. .assist-breadcrumb span {
  164. color: #737373;
  165. }
  166. .assist-breadcrumb a:not(.inactive-action) {
  167. cursor: pointer;
  168. text-decoration: none;
  169. color: #737373;
  170. -webkit-transition: color 0.2s ease;
  171. -moz-transition: color 0.2s ease;
  172. -ms-transition: color 0.2s ease;
  173. transition: color 0.2s ease;
  174. }
  175. .assist-breadcrumb-text {
  176. font-size: 14px;
  177. line-height: 16px;
  178. vertical-align: top;
  179. }
  180. .assist-breadcrumb-back {
  181. font-size: 15px;
  182. margin-right:8px;
  183. }
  184. .assist-tables-counter {
  185. color: #d1d1d1;
  186. font-weight: normal;
  187. }
  188. .assist-table-link {
  189. font-size: 13px;
  190. }
  191. .assist-field-link {
  192. font-size: 12px;
  193. }
  194. .assist-table-link,
  195. .assist-table-link:focus {
  196. color: #444;
  197. }
  198. .assist-field-link,
  199. .assist-field-link:focus {
  200. white-space: nowrap;
  201. color: #737373;
  202. }
  203. .assist-db-header-actions {
  204. position:absolute;
  205. top: 0;
  206. right: 0;
  207. padding-left:4px;
  208. padding-right: 13px;
  209. background-color: #FFF;
  210. }
  211. .assist-db-header-actions > * {
  212. margin-left: 2px;
  213. }
  214. .assist-actions {
  215. position:absolute;
  216. top: 0;
  217. right: 0;
  218. padding-left:4px;
  219. background-color: #FFF;
  220. }
  221. .assist-file-actions {
  222. position:absolute;
  223. top: 0;
  224. right: 0;
  225. padding-right: 2px;
  226. padding-left:4px;
  227. background-color: #FFF;
  228. }
  229. .table-actions {
  230. padding-top:2px;
  231. }
  232. .assist-tables > li.selected .assist-actions {
  233. background-color: #EEE;
  234. }
  235. .assist-details-wrap {
  236. display: table;
  237. width: 100%;
  238. table-layout: fixed;
  239. }
  240. .assist-details-wrap > div {
  241. display: table-row;
  242. }
  243. .highlightable {
  244. -webkit-transition: all .5s linear;
  245. -moz-transition: all .5s linear;
  246. -o-transition: all .5s linear;
  247. transition: all .5s linear;
  248. }
  249. .highlight {
  250. color: #338BB8 !important;
  251. padding-left: 8px;
  252. }
  253. .assist-details-header {
  254. display: table-cell;
  255. width: 95px;
  256. font-weight: bold;
  257. }
  258. .assist-details-value {
  259. display: table-cell;
  260. }
  261. .no-entries {
  262. font-style: italic;
  263. }
  264. .assist-flex-panel {
  265. position: relative;
  266. display: -ms-flexbox;
  267. display: flex;
  268. -ms-flex-flow: column nowrap;
  269. flex-flow: column nowrap;
  270. align-items: stretch;
  271. height:100%;
  272. }
  273. .assist-flex-header {
  274. overflow: hidden;
  275. position: relative;
  276. -ms-flex: 0 0 25px;
  277. flex: 0 0 25px;
  278. white-space: nowrap;
  279. }
  280. .assist-flex-table-search {
  281. overflow: hidden;
  282. position: relative;
  283. -ms-flex: 0 0 65px;
  284. flex: 0 0 65px;
  285. white-space: nowrap;
  286. }
  287. .assist-flex-search {
  288. overflow: hidden;
  289. position: relative;
  290. -ms-flex: 0 0 43px;
  291. flex: 0 0 43px;
  292. white-space: nowrap;
  293. }
  294. .assist-flex-fill {
  295. position: relative;
  296. -ms-flex: 1 1 100%;
  297. flex: 1 1 100%;
  298. white-space: nowrap;
  299. overflow-x: hidden;
  300. overflow-y: auto;
  301. outline: none !important;
  302. }
  303. .database-tree ul {
  304. margin: 0 !important;
  305. }
  306. .database-tree ul li {
  307. padding-left: 15px;
  308. }
  309. .result-entry {
  310. position: relative;
  311. clear: both;
  312. overflow: hidden;
  313. margin: 0 10px 15px 10px;
  314. }
  315. .result-entry .doc-desc {
  316. font-style: italic;
  317. font-size: 12px;
  318. line-height: 15px;
  319. white-space: normal;
  320. margin-left: 35px;
  321. }
  322. .nav-search-tags {
  323. display: inline-block;
  324. margin-left: 3px;
  325. }
  326. .nav-search-tags div {
  327. display: inline-block;
  328. margin: 0 1px;
  329. line-height: 10px;
  330. font-size: 11px;
  331. padding: 3px 6px;
  332. color: #FFF;
  333. background-color: #338BB8;
  334. border-radius: 6px;
  335. }
  336. .result-entry .icon-col {
  337. width: 35px;
  338. float:left;
  339. vertical-align: top;
  340. padding-top: 7px;
  341. font-size: 20px;
  342. color: #338bb8;
  343. }
  344. .result-entry .doc-col {
  345. white-space: nowrap;
  346. }
  347. .doc-col-no-desc {
  348. padding-top: 7px;
  349. }
  350. .result-entry .hue-icon {
  351. font-size: 30px;
  352. }
  353. </style>
  354. <script type="text/html" id="assist-no-database-entries">
  355. <ul class="assist-tables">
  356. <li>
  357. <span style="font-style: italic">${_('The database has no tables')}</span>
  358. </li>
  359. </ul>
  360. </script>
  361. <script type="text/html" id="assist-no-table-entries">
  362. <ul>
  363. <li>
  364. <span style="font-style: italic" class="assist-entry assist-field-link">${_('The table has no columns')}</span>
  365. </li>
  366. </ul>
  367. </script>
  368. <script type="text/html" id="assist-entry-actions">
  369. <div class="assist-actions" data-bind="css: { 'table-actions' : definition.isTable || definition.isView, 'column-actions': definition.isColumn, 'database-actions' : definition.isDatabase } " style="opacity: 0">
  370. <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>
  371. <a class="inactive-action" href="javascript:void(0)" data-bind="visible: navigationSettings.openItem || (navigationSettings.openDatabase && definition.isDatabase), click: openItem"><i class="fa fa-long-arrow-right" title="${_('Open')}"></i></a>
  372. </div>
  373. </script>
  374. <script type="text/html" id="sql-context-items">
  375. <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>
  376. <li><a href="javascript:void(0);" data-bind="click: dblClick"><i class="fa fa-fw fa-pencil"></i> ${ _('Insert') }</a></li>
  377. <!-- ko if: definition.isColumn -->
  378. <li class="divider"></li>
  379. <!-- ko template: { name: 'query-builder-context-items' } --><!-- /ko -->
  380. <!-- /ko -->
  381. </script>
  382. <script type="text/html" id="query-builder-context-items">
  383. <li data-bind="contextSubMenu: '.hue-context-sub-menu'">
  384. <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>
  385. <ul class="hue-context-menu hue-context-sub-menu">
  386. <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Select', 'Project', '{0}', false, false); }">${ _('Select') }</a></li>
  387. <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>
  388. </ul>
  389. </li>
  390. <li data-bind="contextSubMenu: '.hue-context-sub-menu'">
  391. <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>
  392. <ul class="hue-context-menu hue-context-sub-menu">
  393. <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>
  394. <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>
  395. <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>
  396. <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>
  397. <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>
  398. <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>
  399. </ul>
  400. </li>
  401. <li data-bind="contextSubMenu: '.hue-context-sub-menu'">
  402. <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>
  403. <ul class="hue-context-menu hue-context-sub-menu">
  404. <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>
  405. <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>
  406. <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>
  407. <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>
  408. <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>
  409. <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>
  410. </ul>
  411. </li>
  412. <li data-bind="contextSubMenu: '.hue-context-sub-menu'">
  413. <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>
  414. <ul class="hue-context-menu hue-context-sub-menu">
  415. <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>
  416. <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>
  417. </ul>
  418. </li>
  419. </script>
  420. <script type="text/html" id="assist-table-entry">
  421. <li class="assist-table" data-bind="templateContextMenu: { template: 'sql-context-items', scrollContainer: '.assist-db-scrollable' }, visibleOnHover: { override: statsVisible, selector: '.table-actions' }">
  422. <div class="assist-actions table-actions" style="opacity: 0">
  423. <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>
  424. <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>
  425. </div>
  426. <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} }">
  427. <i class="fa fa-fw fa-table muted valign-middle" data-bind="css: { 'fa-eye': definition.isView, 'fa-table': definition.isTable }"></i>
  428. <span data-bind="text: definition.displayName, css: { 'highlight': highlight }"></span>
  429. </a>
  430. <div class="center" data-bind="visible: loading"><i class="fa fa-spinner fa-spin assist-spinner"></i></div>
  431. <!-- ko template: { if: open, name: 'assist-db-entries' } --><!-- /ko -->
  432. </li>
  433. </script>
  434. <script type="text/html" id="assist-column-entry">
  435. <li data-bind="templateContextMenu: { 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 }">
  436. <div class="assist-actions column-actions" style="opacity: 0">
  437. <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>
  438. </div>
  439. <!-- ko if: expandable -->
  440. <a class="assist-entry assist-field-link" href="javascript:void(0)" data-bind="click: toggleOpen, attr: {'title': definition.title }">
  441. <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>
  442. </a>
  443. <!-- /ko -->
  444. <!-- ko ifnot: expandable -->
  445. <div style="cursor: default;" class="assist-entry assist-field-link" href="javascript:void(0)" data-bind="event: { dblClick: dblClick }, attr: {'title': definition.title }">
  446. <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>
  447. </div>
  448. <!-- /ko -->
  449. <div class="center" data-bind="visible: loading"><i class="fa fa-spinner fa-spin assist-spinner"></i></div>
  450. <!-- ko template: { if: open, name: 'assist-db-entries' } --><!-- /ko -->
  451. </li>
  452. </script>
  453. <script type="text/html" id="assist-db-entries">
  454. <!-- ko if: ! hasErrors() && hasEntries() && ! loading() && filteredEntries().length == 0 -->
  455. <ul class="assist-tables">
  456. <li class="assist-entry no-entries">${_('No results found')}</li>
  457. </ul>
  458. <!-- /ko -->
  459. <!-- ko if: ! hasErrors() && hasEntries() && ! loading() && filteredEntries().length > 0 -->
  460. <ul class="database-tree" data-bind="foreachVisible: { data: filteredEntries, minHeight: (definition.isTable || definition.isView ? 20 : 25), container: '.assist-db-scrollable' }, css: { 'assist-tables': definition.isDatabase }">
  461. <!-- ko template: { if: definition.isTable || definition.isView, name: 'assist-table-entry' } --><!-- /ko -->
  462. <!-- ko template: { ifnot: definition.isTable || definition.isView, name: 'assist-column-entry' } --><!-- /ko -->
  463. </ul>
  464. <!-- /ko -->
  465. <!-- ko template: { if: ! hasEntries() && ! loading() && (definition.isTable || definition.isView), name: 'assist-no-table-entries' } --><!-- /ko -->
  466. <!-- ko template: { if: ! hasEntries() && ! loading() && definition.isDatabase, name: 'assist-no-database-entries' } --><!-- /ko -->
  467. <!-- ko if: hasErrors -->
  468. <ul class="assist-tables">
  469. <!-- ko if: definition.isTable -->
  470. <li class="assist-errors">${ _('Error loading columns.') }</li>
  471. <!-- /ko -->
  472. <!-- ko ifnot: definition.isTable -->
  473. <li class="assist-errors">${ _('Error loading fields.') }</li>
  474. <!-- /ko -->
  475. </ul>
  476. <!-- /ko -->
  477. </script>
  478. <script type="text/html" id="assist-db-breadcrumb">
  479. <div class="assist-flex-header assist-breadcrumb">
  480. <!-- ko if: selectedSource() && ! selectedSource().selectedDatabase() && sources().length === 1 -->
  481. <i class="fa fa-server assist-breadcrumb-text"></i>
  482. <span class="assist-breadcrumb-text" data-bind="text: breadcrumb"></span>
  483. <!-- /ko -->
  484. <!-- ko if: selectedSource() && ! selectedSource().selectedDatabase() && sources().length > 1 -->
  485. <a data-bind="click: back">
  486. <i class="fa fa-chevron-left assist-breadcrumb-back"></i>
  487. <i class="fa fa-server assist-breadcrumb-text"></i>
  488. <span class="assist-breadcrumb-text" data-bind="text: breadcrumb"></span>
  489. </a>
  490. <!-- /ko -->
  491. <!-- ko if: selectedSource() && selectedSource().selectedDatabase() -->
  492. <a data-bind="click: back">
  493. <i class="fa fa-chevron-left assist-breadcrumb-back" ></i>
  494. <i class="fa fa-database assist-breadcrumb-text"></i>
  495. <span class="assist-breadcrumb-text" data-bind="text: breadcrumb"></span>
  496. </a>
  497. <!-- /ko -->
  498. </div>
  499. </script>
  500. <script type="text/html" id="assist-sql-inner-panel">
  501. <div class="assist-inner-panel">
  502. <div class="assist-flex-panel">
  503. <!-- ko template: { if: breadcrumb() !== null, name: 'assist-db-breadcrumb' } --><!-- /ko -->
  504. <!-- ko template: { ifnot: selectedSource, name: 'assist-sources-template' } --><!-- /ko -->
  505. <!-- ko with: selectedSource -->
  506. <!-- ko template: { ifnot: selectedDatabase, name: 'assist-databases-template' }--><!-- /ko -->
  507. <!-- ko with: selectedDatabase -->
  508. <!-- ko template: { name: 'assist-tables-template' } --><!-- /ko -->
  509. <!-- /ko -->
  510. <!-- /ko -->
  511. </div>
  512. <!-- ko with: $parents[1] -->
  513. <!-- ko template: { if: searchActive() && searchInput() !== '' && navigatorEnabled(), name: 'nav-search-result' } --><!-- /ko -->
  514. <!-- /ko -->
  515. </div>
  516. </script>
  517. <script type="text/html" id="s3-details-content">
  518. <!-- ko with: definition -->
  519. <div class="assist-details-wrap">
  520. <div><div class="assist-details-header">${ _('Size') }</div><div class="assist-details-value" data-bind="text: humansize"></div></div>
  521. <div><div class="assist-details-header">${ _('Permissions') }</div><div class="assist-details-value" data-bind="text: rwx"></div></div>
  522. </div>
  523. <!-- /ko -->
  524. </script>
  525. <script type="text/html" id="s3-details-title">
  526. <span data-bind="text: definition.name"></span>
  527. </script>
  528. <script type="text/html" id="assist-s3-header-actions">
  529. <div class="assist-db-header-actions" style="margin-top: -1px;">
  530. <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>
  531. </div>
  532. </script>
  533. <script type="text/html" id="assist-s3-inner-panel">
  534. <div class="assist-inner-panel">
  535. <div class="assist-flex-panel">
  536. <!-- ko with: selectedS3Entry -->
  537. <div class="assist-flex-header assist-breadcrumb" >
  538. <!-- ko if: parent !== null -->
  539. <a href="javascript: void(0);" data-bind="click: function () { huePubSub.publish('assist.selectS3Entry', parent); }">
  540. <i class="fa fa-chevron-left" style="font-size: 15px;margin-right:8px;"></i>
  541. <i class="fa fa-folder-o" style="font-size: 14px; line-height: 16px; vertical-align: top; margin-right:4px;"></i>
  542. <span style="font-size: 14px;line-height: 16px;vertical-align: top;" data-bind="text: path"></span>
  543. </a>
  544. <!-- /ko -->
  545. <!-- ko if: parent === null -->
  546. <div>
  547. <i class="fa fa-folder-o" style="font-size: 14px; line-height: 16px;vertical-align: top; margin-right:4px;"></i>
  548. <span style="font-size: 14px;line-height: 16px;vertical-align: top;" data-bind="text: path"></span>
  549. </div>
  550. <!-- /ko -->
  551. <!-- ko template: 'assist-s3-header-actions' --><!-- /ko -->
  552. </div>
  553. <div class="assist-flex-fill assist-s3-scrollable">
  554. <div data-bind="visible: ! loading() && ! hasErrors()" style="position: relative;">
  555. <!-- ko hueSpinner: { spin: loadingMore, overlay: true } --><!-- /ko -->
  556. <ul class="assist-tables" data-bind="foreachVisible: { data: entries, minHeight: 20, container: '.assist-s3-scrollable', fetchMore: $data.fetchMore.bind($data) }">
  557. <li class="assist-entry assist-table-link" style="position: relative;" data-bind="visibleOnHover: { 'selector': '.assist-actions' }">
  558. <div class="assist-actions table-actions" style="opacity: 0;" >
  559. <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' }">
  560. <i class='fa fa-info' title="${ _('Details') }"></i>
  561. </a>
  562. </div>
  563. <a href="javascript:void(0)" class="assist-entry assist-table-link" data-bind="multiClick: { click: toggleOpen, dblClick: dblClick }, attr: {'title': definition.name }">
  564. <!-- ko if: definition.type === 'dir' -->
  565. <i class="fa fa-fw fa-folder-o muted valign-middle"></i>
  566. <!-- /ko -->
  567. <!-- ko if: definition.type === 'file' -->
  568. <i class="fa fa-fw fa-file-o muted valign-middle"></i>
  569. <!-- /ko -->
  570. <span draggable="true" data-bind="text: definition.name, draggableText: { text: '\'' + path + '\'', meta: {'type': 's3', 'definition': definition} }"></span>
  571. </a>
  572. </li>
  573. </ul>
  574. <!-- ko if: !loading() && entries().length === 0 -->
  575. <ul class="assist-tables">
  576. <li class="assist-entry" style="font-style: italic;">${_('Empty directory')}</li>
  577. </ul>
  578. <!-- /ko -->
  579. </div>
  580. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  581. <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
  582. <span>${ _('Error loading contents.') }</span>
  583. </div>
  584. </div>
  585. <!-- /ko -->
  586. </div>
  587. <!-- ko with: $parents[1] -->
  588. <!-- ko template: { if: searchActive() && searchInput() !== '' && navigatorEnabled(), name: 'nav-search-result' } --><!-- /ko -->
  589. <!-- /ko -->
  590. </div>
  591. </script>
  592. <script type="text/html" id="hdfs-details-content">
  593. <!-- ko with: definition -->
  594. <div class="assist-details-wrap">
  595. <div><div class="assist-details-header">${ _('Size') }</div><div class="assist-details-value" data-bind="text: humansize"></div></div>
  596. <!-- ko with: stats -->
  597. <div><div class="assist-details-header">${ _('User') }</div><div class="assist-details-value" data-bind="text: user"></div></div>
  598. <div><div class="assist-details-header">${ _('Group') }</div><div class="assist-details-value" data-bind="text: group"></div></div>
  599. <!-- /ko -->
  600. <div><div class="assist-details-header">${ _('Permissions') }</div><div class="assist-details-value" data-bind="text: rwx"></div></div>
  601. <div><div class="assist-details-header">${ _('Date') }</div><div class="assist-details-value" data-bind="text: mtime"></div></div>
  602. </div>
  603. <!-- /ko -->
  604. </script>
  605. <script type="text/html" id="hdfs-details-title">
  606. <span data-bind="text: definition.name"></span>
  607. </script>
  608. <script type="text/html" id="assist-hdfs-header-actions">
  609. <div class="assist-db-header-actions" style="margin-top: -1px;">
  610. <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.hdfs.refresh'); }"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }" title="${_('Manual refresh')}"></i></a>
  611. </div>
  612. </script>
  613. <script type="text/html" id="assist-hdfs-inner-panel">
  614. <div class="assist-inner-panel">
  615. <div class="assist-flex-panel">
  616. <!-- ko with: selectedHdfsEntry -->
  617. <div class="assist-flex-header assist-breadcrumb" >
  618. <!-- ko if: parent !== null -->
  619. <a href="javascript: void(0);" data-bind="click: function () { huePubSub.publish('assist.selectHdfsEntry', parent); }">
  620. <i class="fa fa-chevron-left" style="font-size: 15px;margin-right:8px;"></i>
  621. <i class="fa fa-folder-o" style="font-size: 14px; line-height: 16px; vertical-align: top; margin-right:4px;"></i>
  622. <span style="font-size: 14px;line-height: 16px;vertical-align: top;" data-bind="text: path"></span>
  623. </a>
  624. <!-- /ko -->
  625. <!-- ko if: parent === null -->
  626. <div>
  627. <i class="fa fa-folder-o" style="font-size: 14px; line-height: 16px;vertical-align: top; margin-right:4px;"></i>
  628. <span style="font-size: 14px;line-height: 16px;vertical-align: top;" data-bind="text: path"></span>
  629. </div>
  630. <!-- /ko -->
  631. <!-- ko template: 'assist-hdfs-header-actions' --><!-- /ko -->
  632. </div>
  633. <div class="assist-flex-fill assist-hdfs-scrollable">
  634. <div data-bind="visible: ! loading() && ! hasErrors()" style="position: relative;">
  635. <!-- ko hueSpinner: { spin: loadingMore, overlay: true } --><!-- /ko -->
  636. <ul class="assist-tables" data-bind="foreachVisible: { data: entries, minHeight: 20, container: '.assist-hdfs-scrollable', fetchMore: $data.fetchMore.bind($data) }">
  637. <li class="assist-entry assist-table-link" style="position: relative;" data-bind="visibleOnHover: { 'selector': '.assist-actions' }">
  638. <div class="assist-actions table-actions" style="opacity: 0;" >
  639. <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' }">
  640. <i class='fa fa-info' title="${ _('Details') }"></i>
  641. </a>
  642. </div>
  643. <a href="javascript:void(0)" class="assist-entry assist-table-link" data-bind="multiClick: { click: toggleOpen, dblClick: dblClick }, attr: {'title': definition.name }">
  644. <!-- ko if: definition.type === 'dir' -->
  645. <i class="fa fa-fw fa-folder-o muted valign-middle"></i>
  646. <!-- /ko -->
  647. <!-- ko if: definition.type === 'file' -->
  648. <i class="fa fa-fw fa-file-o muted valign-middle"></i>
  649. <!-- /ko -->
  650. <span draggable="true" data-bind="text: definition.name, draggableText: { text: '\'' + path + '\'', meta: {'type': 'hdfs', 'definition': definition} }"></span>
  651. </a>
  652. </li>
  653. </ul>
  654. <!-- ko if: !loading() && entries().length === 0 -->
  655. <ul class="assist-tables">
  656. <li class="assist-entry" style="font-style: italic;">${_('Empty directory')}</li>
  657. </ul>
  658. <!-- /ko -->
  659. </div>
  660. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  661. <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
  662. <span>${ _('Error loading contents.') }</span>
  663. </div>
  664. </div>
  665. <!-- /ko -->
  666. </div>
  667. <!-- ko with: $parents[1] -->
  668. <!-- ko template: { if: searchActive() && searchInput() !== '' && navigatorEnabled(), name: 'nav-search-result' } --><!-- /ko -->
  669. <!-- /ko -->
  670. </div>
  671. </script>
  672. <script type="text/html" id="file-details-content">
  673. <!-- ko with: definition -->
  674. <div class="assist-details-wrap">
  675. <div><div class="assist-details-header">${ _('Description') }</div><div class="assist-details-value" data-bind="text: description"></div></div>
  676. <div><div class="assist-details-header">${ _('Modified') }</div><div class="assist-details-value" data-bind="text: localeFormat(last_modified)"></div></div>
  677. <div><div class="assist-details-header">${ _('Owner') }</div><div class="assist-details-value" data-bind="text: owner"></div></div>
  678. </div>
  679. <!-- /ko -->
  680. </script>
  681. <script type="text/html" id="file-details-title">
  682. <span data-bind="text: definition().name"></span>
  683. </script>
  684. <script type="text/html" id="assist-document-header-actions">
  685. <div class="assist-header-actions" style="margin-top: -1px;">
  686. <a class="inactive-action" href="javascript:void(0)"><i class="pointer fa fa-filter" title="${_('Filter')}"></i></a>
  687. <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.file.refresh'); }"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }" title="${_('Manual refresh')}"></i></a>
  688. </div>
  689. </script>
  690. <script type="text/html" id="assist-document-panel">
  691. <div class="assist-inner-panel">
  692. <div class="assist-flex-header">
  693. <!-- ko with: activeEntry -->
  694. <div class="assist-inner-header assist-breadcrumb">
  695. <!-- ko ifnot: isRoot -->
  696. <a href="javascript: void(0);" data-bind="click: function () { parent.makeActive(); }">
  697. <i class="fa fa-chevron-left" style="font-size: 15px;margin-right:8px;"></i>
  698. <i class="fa fa-folder-o" style="font-size: 14px; line-height: 16px; vertical-align: top; margin-right:4px;"></i>
  699. <span style="font-size: 14px;line-height: 16px;vertical-align: top;" data-bind="text: definition().name"></span>
  700. </a>
  701. <!-- /ko -->
  702. <!-- ko if: isRoot -->
  703. <div>
  704. <i class="fa fa-folder-o" style="font-size: 14px; line-height: 16px;vertical-align: top;margin-right:4px;"></i>
  705. <span style="font-size: 14px;line-height: 16px;vertical-align: top;">/</span>
  706. </div>
  707. <!-- /ko -->
  708. <!-- ko template: 'assist-document-header-actions' --><!-- /ko -->
  709. </div>
  710. <!-- /ko -->
  711. </div>
  712. <div class="assist-flex-fill assist-file-scrollable">
  713. <!-- ko with: activeEntry -->
  714. <div data-bind="visible: ! loading() && ! hasErrors() && entries().length > 0">
  715. <ul class="assist-tables" data-bind="foreachVisible: {data: entries, minHeight: 20, container: '.assist-file-scrollable' }">
  716. <li class="assist-entry assist-file-entry" style="position: relative;" data-bind="assistFileDroppable, visibleOnHover: { 'selector': '.assist-file-actions' }">
  717. <div class="assist-file-actions table-actions" style="opacity: 0;" >
  718. <a style="padding: 0 3px;" class="inactive-action" href="javascript:void(0);" data-bind="templatePopover : { contentTemplate: 'file-details-content', titleTemplate: 'file-details-title', minWidth: '350px' }">
  719. <i class='fa fa-info' title="${ _('Details') }"></i>
  720. </a>
  721. </div>
  722. <a href="javascript:void(0)" class="assist-entry assist-table-link" data-bind="click: open, attr: {'title': name }">
  723. <!-- ko if: isDirectory -->
  724. <i class="fa fa-fw fa-folder-o muted valign-middle"></i>
  725. <!-- /ko -->
  726. <!-- ko ifnot: isDirectory -->
  727. <i class="fa fa-fw fa-file-o muted valign-middle"></i>
  728. <!-- /ko -->
  729. <span data-bind="draggableText: { text: definition().name, meta: {'type': 'document', 'definition': definition()} }, text: definition().name"></span>
  730. </a>
  731. </li>
  732. </ul>
  733. </div>
  734. <div data-bind="visible: !loading() && ! hasErrors() && entries().length === 0">
  735. <span style="font-style: italic;">${_('Empty directory')}</span>
  736. </div>
  737. <div class="center" data-bind="visible: loading() && ! hasErrors()">
  738. <!--[if !IE]><!--><i class="fa fa-spinner fa-spin" style="font-size: 20px; color: #BBB"></i><!--<![endif]-->
  739. <!--[if IE]><img src="${ static('desktop/art/spinner.gif') }"/><![endif]-->
  740. </div>
  741. <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
  742. <span>${ _('Error loading contents.') }</span>
  743. </div>
  744. <!-- /ko -->
  745. <!-- ko with: $parents[1] -->
  746. <!-- ko template: { if: searchActive() && searchInput() !== '' && navigatorEnabled(), name: 'nav-search-result' } --><!-- /ko -->
  747. <!-- /ko -->
  748. </div>
  749. </div>
  750. </script>
  751. <script type="text/html" id="assist-documents-inner-panel">
  752. <div class="assist-inner-panel">
  753. <div class="assist-flex-panel">
  754. <!-- ko template: 'assist-document-panel' --><!-- /ko -->
  755. </div>
  756. </div>
  757. </script>
  758. <script type="text/html" id="assist-collections-header-actions">
  759. <div class="assist-db-header-actions" style="margin-top: -1px;">
  760. <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>
  761. <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>
  762. </div>
  763. </script>
  764. <script type="text/html" id="assist-collections-inner-panel">
  765. <div class="assist-inner-panel">
  766. <div class="assist-flex-panel">
  767. <!-- ko with: selectedCollectionEntry -->
  768. <div class="assist-inner-header assist-breadcrumb">
  769. ${_('Collections')}
  770. <!-- ko template: 'assist-collections-header-actions' --><!-- /ko -->
  771. </div>
  772. <div class="assist-flex-table-search" data-bind="visible: $parent.isSearchVisible() && !loading() && !hasErrors() && entries().length > 0">
  773. <div>
  774. <label class="checkbox inline-block margin-left-5"><input type="checkbox" data-bind="checked: $parent.showCores" />${_('Show cores')}</label>
  775. </div>
  776. <div><input id="searchInput" class="clearable" type="text" placeholder="${ _('Collection name...') }" style="width:90%;" data-bind="hasFocus: $parent.editingSearch, clearable: $parent.filter, value: $parent.filter, valueUpdate: 'afterkeydown'"/></div>
  777. </div>
  778. <div class="assist-flex-fill assist-collections-scrollable">
  779. <div data-bind="visible: ! loading() && ! hasErrors()" style="position: relative;">
  780. <ul class="assist-tables" data-bind="foreachVisible: { data: filteredEntries, minHeight: 20, container: '.assist-collections-scrollable' }">
  781. <li class="assist-entry assist-table-link" style="position: relative;" data-bind="visibleOnHover: { 'selector': '.assist-actions' }">
  782. <a href="javascript:void(0)" class="assist-entry assist-table-link" data-bind="multiClick: { click: click, dblClick: dblClick }, attr: {'title': definition.name }">
  783. <i class="fa fa-fw fa-search muted valign-middle"></i>
  784. <span draggable="true" data-bind="text: definition.name, draggableText: { text: '\'' + path + '\'', meta: {'type': 'collection', 'definition': definition} }"></span>
  785. </a>
  786. </li>
  787. </ul>
  788. <!-- ko if: !loading() && entries().length === 0 -->
  789. <ul class="assist-tables">
  790. <li class="assist-entry" style="font-style: italic;">${_('No collections available.')}</li>
  791. </ul>
  792. <!-- /ko -->
  793. </div>
  794. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  795. <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
  796. <span>${ _('Error loading contents.') }</span>
  797. </div>
  798. </div>
  799. <!-- /ko -->
  800. </div>
  801. <!-- ko with: $parents[1] -->
  802. <!-- ko template: { if: searchActive() && searchInput() !== '' && navigatorEnabled(), name: 'nav-search-result' } --><!-- /ko -->
  803. <!-- /ko -->
  804. </div>
  805. </script>
  806. <script type="text/html" id="assist-hbase-header-actions">
  807. <div class="assist-db-header-actions" style="margin-top: -1px;">
  808. <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>
  809. </div>
  810. </script>
  811. <script type="text/html" id="assist-hbase-inner-panel">
  812. <div class="assist-inner-panel">
  813. <div class="assist-flex-panel">
  814. <!-- ko with: selectedHBaseEntry -->
  815. <div class="assist-inner-header assist-breadcrumb" >
  816. <!-- ko if: definition.host !== '' -->
  817. <a href="javascript: void(0);" data-bind="click: function () { huePubSub.publish('assist.clickHBaseRootItem'); }">
  818. <i class="fa fa-chevron-left" style="font-size: 15px;margin-right:8px;"></i>
  819. <i class="fa fa-th-large" style="font-size: 14px; line-height: 16px; vertical-align: top; margin-right:4px;"></i>
  820. <span style="font-size: 14px;line-height: 16px;vertical-align: top;" data-bind="text: definition.name"></span>
  821. </a>
  822. <!-- /ko -->
  823. <!-- ko if: definition.host === '' -->
  824. ${_('Clusters')}
  825. <!-- /ko -->
  826. <!-- ko template: 'assist-hbase-header-actions' --><!-- /ko -->
  827. </div>
  828. <div class="assist-flex-fill assist-hbase-scrollable">
  829. <div data-bind="visible: ! loading() && ! hasErrors()" style="position: relative;">
  830. <ul class="assist-tables" data-bind="foreachVisible: { data: entries, minHeight: 20, container: '.assist-hbase-scrollable' }">
  831. <li class="assist-entry assist-table-link" style="position: relative;" data-bind="visibleOnHover: { 'selector': '.assist-actions' }">
  832. <a href="javascript:void(0)" class="assist-entry assist-table-link" data-bind="multiClick: { click: click, dblClick: dblClick }, attr: {'title': definition.name }">
  833. <!-- ko if: definition.host -->
  834. <i class="fa fa-fw fa-th-large muted valign-middle"></i>
  835. <!-- /ko -->
  836. <!-- ko ifnot: definition.host -->
  837. <i class="fa fa-fw fa-th muted valign-middle"></i>
  838. <!-- /ko -->
  839. <span draggable="true" data-bind="text: definition.name, draggableText: { text: '\'' + definition.name + '\'', meta: {'type': 'collection', 'definition': definition} }"></span>
  840. </a>
  841. </li>
  842. </ul>
  843. <!-- ko if: !loading() && entries().length === 0 -->
  844. <ul class="assist-tables">
  845. <li class="assist-entry" style="font-style: italic;">
  846. <!-- ko if: definition.host === '' -->
  847. ${_('No clusters available.')}
  848. <!-- /ko -->
  849. <!-- ko if: definition.host !== '' -->
  850. ${_('No tables available.')}
  851. <!-- /ko -->
  852. </li>
  853. </ul>
  854. <!-- /ko -->
  855. </div>
  856. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  857. <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
  858. <span>${ _('Error loading contents.') }</span>
  859. </div>
  860. </div>
  861. <!-- /ko -->
  862. </div>
  863. <!-- ko with: $parents[1] -->
  864. <!-- ko template: { if: searchActive() && searchInput() !== '' && navigatorEnabled(), name: 'nav-search-result' } --><!-- /ko -->
  865. <!-- /ko -->
  866. </div>
  867. </script>
  868. <script type="text/html" id="assist-sources-template">
  869. <div class="assist-flex-header">
  870. <div class="assist-inner-header">
  871. ${_('Sources')}
  872. </div>
  873. </div>
  874. <div class="assist-flex-fill">
  875. <ul class="assist-tables" data-bind="foreach: sources">
  876. <li class="assist-table">
  877. <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>
  878. </li>
  879. </ul>
  880. </div>
  881. </script>
  882. <script type="text/html" id="ask-for-invalidate-title">
  883. <a class="pull-right pointer close-popover inactive-action"><i class="fa fa-times"></i></a>
  884. </script>
  885. <script type="text/html" id="ask-for-invalidate-content">
  886. <label class="radio" style="margin-bottom: 2px;">
  887. <input type="radio" name="refreshImpala" value="cache" data-bind="checked: invalidateOnRefresh" />
  888. ${ _('Clear cache') }
  889. </label>
  890. <label class="radio" style="margin-bottom: 2px;">
  891. <input type="radio" name="refreshImpala" value="invalidate" data-bind="checked: invalidateOnRefresh" />
  892. ${ _('Perform incremental metadata update') }
  893. </label>
  894. <div style="display: inline-block; margin-left: 20px; font-style: italic; color: #999;">${ _('This will sync missing tables in Hive.') }</div>
  895. <label class="radio" style="margin-bottom: 2px;">
  896. <input type="radio" name="refreshImpala" value="invalidateAndFlush" data-bind="checked: invalidateOnRefresh" />
  897. ${ _('Invalidate all metadata and rebuild index') }
  898. </label>
  899. <div style="display: inline-block; margin-left: 20px; font-style: italic; color: #999;">${ _('WARNING: This can be both resource and time-intensive.') }</div>
  900. <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 () { huePubSub.publish('close.popover'); triggerRefresh(); }, clickBubble: false">${ _('Refresh') }</button></div>
  901. </script>
  902. <script type="text/html" id="assist-db-header-actions">
  903. <div class="assist-db-header-actions">
  904. <span class="assist-tables-counter">(<span data-bind="text: filteredEntries().length"></span>)</span>
  905. <!-- ko ifnot: loading -->
  906. <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>
  907. <!-- ko if: sourceType === 'impala' -->
  908. <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="${_('Manually refresh the table list')}"></i></a>
  909. <!-- /ko -->
  910. <!-- ko if: sourceType !== 'impala' -->
  911. <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="${_('Manually refresh the table list')}"></i></a>
  912. <!-- /ko -->
  913. <!-- /ko -->
  914. <!-- ko if: loading -->
  915. <span style="color: #aaa;"><i class="fa fa-filter" title="${_('Filter tables')}"></i></span>
  916. <i class="fa fa-refresh fa-spin blue" title="${_('Manually refresh the table list')}"></i>
  917. <!-- /ko -->
  918. </div>
  919. </script>
  920. <script type="text/html" id="assist-databases-template">
  921. <div class="assist-flex-header" data-bind="visibleOnHover: { selector: '.hover-actions', override: loading() || isSearchVisible() }">
  922. <div class="assist-inner-header">
  923. ${_('Databases')}
  924. <!-- ko template: 'assist-db-header-actions' --><!-- /ko -->
  925. </div>
  926. </div>
  927. <div class="assist-flex-search" data-bind="visible: hasEntries() && isSearchVisible() && ! hasErrors()">
  928. <div><input id="searchInput" class="clearable" type="text" placeholder="${ _('Database name...') }" style="margin-top:3px;width:90%;" data-bind="hasFocus: editingSearch, clearable: filter.query, value: filter.query, valueUpdate: 'afterkeydown'"/></div>
  929. </div>
  930. <div class="assist-flex-fill assist-db-scrollable" data-bind="visible: ! hasErrors() && ! loading() && hasEntries()">
  931. <!-- ko if: ! loading() && filteredEntries().length == 0 -->
  932. <ul class="assist-tables">
  933. <li class="assist-entry no-entries">${_('No results found')}</li>
  934. </ul>
  935. <!-- /ko -->
  936. <ul class="assist-tables" data-bind="foreachVisible: {data: filteredEntries, minHeight: 20, container: '.assist-db-scrollable' }">
  937. <li class="assist-table" data-bind="visibleOnHover: { selector: '.database-actions' }">
  938. <!-- ko template: { name: 'assist-entry-actions' } --><!-- /ko -->
  939. <a class="assist-table-link" href="javascript: void(0);" data-bind="click: function () { $parent.selectedDatabase($data); $parent.selectedDatabaseChanged(); }"><i class="fa fa-fw fa-database muted valign-middle"></i> <span class="highlightable" data-bind="text: definition.name, css: { 'highlight': highlight() }"></span></a>
  940. </li>
  941. </ul>
  942. </div>
  943. <div class="assist-flex-fill" data-bind="visible: loading">
  944. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  945. </div>
  946. <div class="assist-flex-fill" data-bind="visible: hasErrors() && ! loading()">
  947. <span class="assist-errors">${ _('Error loading databases.') }</span>
  948. </div>
  949. <div class="assist-flex-fill" data-bind="visible: ! hasErrors() && ! loading() && ! hasEntries()">
  950. <span class="assist-errors">${ _('No databases found.') }</span>
  951. </div>
  952. </script>
  953. <script type="text/html" id="assist-tables-template">
  954. <div class="assist-flex-header">
  955. <div class="assist-inner-header" data-bind="visible: !$parent.loading() && !$parent.hasErrors()">
  956. ${_('Tables')}
  957. <!-- ko template: 'assist-db-header-actions' --><!-- /ko -->
  958. </div>
  959. </div>
  960. <div class="assist-flex-table-search" data-bind="visible: hasEntries() && isSearchVisible() && !$parent.loading() && !$parent.hasErrors()">
  961. <div>
  962. <label class="checkbox inline-block margin-left-5"><input type="checkbox" data-bind="checked: filter.showTables" />${_('Tables')}</label>
  963. <label class="checkbox inline-block margin-left-10"><input type="checkbox" data-bind="checked: filter.showViews" />${_('Views')}</label>
  964. <!-- ko if: filter.enableActiveFilter --><label class="checkbox inline-block margin-left-10"><input type="checkbox" data-bind="checked: filter.showActive" />${_('Active')}</label><!-- /ko -->
  965. </div>
  966. <div><input id="searchInput" class="clearable" type="text" placeholder="${ _('Table name...') }" style="width:90%;" data-bind="hasFocus: editingSearch, clearable: filter.query, value: filter.query, valueUpdate: 'afterkeydown'"/></div>
  967. </div>
  968. <div class="assist-flex-fill assist-db-scrollable" data-bind="visible: ! hasErrors() && ! loading()">
  969. <!-- ko template: 'assist-db-entries' --><!-- /ko -->
  970. </div>
  971. <div class="assist-flex-fill" data-bind="visible: loading() || $parent.loading()">
  972. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  973. </div>
  974. <div class="assist-flex-fill" data-bind="visible: hasErrors() && ! loading()">
  975. <span class="assist-errors">${ _('Error loading tables.') }</span>
  976. </div>
  977. </script>
  978. <style>
  979. .nav-autocomplete-item .ui-state-focus {
  980. border: 1px solid #DBE8F1;
  981. background-color: #DBE8F1 !important;
  982. }
  983. .nav-autocomplete-item-link {
  984. height: 44px;
  985. overflow:hidden;
  986. }
  987. .nav-autocomplete-item-link i {
  988. font-size: 18px;
  989. color: #338bb8;
  990. }
  991. .nav-autocomplete-item-link em, .result-entry em {
  992. font-style: normal;
  993. font-weight: bold;
  994. }
  995. .nav-autocomplete-item-link > div {
  996. vertical-align: top;
  997. display:inline-block;
  998. }
  999. .nav-autocomplete-divider {
  1000. height: 2px;
  1001. border-top: 1px solid #dddddd;
  1002. }
  1003. </style>
  1004. <script type="text/html" id="nav-search-autocomp-item">
  1005. <a>
  1006. <div class="nav-autocomplete-item-link">
  1007. <div style="padding: 12px 8px 0 8px;"><i class="fa fa-fw" data-bind="css: icon"></i></div>
  1008. <div>
  1009. <div style="font-size: 14px; color: #338bb8" data-bind="html: label, style: { 'padding-top': description ? 0 : '10px' }"></div>
  1010. <!-- ko if: description -->
  1011. <div style="display:inline-block; width: 250px; overflow: hidden; white-space: nowrap; text-overflow:ellipsis; font-size: 12px;" data-bind="html: description"></div>
  1012. <!-- /ko -->
  1013. </div>
  1014. </div>
  1015. </a>
  1016. </script>
  1017. <script type="text/html" id="nav-search-autocomp-no-match">
  1018. <div class="nav-autocomplete-item-link" style="height: 30px;">
  1019. <div style="font-size: 12px; margin: 6px 8px; color: #737373; font-style: italic;">${ _('No recent match found') }</div>
  1020. </div>
  1021. </script>
  1022. <script type="text/html" id="assist-panel-navigator-search">
  1023. <!-- ko if: navigatorEnabled -->
  1024. <div class="search-container" data-bind="style: { 'padding-right': tabsEnabled ? null : '20px' }">
  1025. <input placeholder="${ _('Search...') }" type="text" data-bind="autocomplete: {
  1026. source: navAutocompleteSource,
  1027. itemTemplate: 'nav-search-autocomp-item',
  1028. noMatchTemplate: 'nav-search-autocomp-no-match',
  1029. classPrefix: 'nav-',
  1030. showOnFocus: true,
  1031. onEnter: performSearch,
  1032. reopenPattern: /.*:$/
  1033. },
  1034. hasFocus: searchHasFocus,
  1035. clearable: { value: searchInput, onClear: function () { searchActive(false); huePubSub.publish('autocomplete.close'); } },
  1036. textInput: searchInput,
  1037. valueUpdate: 'afterkeydown',
  1038. attr: { placeholder: '${ _('Search ') }' + $parent.name.replace(/s$/g, '') + ($parent.type == 'sql' ? '${ _(' tables') }' : '${ _(' files') }' ) + '...' }">
  1039. <a class="inactive-action" data-bind="click: performSearch"><i class="fa fa-search" data-bind="css: { 'blue': searchHasFocus() || searchActive() }"></i></a>
  1040. </div>
  1041. <!-- /ko -->
  1042. </script>
  1043. <script type="text/html" id="assist-panel-inner-header">
  1044. <div class="assist-header assist-fixed-height" data-bind="visibleOnHover: { selector: '.assist-header-actions' }, css: { 'assist-resizer': $index() > 0 }" style="display:none;">
  1045. <span data-bind="text: $parent.name"></span>
  1046. <div class="assist-header-actions">
  1047. <div class="inactive-action" data-bind="click: function () { $parent.visible(false) }"><i class="fa fa-times"></i></div>
  1048. </div>
  1049. </div>
  1050. </script>
  1051. <script type="text/html" id="assist-panel-template">
  1052. <div style="display: -ms-flexbox; display: flex; -ms-flex-direction: column; flex-direction: column; position:relative; height: 100%; overflow: hidden;">
  1053. <!-- ko if: availablePanels.length > 1 -->
  1054. <div style="position: relative; flex: 0 0 40px; line-height: 40px;" class="assist-panel-switches">
  1055. <!-- ko foreach: availablePanels -->
  1056. <div class="inactive-action assist-type-switch" data-bind="click: function () { $parent.visiblePanel($data); }, css: { 'blue': $parent.visiblePanel() === $data }, attr: { 'title': name }">
  1057. <i class="fa fa-fw valign-middle" data-bind="css: icon"></i>
  1058. </div>
  1059. <!-- /ko -->
  1060. </div>
  1061. <!-- /ko -->
  1062. <!-- ko with: visiblePanel -->
  1063. <!-- ko template: { if: showNavSearch && $parent.navigatorEnabled, name: 'assist-panel-navigator-search', data: $parent }--><!-- /ko -->
  1064. <div style="position: relative; -ms-flex: 1 1 100%; flex: 1 1 100%; overflow: hidden; padding-top: 10px;" data-bind="style: { 'padding-top': $parent.availablePanels.length > 1 ? '10px' : '5px' }">
  1065. <!-- ko template: { name: templateName, data: panelData } --><!-- /ko -->
  1066. </div>
  1067. <!-- /ko -->
  1068. </div>
  1069. </script>
  1070. <script type="text/html" id="nav-search-result">
  1071. <div style="position:absolute; left:0; right: 0; top: 0; bottom: 0; overflow: hidden; background-color: #FFF;" data-bind="niceScroll">
  1072. <div class="assist-inner-header" style="width: inherit;">${ _('Search result') }
  1073. <div class="assist-db-header-actions">
  1074. <span class="assist-tables-counter" data-bind="visible: searchResult().length > 0">(<span data-bind="text: searchResultCount">0</span>)</span>
  1075. <a class="inactive-action" href="javascript:void(0)" data-bind="click: function() { searchActive(false); }"><i class="pointer fa fa-times" title="${ _('Close') }"></i></a>
  1076. </div>
  1077. </div>
  1078. <!-- ko hueSpinner: { spin: searching, center: true, size: 'large' } --><!-- /ko -->
  1079. <!-- ko if: !searching() -->
  1080. <!-- ko if: searchResult().length == 0 -->
  1081. <div class="result-entry">${ _('No result found.') }</div>
  1082. <!-- /ko -->
  1083. <div data-bind="foreach: searchResult" style="overflow-x:hidden">
  1084. <div class="result-entry" data-bind="visibleOnHover: { override: statsVisible, selector: '.table-actions' }, event: { mouseover: showNavContextPopoverDelayed, mouseout: clearNavContextPopoverDelay }">
  1085. <div class="icon-col">
  1086. <i class="fa fa-fw valign-middle" data-bind="css: icon"></i>
  1087. </div>
  1088. <div class="doc-col" data-bind="css: { 'doc-col-no-desc' : !hasDescription }">
  1089. <!-- ko if: typeof click !== 'undefined' -->
  1090. <a class="pointer" data-bind="click: click, html: hue_name" target="_blank" ></a>
  1091. <!-- /ko -->
  1092. <!-- ko if: typeof click === 'undefined' -->
  1093. <a class="pointer" data-bind="attr: { 'href': link }, text: originalName" target="_blank" ></a>
  1094. <!-- /ko -->
  1095. <div class="doc-desc" data-bind="html: hue_description"></div>
  1096. </div>
  1097. </div>
  1098. </div>
  1099. <!-- /ko -->
  1100. </div>
  1101. </script>
  1102. <script type="text/javascript" charset="utf-8">
  1103. (function () {
  1104. ko.bindingHandlers.assistFileDroppable = {
  1105. init: function(element, valueAccessor, allBindings, boundEntry) {
  1106. var dragData;
  1107. huePubSub.subscribe('doc.browser.dragging', function (data) {
  1108. dragData = data;
  1109. });
  1110. var $element = $(element);
  1111. if (boundEntry.isDirectory) {
  1112. $element.droppable({
  1113. drop: function () {
  1114. if (dragData && !dragData.dragToSelect) {
  1115. boundEntry.moveHere(dragData.selectedEntries);
  1116. dragData.originEntry.load();
  1117. }
  1118. },
  1119. over: function () {
  1120. if (dragData && !dragData.dragToSelect) {
  1121. $element.addClass('assist-file-entry-drop');
  1122. }
  1123. },
  1124. out: function () {
  1125. $element.removeClass('assist-file-entry-drop');
  1126. }
  1127. })
  1128. }
  1129. }
  1130. };
  1131. /**
  1132. * @param {Object} options
  1133. * @param {ApiHelper} options.apiHelper
  1134. * @param {string} options.type
  1135. * @param {number} options.minHeight
  1136. * @param {string} options.icon
  1137. * @param {boolean} options.visible
  1138. * @param {boolean} [options.showNavSearch] - Default true
  1139. * @param {(AssistDbPanel|AssistHdfsPanel|AssistDocumentsPanel|AssistS3Panel|AssistCollectionsPanel)} panelData
  1140. * @constructor
  1141. */
  1142. function AssistInnerPanel (options) {
  1143. var self = this;
  1144. self.minHeight = options.minHeight;
  1145. self.icon = options.icon;
  1146. self.type = options.type;
  1147. self.name = options.name;
  1148. self.panelData = options.panelData;
  1149. self.showNavSearch = typeof options.showNavSearch !== 'undefined' ? options.showNavSearch : true;
  1150. self.visible = ko.observable(options.visible || true);
  1151. options.apiHelper.withTotalStorage('assist', 'showingPanel_' + self.type, self.visible, false, options.visible);
  1152. self.templateName = 'assist-' + self.type + '-inner-panel';
  1153. var loadWhenVisible = function () {
  1154. if (! self.visible()) {
  1155. return;
  1156. }
  1157. if (self.type === 'documents' && !self.panelData.activeEntry().loaded()) {
  1158. self.panelData.activeEntry().load();
  1159. }
  1160. };
  1161. self.visible.subscribe(loadWhenVisible);
  1162. loadWhenVisible();
  1163. }
  1164. /**
  1165. * @param {Object} options
  1166. * @param {ApiHelper} options.apiHelper
  1167. * @param {Object} options.i18n
  1168. * @param {Object[]} options.sourceTypes - All the available SQL source types
  1169. * @param {string} options.sourceTypes[].name - Example: Hive SQL
  1170. * @param {string} options.sourceTypes[].type - Example: hive
  1171. * @param {string} [options.activeSourceType] - Example: hive
  1172. * @param {Object} options.navigationSettings - enable/disable the links
  1173. * @param {boolean} options.navigationSettings.openItem
  1174. * @param {boolean} options.navigationSettings.showStats
  1175. * @param {boolean} options.navigationSettings.pinEnabled
  1176. * @constructor
  1177. **/
  1178. function AssistDbPanel(options) {
  1179. var self = this;
  1180. self.options = options;
  1181. self.apiHelper = options.apiHelper;
  1182. self.i18n = options.i18n;
  1183. self.sources = ko.observableArray();
  1184. self.sourceIndex = {};
  1185. $.each(options.sourceTypes, function (idx, sourceType) {
  1186. self.sourceIndex[sourceType.type] = new AssistDbSource({
  1187. apiHelper: self.apiHelper,
  1188. i18n: self.i18n,
  1189. type: sourceType.type,
  1190. name: sourceType.name,
  1191. navigationSettings: options.navigationSettings
  1192. });
  1193. self.sources.push(self.sourceIndex[sourceType.type]);
  1194. });
  1195. huePubSub.subscribe('assist.db.highlight', function (location) {
  1196. var foundSource;
  1197. $.each(self.sources(), function (idx, source) {
  1198. if (source.sourceType === location.sourceType) {
  1199. foundSource = source;
  1200. return false;
  1201. }
  1202. });
  1203. if (foundSource) {
  1204. if (foundSource.hasEntries()) {
  1205. self.selectedSource(foundSource);
  1206. foundSource.highlightInside(location.path);
  1207. } else {
  1208. foundSource.initDatabases(function () {
  1209. self.selectedSource(foundSource);
  1210. foundSource.highlightInside(location.path);
  1211. });
  1212. }
  1213. }
  1214. });
  1215. self.selectedSource = ko.observable(null);
  1216. self.setDatabaseWhenLoaded = function (databaseName) {
  1217. if (self.selectedSource().loaded()) {
  1218. self.selectedSource().setDatabase(databaseName);
  1219. } else {
  1220. var subscription = self.selectedSource().loaded.subscribe(function (newValue) {
  1221. if (newValue) {
  1222. self.selectedSource().setDatabase(databaseName);
  1223. subscription.dispose();
  1224. }
  1225. });
  1226. if (!self.selectedSource().loaded() && !self.selectedSource().loading()) {
  1227. self.selectedSource().initDatabases();
  1228. }
  1229. }
  1230. };
  1231. huePubSub.subscribe("assist.set.database", function (databaseDef) {
  1232. if (!databaseDef.source || !self.sourceIndex[databaseDef.source]) {
  1233. return;
  1234. }
  1235. self.selectedSource(self.sourceIndex[databaseDef.source]);
  1236. self.setDatabaseWhenLoaded(databaseDef.name);
  1237. });
  1238. huePubSub.subscribe("assist.get.database", function (source) {
  1239. if (self.sourceIndex[source] && self.sourceIndex[source].selectedDatabase()) {
  1240. huePubSub.publish("assist.database.set", {
  1241. source: source,
  1242. name: self.sourceIndex[source].selectedDatabase().databaseName
  1243. });
  1244. } else {
  1245. huePubSub.publish("assist.database.set", {
  1246. source: source,
  1247. name: null
  1248. });
  1249. }
  1250. });
  1251. huePubSub.publish("assist.db.panel.ready");
  1252. self.selectedSource.subscribe(function (newSource) {
  1253. if (newSource) {
  1254. if (newSource.databases().length === 0) {
  1255. newSource.initDatabases();
  1256. }
  1257. self.apiHelper.setInTotalStorage('assist', 'lastSelectedSource', newSource.sourceType);
  1258. } else {
  1259. self.apiHelper.setInTotalStorage('assist', 'lastSelectedSource');
  1260. }
  1261. });
  1262. self.breadcrumb = ko.computed(function () {
  1263. if (self.selectedSource()) {
  1264. if (self.selectedSource().selectedDatabase()) {
  1265. return self.selectedSource().selectedDatabase().definition.name;
  1266. }
  1267. return self.selectedSource().name;
  1268. }
  1269. return null;
  1270. });
  1271. }
  1272. AssistDbPanel.prototype.back = function () {
  1273. var self = this;
  1274. if (self.selectedSource() && self.selectedSource().selectedDatabase()) {
  1275. self.selectedSource().selectedDatabase(null)
  1276. } else if (self.selectedSource()) {
  1277. self.selectedSource(null);
  1278. }
  1279. };
  1280. AssistDbPanel.prototype.init = function () {
  1281. var self = this;
  1282. var storageSourceType = self.apiHelper.getFromTotalStorage('assist', 'lastSelectedSource');
  1283. if (!self.selectedSource()) {
  1284. if (self.options.activeSourceType) {
  1285. self.selectedSource(self.sourceIndex[self.options.activeSourceType]);
  1286. self.setDatabaseWhenLoaded();
  1287. } else if (storageSourceType && self.sourceIndex[storageSourceType]) {
  1288. self.selectedSource(self.sourceIndex[storageSourceType]);
  1289. self.setDatabaseWhenLoaded();
  1290. }
  1291. }
  1292. };
  1293. /**
  1294. * @param {Object} options
  1295. * @param {ApiHelper} options.apiHelper
  1296. * @param {string} options.user
  1297. * @param {Object} options.i18n
  1298. * @constructor
  1299. **/
  1300. function AssistDocumentsPanel (options) {
  1301. var self = this;
  1302. self.activeEntry = ko.observable();
  1303. self.activeEntry(new HueFileEntry({
  1304. activeEntry: self.activeEntry,
  1305. trashEntry: ko.observable,
  1306. apiHelper: options.apiHelper,
  1307. app: 'documents',
  1308. user: options.user,
  1309. activeSort: ko.observable('name'),
  1310. definition: {
  1311. name: '/',
  1312. type: 'directory'
  1313. }
  1314. }));
  1315. huePubSub.subscribe('assist.document.refresh', function () {
  1316. huePubSub.publish('assist.clear.document.cache');
  1317. self.reload();
  1318. });
  1319. }
  1320. AssistDocumentsPanel.prototype.init = function () {
  1321. var self = this;
  1322. if (! self.activeEntry().loaded()) {
  1323. self.activeEntry().load();
  1324. }
  1325. };
  1326. /**
  1327. * @param {Object} options
  1328. * @param {ApiHelper} options.apiHelper
  1329. * @constructor
  1330. **/
  1331. function AssistHdfsPanel (options) {
  1332. var self = this;
  1333. self.apiHelper = options.apiHelper;
  1334. self.selectedHdfsEntry = ko.observable();
  1335. self.reload = function () {
  1336. var lastKnownPath = self.apiHelper.getFromTotalStorage('assist', 'currentHdfsPath', '/');
  1337. var parts = lastKnownPath.split('/');
  1338. parts.shift();
  1339. var currentEntry = new AssistHdfsEntry({
  1340. definition: {
  1341. name: '/',
  1342. type: 'dir'
  1343. },
  1344. parent: null,
  1345. apiHelper: self.apiHelper
  1346. });
  1347. currentEntry.loadDeep(parts, function (entry) {
  1348. self.selectedHdfsEntry(entry);
  1349. entry.open(true);
  1350. });
  1351. };
  1352. huePubSub.subscribe('assist.selectHdfsEntry', function (entry) {
  1353. self.selectedHdfsEntry(entry);
  1354. self.apiHelper.setInTotalStorage('assist', 'currentHdfsPath', entry.path);
  1355. });
  1356. huePubSub.subscribe('assist.hdfs.refresh', function () {
  1357. huePubSub.publish('assist.clear.hdfs.cache');
  1358. self.reload();
  1359. });
  1360. }
  1361. AssistHdfsPanel.prototype.init = function () {
  1362. this.reload();
  1363. };
  1364. /**
  1365. * @param {Object} options
  1366. * @param {ApiHelper} options.apiHelper
  1367. * @constructor
  1368. **/
  1369. function AssistS3Panel (options) {
  1370. var self = this;
  1371. self.apiHelper = options.apiHelper;
  1372. self.selectedS3Entry = ko.observable();
  1373. self.reload = function () {
  1374. var lastKnownPath = self.apiHelper.getFromTotalStorage('assist', 'currentS3Path', '/');
  1375. var parts = lastKnownPath.split('/');
  1376. parts.shift();
  1377. var currentEntry = new AssistS3Entry({
  1378. definition: {
  1379. name: '/',
  1380. type: 'dir'
  1381. },
  1382. parent: null,
  1383. apiHelper: self.apiHelper
  1384. });
  1385. currentEntry.loadDeep(parts, function (entry) {
  1386. self.selectedS3Entry(entry);
  1387. entry.open(true);
  1388. });
  1389. };
  1390. huePubSub.subscribe('assist.selectS3Entry', function (entry) {
  1391. self.selectedS3Entry(entry);
  1392. self.apiHelper.setInTotalStorage('assist', 'currentS3Path', entry.path);
  1393. });
  1394. huePubSub.subscribe('assist.s3.refresh', function () {
  1395. huePubSub.publish('assist.clear.s3.cache');
  1396. self.reload();
  1397. });
  1398. }
  1399. AssistS3Panel.prototype.init = function () {
  1400. this.reload();
  1401. };
  1402. /**
  1403. * @param {Object} options
  1404. * @param {ApiHelper} options.apiHelper
  1405. * @constructor
  1406. **/
  1407. function AssistCollectionsPanel (options) {
  1408. var self = this;
  1409. self.apiHelper = options.apiHelper;
  1410. self.isSearchVisible = ko.observable(false);
  1411. self.editingSearch = ko.observable(false);
  1412. self.toggleSearch = function () {
  1413. self.isSearchVisible(!self.isSearchVisible());
  1414. self.editingSearch(self.isSearchVisible());
  1415. };
  1416. self.showCores = ko.observable(false);
  1417. self.selectedCollectionEntry = ko.observable();
  1418. self.filter = ko.observable('');
  1419. self.reload = function () {
  1420. var currentEntry = new AssistCollectionEntry({
  1421. definition: {
  1422. name: '/',
  1423. type: 'collection'
  1424. },
  1425. apiHelper: self.apiHelper
  1426. }, self.filter, self.showCores);
  1427. self.selectedCollectionEntry(currentEntry);
  1428. currentEntry.loadEntries();
  1429. currentEntry.hasOnlyCores.subscribe(function (onlyCores) {
  1430. self.showCores(onlyCores);
  1431. });
  1432. self.showCores(currentEntry.hasOnlyCores());
  1433. };
  1434. huePubSub.subscribe('assist.clickCollectionItem', function (entry) {
  1435. });
  1436. huePubSub.subscribe('assist.dblClickCollectionItem', function (entry) {
  1437. window.open('/indexer/#edit/' + entry.definition.name);
  1438. });
  1439. huePubSub.subscribe('assist.collections.refresh', function () {
  1440. huePubSub.publish('assist.clear.collections.cache');
  1441. self.reload();
  1442. });
  1443. }
  1444. AssistCollectionsPanel.prototype.init = function () {
  1445. this.reload();
  1446. };
  1447. /**
  1448. * @param {Object} options
  1449. * @param {ApiHelper} options.apiHelper
  1450. * @constructor
  1451. **/
  1452. function AssistHBasePanel(options) {
  1453. var self = this;
  1454. self.apiHelper = options.apiHelper;
  1455. var root = new AssistHBaseEntry({
  1456. definition: {
  1457. host: '',
  1458. name: '',
  1459. port: 0
  1460. },
  1461. apiHelper: self.apiHelper
  1462. });
  1463. self.selectedHBaseEntry = ko.observable();
  1464. self.reload = function () {
  1465. self.selectedHBaseEntry(root);
  1466. root.loadEntries();
  1467. };
  1468. huePubSub.subscribe('assist.clickHBaseItem', function (entry) {
  1469. if (entry.definition.host) {
  1470. entry.loadEntries();
  1471. self.selectedHBaseEntry(entry);
  1472. }
  1473. });
  1474. huePubSub.subscribe('assist.clickHBaseRootItem', function (entry) {
  1475. self.reload();
  1476. });
  1477. huePubSub.subscribe('assist.dblClickHBaseItem', function (entry) {
  1478. window.open('/hbase/#' + self.selectedHBaseEntry().definition.name + '/' + entry.definition.name);
  1479. });
  1480. huePubSub.subscribe('assist.hbase.refresh', function () {
  1481. huePubSub.publish('assist.clear.hbase.cache');
  1482. self.reload();
  1483. });
  1484. }
  1485. AssistHBasePanel.prototype.init = function () {
  1486. this.reload();
  1487. };
  1488. var NAV_FACET_ICON = 'fa-tags';
  1489. var NAV_TYPE_ICONS = {
  1490. 'DATABASE': 'fa-database',
  1491. 'TABLE': 'fa-table',
  1492. 'VIEW': 'fa-eye',
  1493. 'FIELD': 'fa-columns',
  1494. 'PARTITION': 'fa-th',
  1495. 'SOURCE': 'fa-server',
  1496. 'OPERATION': 'fa-cogs',
  1497. 'OPERATION_EXECUTION': 'fa-cog',
  1498. 'DIRECTORY': 'fa-folder-o',
  1499. 'FILE': 'fa-file-o',
  1500. 'SUB_OPERATION': 'fa-code-fork',
  1501. 'COLLECTION': 'fa-search',
  1502. 'HBASE': 'fa-th-large',
  1503. 'HUE': 'fa-file-o'
  1504. };
  1505. /**
  1506. * @param {Object} params
  1507. * @param {string} params.user
  1508. * @param {boolean} params.onlySql - For the old query editors
  1509. * @param {string[]} params.visibleAssistPanels - Panels that will initially be shown regardless of total storage
  1510. * @param {Object} params.sql
  1511. * @param {Object[]} params.sql.sourceTypes - All the available SQL source types
  1512. * @param {string} params.sql.sourceTypes[].name - Example: Hive SQL
  1513. * @param {string} params.sql.sourceTypes[].type - Example: hive
  1514. * @param {string} [params.sql.activeSourceType] - Example: hive
  1515. * @param {Object} params.sql.navigationSettings - enable/disable the links
  1516. * @param {boolean} params.sql.navigationSettings.openItem - Example: true
  1517. * @param {boolean} params.sql.navigationSettings.showStats - Example: true
  1518. * @constructor
  1519. */
  1520. function AssistPanel (params) {
  1521. var self = this;
  1522. var i18n = {
  1523. errorLoadingDatabases: "${ _('There was a problem loading the databases') }",
  1524. errorLoadingTablePreview: "${ _('There was a problem loading the table preview.') }",
  1525. documentTypes: {
  1526. 'query-hive': "${ _('Hive Query') }",
  1527. 'query': "${ _('Query') }",
  1528. 'notebook': "${ _('Notebook') }"
  1529. }
  1530. };
  1531. self.apiHelper = ApiHelper.getInstance({
  1532. i18n: i18n,
  1533. user: params.user
  1534. });
  1535. self.navigatorEnabled = ko.observable('${ has_navigator(user) }' === 'True');
  1536. self.tabsEnabled = '${ USE_NEW_SIDE_PANELS.get() }' === 'True';
  1537. self.searchInput = ko.observable('').extend({rateLimit: 500});
  1538. self.searchResult = ko.observableArray();
  1539. self.searchResultCount = ko.observable();
  1540. self.searchHasFocus = ko.observable(false);
  1541. self.searching = ko.observable(false);
  1542. self.searchActive = ko.observable(false);
  1543. var lastQuery = -1;
  1544. self.availablePanels = [
  1545. new AssistInnerPanel({
  1546. panelData: new AssistDbPanel($.extend({
  1547. apiHelper: self.apiHelper,
  1548. i18n: i18n
  1549. }, params.sql)),
  1550. apiHelper: self.apiHelper,
  1551. name: '${ _("SQL") }',
  1552. type: 'sql',
  1553. icon: 'fa-database',
  1554. minHeight: 75
  1555. })
  1556. ];
  1557. if (self.tabsEnabled) {
  1558. self.availablePanels.push(new AssistInnerPanel({
  1559. panelData: new AssistHdfsPanel({
  1560. apiHelper: self.apiHelper
  1561. }),
  1562. apiHelper: self.apiHelper,
  1563. name: '${ _("HDFS") }',
  1564. type: 'hdfs',
  1565. icon: 'fa-folder-o',
  1566. minHeight: 50
  1567. }));
  1568. if (window.IS_S3_ENABLED) { // coming from common_header.mako
  1569. self.availablePanels.push(new AssistInnerPanel({
  1570. panelData: new AssistS3Panel({
  1571. apiHelper: self.apiHelper
  1572. }),
  1573. apiHelper: self.apiHelper,
  1574. name: '${ _("S3") }',
  1575. type: 's3',
  1576. icon: 'fa-cubes',
  1577. minHeight: 50,
  1578. showNavSearch: false
  1579. }));
  1580. }
  1581. self.availablePanels.push(new AssistInnerPanel({
  1582. panelData: new AssistCollectionsPanel({
  1583. apiHelper: self.apiHelper
  1584. }),
  1585. apiHelper: self.apiHelper,
  1586. name: '${ _("Collections") }',
  1587. type: 'collections',
  1588. icon: 'fa-search-plus',
  1589. minHeight: 50,
  1590. showNavSearch: false
  1591. }));
  1592. self.availablePanels.push(new AssistInnerPanel({
  1593. panelData: new AssistHBasePanel({
  1594. apiHelper: self.apiHelper
  1595. }),
  1596. apiHelper: self.apiHelper,
  1597. name: '${ _("HBase") }',
  1598. type: 'hbase',
  1599. icon: 'fa-th-large',
  1600. minHeight: 50,
  1601. showNavSearch: false
  1602. }));
  1603. self.availablePanels.push(new AssistInnerPanel({
  1604. panelData: new AssistDocumentsPanel({
  1605. user: params.user,
  1606. apiHelper: self.apiHelper,
  1607. i18n: i18n
  1608. }),
  1609. apiHelper: self.apiHelper,
  1610. name: '${ _("Documents") }',
  1611. type: 'documents',
  1612. icon: 'fa-files-o',
  1613. minHeight: 50,
  1614. visible: params.visibleAssistPanels && params.visibleAssistPanels.indexOf('documents') !== -1
  1615. }));
  1616. }
  1617. self.performSearch = function () {
  1618. huePubSub.publish('autocomplete.close');
  1619. if (self.searchInput() === '') {
  1620. self.searchActive(false);
  1621. return;
  1622. }
  1623. if (!self.searchActive()) {
  1624. self.searchActive(true);
  1625. } else if (self.searchInput() === lastQuery) {
  1626. return;
  1627. }
  1628. if (self.searching()) {
  1629. window.setTimeout(function() {
  1630. self.performSearch();
  1631. }, 100);
  1632. return;
  1633. }
  1634. lastQuery = self.searchInput();
  1635. self.searching(true);
  1636. var showInAssist = function (entry) {
  1637. self.searchInput('');
  1638. self.searchHasFocus(false);
  1639. var path = entry.parentPath.split('/').concat([entry.originalName]).splice(1);
  1640. window.setTimeout(function () {
  1641. huePubSub.publish('assist.db.highlight', { sourceType: entry.sourceType.toLowerCase(), path: path });
  1642. }, 200); // For animation effect
  1643. };
  1644. var showNavContextPopover = function (entry, event) {
  1645. if (entry.type && entry.type !== 'TABLE' && entry.type !== 'VIEW' && entry.type !== 'DATABASE' && entry.type !== 'FIELD') {
  1646. return;
  1647. }
  1648. var $source = $(event.target).closest('.result-entry');
  1649. var offset = $source.offset();
  1650. entry.statsVisible(true);
  1651. huePubSub.publish('sql.context.popover.show', {
  1652. data: {
  1653. type: entry.type === 'FIELD' ? 'column' : (entry.type === 'DATABASE' ? 'database' : 'table'),
  1654. identifierChain: $.map(entry.parentPath.substring(1).split('/'), function (part) { return { name: part } }).concat({ name: entry.originalName })
  1655. },
  1656. delayedHide: '.result-entry',
  1657. orientation: 'right',
  1658. sourceType: entry.sourceType.toLowerCase(),
  1659. defaultDatabase: entry.parentPath.substring(1),
  1660. pinEnabled: params.sql.navigationSettings.pinEnabled,
  1661. source: {
  1662. element: event.target,
  1663. left: offset.left,
  1664. top: offset.top - 3,
  1665. right: offset.left + $source.width() + 3,
  1666. bottom: offset.top + $source.height() - 3
  1667. }
  1668. });
  1669. huePubSub.subscribeOnce('sql.context.popover.hidden', function () {
  1670. entry.statsVisible(false);
  1671. });
  1672. };
  1673. var navContextPopoverTimeout = -1;
  1674. var showNavContextPopoverDelayed = function (entry, event) {
  1675. window.clearTimeout(navContextPopoverTimeout);
  1676. navContextPopoverTimeout = window.setTimeout(function () {
  1677. showNavContextPopover(entry, event);
  1678. }, 500);
  1679. };
  1680. var clearNavContextPopoverDelay = function () {
  1681. window.clearTimeout(navContextPopoverTimeout);
  1682. };
  1683. $.post('/desktop/api/search/entities', {
  1684. query_s: ko.mapping.toJSON(self.searchInput()),
  1685. limit: 25,
  1686. sources: ko.mapping.toJSON([self.visiblePanel().type])
  1687. }, function (data) {
  1688. data.entities.forEach(function (entity) {
  1689. entity.statsVisible = ko.observable(false);
  1690. entity.showNavContextPopoverDelayed = showNavContextPopoverDelayed;
  1691. entity.clearNavContextPopoverDelay = clearNavContextPopoverDelay;
  1692. entity.icon = NAV_TYPE_ICONS[entity.type];
  1693. switch (entity.type) {
  1694. case 'DATABASE': { }
  1695. case 'TABLE': { }
  1696. case 'VIEW': { }
  1697. case 'FIELD': {
  1698. entity.click = function () {
  1699. showInAssist(entity);
  1700. };
  1701. break;
  1702. }
  1703. case 'SOURCE': {
  1704. entity.originalDescription = '${ _("Cluster") }: ' + entity.clusterName;
  1705. entity.link = entity.sourceUrl;
  1706. break;
  1707. }
  1708. case 'OPERATION_EXECUTION': {
  1709. entity.link = '/jobbrowser/jobs/' + entity.jobID;
  1710. break;
  1711. }
  1712. case 'DIRECTORY': {
  1713. entity.originalDescription = entity.parentPath;
  1714. entity.link = '/filebrowser/#' + entity.fileSystemPath;
  1715. break;
  1716. }
  1717. case 'FILE': {
  1718. entity.originalDescription = entity.parentPath;
  1719. entity.link = '/filebrowser/#' + entity.fileSystemPath;
  1720. break;
  1721. }
  1722. case 'SUB_OPERATION': {
  1723. entity.originalDescription = entity.metaClassName;
  1724. break;
  1725. }
  1726. case 'PARTITION': {}
  1727. case 'OPERATION': {}
  1728. }
  1729. entity.hasDescription = typeof entity.originalDescription !== 'undefined' && entity.originalDescription !== null && entity.originalDescription.length > 0;
  1730. });
  1731. self.searchResult(data.entities);
  1732. self.searchResultCount(data.count);
  1733. self.searching(false);
  1734. }).fail(function (xhr, textStatus, errorThrown) {
  1735. $(document).trigger("error", xhr.responseText);
  1736. self.searching(false);
  1737. });
  1738. };
  1739. var lastOpenPanelType = self.apiHelper.getFromTotalStorage('assist', 'last.open.panel', self.availablePanels[0].type);
  1740. var lastFoundPanel = self.availablePanels.filter(function (panel) { return panel.type === lastOpenPanelType });
  1741. var dbPanel = self.availablePanels.filter(function (panel) { return panel.type === 'sql' });
  1742. if (lastFoundPanel.length === 1) {
  1743. dbPanel[0].panelData.init(); // always forces the db panel to load
  1744. }
  1745. self.visiblePanel = ko.observable(lastFoundPanel.length === 1 ? lastFoundPanel[0] : self.availablePanels[0]);
  1746. self.visiblePanel().panelData.init();
  1747. self.visiblePanel.subscribe(function(newValue) {
  1748. self.apiHelper.setInTotalStorage('assist', 'last.open.panel', newValue.type);
  1749. if (self.navigatorEnabled() && self.searchActive()) {
  1750. lastQuery = 'refresh';
  1751. self.performSearch();
  1752. }
  1753. newValue.panelData.init();
  1754. });
  1755. self.navAutocompleteSource = function (request, callback) {
  1756. var facetMatch = request.term.match(/([a-z]+):\s*(\S+)?$/i);
  1757. var isFacet = facetMatch !== null;
  1758. var partialMatch = isFacet ? null : request.term.match(/\S+$/);
  1759. var partial = isFacet && facetMatch[2] ? facetMatch[2] : (partialMatch ? partialMatch[0] : '');
  1760. var beforePartial = request.term.substring(0, request.term.length - partial.length);
  1761. self.apiHelper.navSearchAutocomplete({
  1762. source: self.visiblePanel().type === 'sql' ?
  1763. (self.visiblePanel().panelData.selectedSource() ? self.visiblePanel().panelData.selectedSource().sourceType : 'hive') : self.visiblePanel().type,
  1764. query: request.term,
  1765. successCallback: function (data) {
  1766. var values = [];
  1767. var facetPartialRe = new RegExp(partial.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i'); // Protect for 'tags:*axe'
  1768. if (isFacet && typeof data.facets !== 'undefined') { // Is typed facet, e.g. type: type:bla
  1769. var facetInQuery = facetMatch[1];
  1770. if (typeof data.facets[facetInQuery] !== 'undefined') {
  1771. $.map(data.facets[facetInQuery], function (count, value) {
  1772. if (facetPartialRe.test(value)) {
  1773. values.push({ data: { label: facetInQuery + ':' + value, icon: NAV_FACET_ICON, description: count }, value: beforePartial + value})
  1774. }
  1775. });
  1776. }
  1777. } else {
  1778. if (typeof data.facets !== 'undefined') {
  1779. Object.keys(data.facets).forEach(function (facet) {
  1780. if (facetPartialRe.test(facet)) {
  1781. if (Object.keys(data.facets[facet]).length > 0) {
  1782. values.push({ data: { label: facet + ':', icon: NAV_FACET_ICON, description: $.map(data.facets[facet], function (key, value) { return value + ' (' + key + ')'; }).join(', ') }, value: beforePartial + facet + ':'});
  1783. } else { // Potential facet from the list
  1784. values.push({ data: { label: facet + ':', icon: NAV_FACET_ICON, description: '' }, value: beforePartial + facet + ':'});
  1785. }
  1786. } else if (partial.length > 0) {
  1787. Object.keys(data.facets[facet]).forEach(function (facetValue) {
  1788. if (facetValue.indexOf(partial) !== -1) {
  1789. values.push({ data: { label: facet + ':' + facetValue, icon: NAV_FACET_ICON, description: facetValue }, value: beforePartial + facet + ':' + facetValue });
  1790. }
  1791. });
  1792. }
  1793. });
  1794. }
  1795. }
  1796. if (values.length > 0) {
  1797. values.push({ divider: true });
  1798. }
  1799. if (typeof data.results !== 'undefined') {
  1800. data.results.forEach(function (result) {
  1801. values.push({ data: { label: result.hue_name, icon: NAV_TYPE_ICONS[result.type], description: result.hue_description }, value: beforePartial + result.originalName });
  1802. });
  1803. }
  1804. if (values.length > 0 && values[values.length - 1].divider) {
  1805. values.pop();
  1806. }
  1807. if (values.length === 0) {
  1808. values.push({ noMatch: true });
  1809. }
  1810. callback(values);
  1811. },
  1812. silenceErrors: true,
  1813. errorCallback: function () {
  1814. callback([]);
  1815. }
  1816. });
  1817. };
  1818. }
  1819. ko.components.register('assist-panel', {
  1820. viewModel: AssistPanel,
  1821. template: { element: 'assist-panel-template' }
  1822. });
  1823. })();
  1824. </script>
  1825. </%def>