assist.mako 93 KB

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