assist.mako 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412
  1. ## Licensed to Cloudera, Inc. under one
  2. ## or more contributor license agreements. See the NOTICE file
  3. ## distributed with this work for additional information
  4. ## regarding copyright ownership. Cloudera, Inc. licenses this file
  5. ## to you under the Apache License, Version 2.0 (the
  6. ## "License"); you may not use this file except in compliance
  7. ## with the License. You may obtain a copy of the License at
  8. ##
  9. ## http://www.apache.org/licenses/LICENSE-2.0
  10. ##
  11. ## Unless required by applicable law or agreed to in writing, software
  12. ## distributed under the License is distributed on an "AS IS" BASIS,
  13. ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ## See the License for the specific language governing permissions and
  15. ## limitations under the License.
  16. <%!
  17. from desktop import conf
  18. from desktop.conf import USE_NEW_SIDE_PANELS
  19. from desktop.lib.i18n import smart_unicode
  20. from desktop.views import _ko
  21. from django.utils.translation import ugettext as _
  22. from metadata.conf import has_navigator
  23. %>
  24. <%def name="assistPanel()">
  25. <%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
  26. <%namespace name="nav_components" file="/nav_components.mako" />
  27. ${ sqlContextPopover.sqlContextPopover() }
  28. ${ nav_components.nav_tags() }
  29. <style>
  30. .assist-icon {
  31. width: 16px;
  32. height: 16px;
  33. -webkit-filter: grayscale(1);
  34. filter: grayscale(1);
  35. opacity: .8;
  36. }
  37. .assist {
  38. position: relative;
  39. height: 100%;
  40. }
  41. .assist-resizer {
  42. cursor: row-resize;
  43. }
  44. .assist-spinner {
  45. font-size: 20px;
  46. color: #BBB;
  47. }
  48. .assist-header {
  49. flex: 1;
  50. color: #338bb8;
  51. background-color: #f9f9f9;
  52. border-top: 1px solid #f1f1f1;
  53. border-bottom: 1px solid #f1f1f1;
  54. font-weight: bold;
  55. letter-spacing: 0.035em;
  56. font-size: 0.975em;
  57. line-height: 25px;
  58. padding-left: 10px;
  59. height: 24px;
  60. margin-bottom: 8px;
  61. }
  62. .assist-inner-panel {
  63. overflow: hidden;
  64. height: 100%;
  65. position: relative;
  66. padding: 0 0 0 10px;
  67. margin-right: 1px;
  68. }
  69. .assist-inner-header {
  70. width: 100%;
  71. color: #737373;
  72. margin-left:3px;
  73. margin-bottom:2px;
  74. font-weight: bold;
  75. margin-top: 0
  76. }
  77. .assist-stretchable-list {
  78. position:relative;
  79. overflow-y: auto;
  80. overflow-x: hidden;
  81. width: 100%;
  82. border: none;
  83. padding: 0;
  84. margin-bottom: 1px;
  85. margin-top:3px;
  86. }
  87. .assist-header-actions {
  88. float: right;
  89. margin-right: 3px;
  90. opacity: 0;
  91. }
  92. .assist-header-actions > div {
  93. cursor: pointer;
  94. }
  95. .assist-panel-switches {
  96. padding-left: 12px;
  97. height: 29px;
  98. border-bottom: 1px solid #f1f1f1;
  99. }
  100. .assist-type-switch {
  101. display: inline-block;
  102. font-size: 16px;
  103. margin-right: 2px;
  104. cursor: pointer;
  105. }
  106. .assist-column {
  107. position: relative;
  108. }
  109. .assist-entry,a {
  110. white-space: nowrap;
  111. }
  112. .assist-file-entry {
  113. margin-right: 15px;
  114. border: 1px solid transparent;
  115. }
  116. .assist-file-entry-drop {
  117. border: 1px solid #338BB8 !important;
  118. }
  119. .assist-tables {
  120. margin-left: 0;
  121. }
  122. .assist-tables a {
  123. text-decoration: none;
  124. }
  125. .assist-tables li {
  126. list-style: none;
  127. }
  128. .assist-breadcrumb > a:hover {
  129. color: #338bb8;
  130. }
  131. .assist-errors {
  132. padding: 4px 5px;
  133. font-style: italic;
  134. }
  135. .assist-tables > li {
  136. position: relative;
  137. padding-top: 2px;
  138. padding-bottom: 2px;
  139. padding-left: 4px;
  140. margin-right: 15px;
  141. overflow-x: hidden;
  142. }
  143. .assist-tables > li.selected {
  144. background-color: #EEE;
  145. }
  146. .assist-breadcrumb {
  147. padding-top: 0;
  148. padding-left: 0;
  149. }
  150. .assist-breadcrumb span {
  151. color: #737373;
  152. }
  153. .assist-breadcrumb a:not(.inactive-action) {
  154. cursor: pointer;
  155. text-decoration: none;
  156. color: #737373;
  157. -webkit-transition: color 0.2s ease;
  158. -moz-transition: color 0.2s ease;
  159. -ms-transition: color 0.2s ease;
  160. transition: color 0.2s ease;
  161. }
  162. .assist-breadcrumb-text {
  163. font-size: 14px;
  164. line-height: 16px;
  165. vertical-align: top;
  166. }
  167. .assist-breadcrumb-back {
  168. font-size: 15px;
  169. margin-right:8px;
  170. }
  171. .assist-tables-counter {
  172. color: #d1d1d1;
  173. font-weight: normal;
  174. }
  175. .assist-table-link {
  176. font-size: 13px;
  177. }
  178. .assist-field-link {
  179. font-size: 12px;
  180. }
  181. .assist-table-link,
  182. .assist-table-link:focus {
  183. color: #444;
  184. }
  185. .assist-field-link,
  186. .assist-field-link:focus {
  187. white-space: nowrap;
  188. color: #737373;
  189. }
  190. .assist-db-header-actions {
  191. position:absolute;
  192. top: 0;
  193. right: 0;
  194. padding-left:4px;
  195. padding-right: 13px;
  196. background-color: #FFF;
  197. }
  198. .assist-actions {
  199. position:absolute;
  200. top: 0;
  201. right: 0;
  202. padding-left:4px;
  203. background-color: #FFF;
  204. }
  205. .assist-file-actions {
  206. position:absolute;
  207. top: 0;
  208. right: 0;
  209. padding-right: 2px;
  210. padding-left:4px;
  211. background-color: #FFF;
  212. }
  213. .table-actions {
  214. padding-top:2px;
  215. }
  216. .assist-tables > li.selected .assist-actions {
  217. background-color: #EEE;
  218. }
  219. .assist-details-wrap {
  220. display: table;
  221. width: 100%;
  222. table-layout: fixed;
  223. }
  224. .assist-details-wrap > div {
  225. display: table-row;
  226. }
  227. .highlightable {
  228. -webkit-transition: all .5s linear;
  229. -moz-transition: all .5s linear;
  230. -o-transition: all .5s linear;
  231. transition: all .5s linear;
  232. }
  233. .highlight {
  234. color: #338BB8 !important;
  235. padding-left: 8px;
  236. }
  237. .assist-details-header {
  238. display: table-cell;
  239. width: 95px;
  240. font-weight: bold;
  241. }
  242. .assist-details-value {
  243. display: table-cell;
  244. }
  245. .no-entries {
  246. font-style: italic;
  247. }
  248. .assist-flex-panel {
  249. position: relative;
  250. display: -ms-flexbox;
  251. display: flex;
  252. -ms-flex-flow: column nowrap;
  253. flex-flow: column nowrap;
  254. align-items: stretch;
  255. height:100%;
  256. }
  257. .assist-flex-header {
  258. overflow: hidden;
  259. position: relative;
  260. -ms-flex: 0 0 25px;
  261. flex: 0 0 25px;
  262. white-space: nowrap;
  263. }
  264. .assist-flex-table-search {
  265. overflow: hidden;
  266. position: relative;
  267. -ms-flex: 0 0 65px;
  268. flex: 0 0 65px;
  269. white-space: nowrap;
  270. }
  271. .assist-flex-search {
  272. overflow: hidden;
  273. position: relative;
  274. -ms-flex: 0 0 43px;
  275. flex: 0 0 43px;
  276. white-space: nowrap;
  277. }
  278. .assist-flex-fill {
  279. position: relative;
  280. -ms-flex: 1 1 100%;
  281. flex: 1 1 100%;
  282. white-space: nowrap;
  283. overflow-x: hidden;
  284. overflow-y: auto;
  285. outline: none !important;
  286. }
  287. .database-tree ul {
  288. margin: 0 !important;
  289. }
  290. .database-tree ul li {
  291. padding-left: 15px;
  292. }
  293. .searchbar {
  294. margin: 0 10px 10px 15px;
  295. }
  296. .searchbar input {
  297. min-height: 20px;
  298. height: 27px;
  299. width: calc(100% - 65px);
  300. margin: 0;
  301. box-shadow: none;
  302. border: 1px solid #DDD;
  303. border-right: none;
  304. border-bottom-left-radius: 2px;
  305. border-top-left-radius: 2px;
  306. }
  307. .searchbar .add-on {
  308. border-radius: 1.5em;
  309. border-bottom-left-radius: 0;
  310. border-top-left-radius: 0;
  311. border-left: none;
  312. }
  313. .searchbar .add-on i {
  314. margin-top: -2px;
  315. margin-lefT: -2px;
  316. font-size: 14px;
  317. }
  318. .result-entry {
  319. clear: both;
  320. width: calc(100% - 20px);
  321. margin: 0px 10px 15px 10px;
  322. }
  323. .result-entry .doc-desc {
  324. font-style: italic;
  325. font-size: 12px;
  326. line-height: 15px;
  327. }
  328. .result-entry .icon-col {
  329. width: 35px;
  330. display: inline-block;
  331. vertical-align: top;
  332. padding-top: 7px;
  333. font-size: 20px;
  334. color: #338bb8;
  335. }
  336. .result-entry .doc-col {
  337. width: calc(100% - 50px);
  338. display: inline-block;
  339. }
  340. .result-entry .hue-icon {
  341. font-size: 30px;
  342. }
  343. </style>
  344. <script type="text/html" id="assist-no-database-entries">
  345. <ul class="assist-tables">
  346. <li>
  347. <span style="font-style: italic">${_('The database has no tables')}</span>
  348. </li>
  349. </ul>
  350. </script>
  351. <script type="text/html" id="assist-no-table-entries">
  352. <ul>
  353. <li>
  354. <span style="font-style: italic" class="assist-entry assist-field-link">${_('The table has no columns')}</span>
  355. </li>
  356. </ul>
  357. </script>
  358. <script type="text/html" id="assist-entry-actions">
  359. <div class="assist-actions" data-bind="css: { 'table-actions' : definition.isTable || definition.isView, 'column-actions': definition.isColumn, 'database-actions' : definition.isDatabase } " style="opacity: 0">
  360. <a class="inactive-action" href="javascript:void(0)" data-bind="visible: navigationSettings.showStats, click: function (data, event) { showContextPopover(data, event, navigationSettings.pinEnabled); }, css: { 'blue': statsVisible }"><i class="fa fa-bar-chart" title="${_('Show details')}"></i></a>
  361. <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>
  362. </div>
  363. </script>
  364. <script type="text/html" id="assist-table-entry">
  365. <li class="assist-table" data-bind="visibleOnHover: { override: statsVisible, selector: '.table-actions' }">
  366. <div class="assist-actions table-actions" style="opacity: 0">
  367. <a class="inactive-action" href="javascript:void(0)" data-bind="visible: navigationSettings.showStats, click: function (data, event) { showContextPopover(data, event, navigationSettings.pinEnabled); }, css: { 'blue': statsVisible }"><i class="fa fa-bar-chart" title="${_('Show details')}"></i></a>
  368. <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>
  369. </div>
  370. <a class="assist-entry assist-table-link" href="javascript:void(0)" data-bind="multiClick: { click: toggleOpen, dblClick: dblClick }, attr: {'title': definition.title }, draggableText: { text: editorText, meta: {'type': 'sql', 'table': tableName, 'database': databaseName} }"><i class="fa fa-fw fa-table muted valign-middle"></i><span data-bind="text: definition.displayName, css: { 'highlight': highlight }"></span></a>
  371. <div class="center" data-bind="visible: loading" style="display:none;"><i class="fa fa-spinner fa-spin assist-spinner"></i></div>
  372. <!-- ko template: { if: open, name: 'assist-db-entries' } --><!-- /ko -->
  373. </li>
  374. </script>
  375. <script type="text/html" id="assist-db-entries">
  376. <!-- ko if: hasEntries() && ! loading() && filteredEntries().length == 0 -->
  377. <ul class="assist-tables">
  378. <li class="assist-entry no-entries">${_('No results found')}</li>
  379. </ul>
  380. <!-- /ko -->
  381. <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 }">
  382. <!-- ko template: { if: definition.isTable, name: 'assist-table-entry' } --><!-- /ko -->
  383. <!-- ko ifnot: definition.isTable && ! hasErrors() -->
  384. <li data-bind="visible: ! hasErrors(), visibleOnHover: { override: statsVisible, selector: definition.isView ? '.table-actions' : '.column-actions' }, css: { 'assist-table': definition.isView, 'assist-column': definition.isColumn }">
  385. <!-- ko template: { if: definition.isView || definition.isColumn, name: 'assist-entry-actions' } --><!-- /ko -->
  386. <!-- ko if: expandable -->
  387. <a class="assist-entry" href="javascript:void(0)" data-bind="multiClick: { click: toggleOpen, dblClick: dblClick }, attr: {'title': definition.title }, css: { 'assist-field-link': !definition.isView, 'assist-table-link': definition.isView }">
  388. <!-- ko if: definition.isView -->
  389. <i class="fa fa-fw fa-eye muted valign-middle"></i>
  390. <!-- /ko -->
  391. <span class="highlightable" data-bind="css: {'query-builder-menu': definition.isColumn, '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>
  392. </a>
  393. <!-- /ko -->
  394. <!-- ko ifnot: expandable -->
  395. <div style="cursor: default;" class="assist-entry" href="javascript:void(0)" data-bind="multiClick: { dblClick: dblClick }, attr: {'title': definition.title }, css: { 'assist-field-link': !definition.isView, 'assist-table-link': definition.isView }">
  396. <!-- ko if: definition.isView -->
  397. <i class="fa fa-fw fa-eye muted valign-middle"></i>
  398. <!-- /ko -->
  399. <span class="highlightable" data-bind="css: {'query-builder-menu': definition.isColumn, '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>
  400. </div>
  401. <!-- /ko -->
  402. <div class="center" data-bind="visible: loading" style="display:none;"><i class="fa fa-spinner fa-spin assist-spinner"></i></div>
  403. <!-- ko template: { if: open, name: 'assist-db-entries' } --><!-- /ko -->
  404. </li>
  405. <!-- ko if: definition.isTable && hasErrors() -->
  406. <li class="assist-errors">
  407. <span >${ _('Error loading columns.') }</span>
  408. </li>
  409. <!-- /ko -->
  410. <!-- /ko -->
  411. </ul>
  412. <!-- ko template: { if: ! hasEntries() && ! loading() && (definition.isTable || definition.isView), name: 'assist-no-table-entries' } --><!-- /ko -->
  413. <!-- ko template: { if: ! hasEntries() && ! loading() && definition.isDatabase, name: 'assist-no-database-entries' } --><!-- /ko -->
  414. </script>
  415. <script type="text/html" id="assist-db-breadcrumb">
  416. <div class="assist-flex-header assist-breadcrumb">
  417. <!-- ko if: selectedSource() && ! selectedSource().selectedDatabase() && sources().length === 1 -->
  418. <i class="fa fa-server assist-breadcrumb-text"></i>
  419. <span class="assist-breadcrumb-text" data-bind="text: breadcrumb"></span>
  420. <!-- /ko -->
  421. <!-- ko if: selectedSource() && ! selectedSource().selectedDatabase() && sources().length > 1 -->
  422. <a data-bind="click: back">
  423. <i class="fa fa-chevron-left assist-breadcrumb-back"></i>
  424. <i class="fa fa-server assist-breadcrumb-text"></i>
  425. <span class="assist-breadcrumb-text" data-bind="text: breadcrumb"></span>
  426. </a>
  427. <!-- /ko -->
  428. <!-- ko if: selectedSource() && selectedSource().selectedDatabase() -->
  429. <a data-bind="click: back">
  430. <i class="fa fa-chevron-left assist-breadcrumb-back" ></i>
  431. <i class="fa fa-database assist-breadcrumb-text"></i>
  432. <span class="assist-breadcrumb-text" data-bind="text: breadcrumb"></span>
  433. </a>
  434. <!-- /ko -->
  435. </div>
  436. </script>
  437. <script type="text/html" id="assist-hive-inner-panel">
  438. <div class="assist-inner-panel">
  439. <div class="assist-flex-panel">
  440. <!-- ko template: { if: breadcrumb() !== null, name: 'assist-db-breadcrumb' } --><!-- /ko -->
  441. <!-- ko template: { ifnot: selectedSource, name: 'assist-sources-template' } --><!-- /ko -->
  442. <!-- ko with: selectedSource -->
  443. <!-- ko template: { ifnot: selectedDatabase, name: 'assist-databases-template' }--><!-- /ko -->
  444. <!-- ko with: selectedDatabase -->
  445. <!-- ko template: { name: "assist-tables-template" } --><!-- /ko -->
  446. <!-- /ko -->
  447. <!-- /ko -->
  448. </div>
  449. <!-- ko with: $parents[1] -->
  450. <!-- ko template: { if: (searchInput() !== '' || searchHasFocus()) && navigatorEnabled(), name: 'nav-search-result' } --><!-- /ko -->
  451. <!-- /ko -->
  452. </div>
  453. </script>
  454. <script type="text/html" id="hdfs-details-content">
  455. <!-- ko with: definition -->
  456. <div class="assist-details-wrap">
  457. <div><div class="assist-details-header">${ _('Size') }</div><div class="assist-details-value" data-bind="text: humansize"></div></div>
  458. <!-- ko with: stats -->
  459. <div><div class="assist-details-header">${ _('User') }</div><div class="assist-details-value" data-bind="text: user"></div></div>
  460. <div><div class="assist-details-header">${ _('Group') }</div><div class="assist-details-value" data-bind="text: group"></div></div>
  461. <!-- /ko -->
  462. <div><div class="assist-details-header">${ _('Permissions') }</div><div class="assist-details-value" data-bind="text: rwx"></div></div>
  463. <div><div class="assist-details-header">${ _('Date') }</div><div class="assist-details-value" data-bind="text: mtime"></div></div>
  464. </div>
  465. <!-- /ko -->
  466. </script>
  467. <script type="text/html" id="hdfs-details-title">
  468. <span data-bind="text: definition.name"></span>
  469. </script>
  470. <script type="text/html" id="assist-hdfs-header-actions">
  471. <div class="assist-db-header-actions"style="margin-top: -1px;">
  472. <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>
  473. </div>
  474. </script>
  475. <script type="text/html" id="assist-hdfs-inner-panel">
  476. <div class="assist-inner-panel">
  477. <div class="assist-flex-panel">
  478. <!-- ko with: selectedHdfsEntry -->
  479. <div class="assist-flex-header assist-breadcrumb" >
  480. <!-- ko if: parent !== null -->
  481. <a href="javascript: void(0);" data-bind="click: function () { huePubSub.publish('assist.selectHdfsEntry', parent); }">
  482. <i class="fa fa-chevron-left" style="font-size: 15px;margin-right:8px;"></i>
  483. <i class="fa fa-folder-o" style="font-size: 14px; line-height: 16px; vertical-align: top; margin-right:4px;"></i>
  484. <span style="font-size: 14px;line-height: 16px;vertical-align: top;" data-bind="text: path"></span>
  485. </a>
  486. <!-- /ko -->
  487. <!-- ko if: parent === null -->
  488. <div>
  489. <i class="fa fa-folder-o" style="font-size: 14px; line-height: 16px;vertical-align: top; margin-right:4px;"></i>
  490. <span style="font-size: 14px;line-height: 16px;vertical-align: top;" data-bind="text: path"></span>
  491. </div>
  492. <!-- /ko -->
  493. <!-- ko template: 'assist-hdfs-header-actions' --><!-- /ko -->
  494. </div>
  495. <div class="assist-flex-fill assist-hdfs-scrollable">
  496. <div data-bind="visible: ! loading() && ! hasErrors()">
  497. <ul class="assist-tables" data-bind="foreachVisible: {data: entries, minHeight: 20, container: '.assist-hdfs-scrollable' }">
  498. <li class="assist-entry assist-table-link" style="position: relative;" data-bind="visibleOnHover: { 'selector': '.assist-actions' }">
  499. <div class="assist-actions table-actions" style="opacity: 0;" >
  500. <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' }">
  501. <i class='fa fa-info' title="${ _('Details') }"></i>
  502. </a>
  503. </div>
  504. <a href="javascript:void(0)" class="assist-entry assist-table-link" data-bind="multiClick: { click: toggleOpen, dblClick: dblClick }, attr: {'title': definition.name }">
  505. <!-- ko if: definition.type === 'dir' -->
  506. <i class="fa fa-fw fa-folder-o muted valign-middle"></i>
  507. <!-- /ko -->
  508. <!-- ko if: definition.type === 'file' -->
  509. <i class="fa fa-fw fa-file-o muted valign-middle"></i>
  510. <!-- /ko -->
  511. <span draggable="true" data-bind="text: definition.name, draggableText: { text: '\'' + path + '\'', meta: {'type': 'hdfs', 'definition': definition} }"></span>
  512. </a>
  513. </li>
  514. </ul>
  515. <!-- ko if: !loading() && entries().length === 0 -->
  516. <ul class="assist-tables">
  517. <li class="assist-entry" style="font-style: italic;">${_('Empty directory')}</li>
  518. </ul>
  519. <!-- /ko -->
  520. </div>
  521. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  522. <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
  523. <span>${ _('Error loading contents.') }</span>
  524. </div>
  525. </div>
  526. <!-- /ko -->
  527. </div>
  528. <!-- ko with: $parents[1] -->
  529. <!-- ko template: { if: (searchInput() !== '' || searchHasFocus()) && navigatorEnabled(), name: 'nav-search-result' } --><!-- /ko -->
  530. <!-- /ko -->
  531. </div>
  532. </script>
  533. <script type="text/html" id="file-details-content">
  534. <!-- ko with: definition -->
  535. <div class="assist-details-wrap">
  536. <div><div class="assist-details-header">${ _('Description') }</div><div class="assist-details-value" data-bind="text: description"></div></div>
  537. <div><div class="assist-details-header">${ _('Modified') }</div><div class="assist-details-value" data-bind="text: localeFormat(last_modified)"></div></div>
  538. <div><div class="assist-details-header">${ _('Owner') }</div><div class="assist-details-value" data-bind="text: owner"></div></div>
  539. </div>
  540. <!-- /ko -->
  541. </script>
  542. <script type="text/html" id="file-details-title">
  543. <span data-bind="text: definition().name"></span>
  544. </script>
  545. <script type="text/html" id="assist-file-panel">
  546. <div class="assist-flex-header assist-breadcrumb">
  547. <!-- ko with: activeEntry -->
  548. <!-- ko ifnot: isRoot -->
  549. <a href="javascript: void(0);" data-bind="click: function () { parent.makeActive(); }">
  550. <i class="fa fa-chevron-left" style="font-size: 15px;margin-right:8px;"></i>
  551. <i class="fa fa-folder-o" style="font-size: 14px; line-height: 16px; vertical-align: top; margin-right:4px;"></i>
  552. <span style="font-size: 14px;line-height: 16px;vertical-align: top;" data-bind="text: definition().name"></span>
  553. </a>
  554. <!-- /ko -->
  555. <!-- ko if: isRoot -->
  556. <div>
  557. <i class="fa fa-folder-o" style="font-size: 14px; line-height: 16px;vertical-align: top;margin-right:4px;"></i>
  558. <span style="font-size: 14px;line-height: 16px;vertical-align: top;">/</span>
  559. </div>
  560. <!-- /ko -->
  561. <!-- /ko -->
  562. </div>
  563. <div class="assist-flex-fill assist-file-scrollable">
  564. <!-- ko with: activeEntry -->
  565. <div data-bind="visible: ! loading() && ! hasErrors() && entries().length > 0">
  566. <ul class="assist-tables" data-bind="foreachVisible: {data: entries, minHeight: 20, container: '.assist-file-scrollable' }">
  567. <li class="assist-entry assist-file-entry" style="position: relative;" data-bind="assistFileDroppable, visibleOnHover: { 'selector': '.assist-file-actions' }">
  568. <div class="assist-file-actions table-actions" style="opacity: 0;" >
  569. <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' }">
  570. <i class='fa fa-info' title="${ _('Details') }"></i>
  571. </a>
  572. </div>
  573. <a href="javascript:void(0)" class="assist-entry assist-table-link" data-bind="click: open, attr: {'title': name }">
  574. <!-- ko if: isDirectory -->
  575. <i class="fa fa-fw fa-folder-o muted valign-middle"></i>
  576. <!-- /ko -->
  577. <!-- ko ifnot: isDirectory -->
  578. <i class="fa fa-fw fa-file-o muted valign-middle"></i>
  579. <!-- /ko -->
  580. <span data-bind="draggableText: { text: definition().name, meta: {'type': 'document', 'definition': definition()} }, text: definition().name"></span>
  581. </a>
  582. </li>
  583. </ul>
  584. </div>
  585. <div data-bind="visible: !loading() && ! hasErrors() && entries().length === 0">
  586. <span style="font-style: italic;">${_('Empty directory')}</span>
  587. </div>
  588. <div class="center" data-bind="visible: loading() && ! hasErrors()">
  589. <!--[if !IE]><!--><i class="fa fa-spinner fa-spin" style="font-size: 20px; color: #BBB"></i><!--<![endif]-->
  590. <!--[if IE]><img src="${ static('desktop/art/spinner.gif') }"/><![endif]-->
  591. </div>
  592. <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
  593. <span>${ _('Error loading contents.') }</span>
  594. </div>
  595. <!-- /ko -->
  596. </div>
  597. </script>
  598. <script type="text/html" id="assist-documents-inner-panel">
  599. <div class="assist-inner-panel">
  600. <div class="assist-flex-panel">
  601. <!-- ko template: 'assist-file-panel' --><!-- /ko -->
  602. </div>
  603. </div>
  604. </script>
  605. <script type="text/html" id="assist-sources-template">
  606. <div class="assist-flex-header">
  607. <div class="assist-inner-header">
  608. ${_('Sources')}
  609. </div>
  610. </div>
  611. <div class="assist-flex-fill">
  612. <ul class="assist-tables" data-bind="foreach: sources">
  613. <li class="assist-table">
  614. <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>
  615. </li>
  616. </ul>
  617. </div>
  618. </script>
  619. <script type="text/html" id="ask-for-invalidate-title">
  620. <a class="pull-right pointer close-popover inactive-action"><i class="fa fa-times"></i></a>
  621. </script>
  622. <script type="text/html" id="ask-for-invalidate-content">
  623. <label class="radio" style="margin-bottom: 2px;">
  624. <input type="radio" name="refreshImpala" value="cache" data-bind="checked: invalidateOnRefresh" />
  625. ${ _('Clear cache') }
  626. </label>
  627. <label class="radio" style="margin-bottom: 2px;">
  628. <input type="radio" name="refreshImpala" value="invalidate" data-bind="checked: invalidateOnRefresh" />
  629. ${ _('Perform incremental metadata update') }
  630. </label>
  631. <div style="display: inline-block; margin-left: 20px; font-style: italic; color: #999;">${ _('This will sync missing tables in Hive.') }</div>
  632. <label class="radio" style="margin-bottom: 2px;">
  633. <input type="radio" name="refreshImpala" value="invalidateAndFlush" data-bind="checked: invalidateOnRefresh" />
  634. ${ _('Invalidate all metadata and rebuild index') }
  635. </label>
  636. <div style="display: inline-block; margin-left: 20px; font-style: italic; color: #999;">${ _('WARNING: This can be both resource and time-intensive.') }</div>
  637. <div style="width: 100%; display: inline-block; margin-top: 5px;"><button class="pull-right btn btn-primary" data-bind="css: { 'btn-primary': invalidateOnRefresh() !== 'invalidateAndFlush', 'btn-danger': invalidateOnRefresh() === 'invalidateAndFlush' }, click: function () { huePubSub.publish('close.popover'); triggerRefresh(); }, clickBubble: false">${ _('Refresh') }</button></div>
  638. </script>
  639. <script type="text/html" id="assist-db-header-actions">
  640. <div class="assist-db-header-actions">
  641. <span class="assist-tables-counter">(<span data-bind="text: filteredEntries().length"></span>)</span>
  642. <!-- ko ifnot: loading -->
  643. <a class="inactive-action" href="javascript:void(0)" data-bind="click: toggleSearch, css: { 'blue' : isSearchVisible }"><i class="pointer fa fa-search" title="${_('Search')}"></i></a>
  644. <!-- ko if: sourceType === 'impala' -->
  645. <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>
  646. <!-- /ko -->
  647. <!-- ko if: sourceType !== 'impala' -->
  648. <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>
  649. <!-- /ko -->
  650. <!-- /ko -->
  651. <!-- ko if: loading -->
  652. <span style="color: #aaa;"><i class="fa fa-search" title="${_('Search')}"></i></span>
  653. <i class="fa fa-refresh fa-spin blue" title="${_('Manually refresh the table list')}"></i></a>
  654. <!-- /ko -->
  655. </div>
  656. </script>
  657. <script type="text/html" id="assist-databases-template">
  658. <div class="assist-flex-header" data-bind="visibleOnHover: { selector: '.hover-actions', override: loading() || isSearchVisible() }">
  659. <div class="assist-inner-header">
  660. ${_('Databases')}
  661. <!-- ko template: 'assist-db-header-actions' --><!-- /ko -->
  662. </div>
  663. </div>
  664. <div class="assist-flex-search" data-bind="visible: hasEntries() && isSearchVisible() && ! hasErrors()">
  665. <div><input id="searchInput" class="clearable" type="text" placeholder="${ _('Database name...') }" style="margin-top:3px;width:90%;" data-bind="hasFocus: editingSearch, clearable: filter.query, value: filter.query, valueUpdate: 'afterkeydown'"/></div>
  666. </div>
  667. <div class="assist-flex-fill assist-db-scrollable" data-bind="visible: ! hasErrors() && ! loading() && hasEntries()" style="display: none;">
  668. <!-- ko if: ! loading() && filteredEntries().length == 0 -->
  669. <ul class="assist-tables">
  670. <li class="assist-entry no-entries">${_('No results found')}</li>
  671. </ul>
  672. <!-- /ko -->
  673. <ul class="assist-tables" data-bind="foreachVisible: {data: filteredEntries, minHeight: 20, container: '.assist-db-scrollable' }">
  674. <li class="assist-table" data-bind="visibleOnHover: { selector: '.database-actions' }">
  675. <!-- ko template: { name: 'assist-entry-actions' } --><!-- /ko -->
  676. <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>
  677. </li>
  678. </ul>
  679. </div>
  680. <div class="assist-flex-fill" data-bind="visible: loading" style="display: none;">
  681. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  682. </div>
  683. <div class="assist-flex-fill" data-bind="visible: hasErrors() && ! loading()" style="display: none;">
  684. <span class="assist-errors">${ _('Error loading databases.') }</span>
  685. </div>
  686. <div class="assist-flex-fill" data-bind="visible: ! hasErrors() && ! loading() && ! hasEntries()" style="display: none;">
  687. <span class="assist-errors">${ _('No databases found.') }</span>
  688. </div>
  689. </script>
  690. <script type="text/html" id="assist-tables-template">
  691. <div class="assist-flex-header">
  692. <div class="assist-inner-header" data-bind="visible: !$parent.loading() && !$parent.hasErrors()">
  693. ${_('Tables')}
  694. <!-- ko template: 'assist-db-header-actions' --><!-- /ko -->
  695. </div>
  696. </div>
  697. <div class="assist-flex-table-search" data-bind="visible: hasEntries() && isSearchVisible() && !$parent.loading() && !$parent.hasErrors()">
  698. <div><label class="checkbox inline-block margin-left-5"><input type="checkbox" data-bind="checked: filter.showTables" />Tables</label><label class="checkbox inline-block margin-left-10"><input type="checkbox" data-bind="checked: filter.showViews" />Views</label></div>
  699. <div><input id="searchInput" class="clearable" type="text" placeholder="${ _('Table name...') }" style="width:90%;" data-bind="hasFocus: editingSearch, clearable: filter.query, value: filter.query, valueUpdate: 'afterkeydown'"/></div>
  700. </div>
  701. <div class="assist-flex-fill assist-db-scrollable" data-bind="visible: ! hasErrors() && ! loading()" style="display: none;">
  702. <!-- ko template: 'assist-db-entries' --><!-- /ko -->
  703. </div>
  704. <div class="assist-flex-fill" data-bind="visible: loading() || $parent.loading()" style="display: none;">
  705. <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
  706. </div>
  707. <div class="assist-flex-fill" data-bind="visible: hasErrors() && ! loading()" style="display: none;">
  708. <span class="assist-errors">${ _('Error loading tables.') }</span>
  709. </div>
  710. </script>
  711. <script type="text/html" id="nav-search-autocomp-item">
  712. <a><i class="fa" data-bind="css: icon"></i> <span data-bind="text: label"></span></a>
  713. </script>
  714. <script type="text/html" id="assist-panel-navigator-search">
  715. <!-- ko if: navigatorEnabled -->
  716. <div class="searchbar">
  717. <input id="appendedInput" placeholder="${ _('Search everywhere...') }" type="text" data-bind="autocomplete: { source: navAutocompleteSource, itemTemplate: 'nav-search-autocomp-item' }, hasFocus: searchHasFocus, textinput: searchInput, valueUpdate: 'afterkeydown'">
  718. <button class="btn btn-primary add-on" data-bind="enabled: ! searchSubmitted(), click: function () { if (searchInput() !== '') { searchInput(''); searchHasFocus(false); } else { searchHasFocus(true); window.setTimeout(performSearch, 200); } }">
  719. <i class="fa" data-bind="css: { 'fa-search': searchInput() === '', 'fa-times' : searchInput() !== '' }"></i>
  720. </button>
  721. </div>
  722. <!-- /ko -->
  723. </script>
  724. <script type="text/html" id="assist-panel-inner-header">
  725. <div class="assist-header assist-fixed-height" data-bind="visibleOnHover: { selector: '.assist-header-actions' }, css: { 'assist-resizer': $index() > 0 }" style="display:none;">
  726. <span data-bind="text: $parent.name"></span>
  727. <div class="assist-header-actions">
  728. <div class="inactive-action" data-bind="click: function () { $parent.visible(false) }"><i class="fa fa-times"></i></div>
  729. </div>
  730. </div>
  731. </script>
  732. <script type="text/html" id="assist-panel-template">
  733. <div style="display: flex; flex-direction: column; position:relative; height: 100%; overflow: hidden;">
  734. <!-- ko template: { if: navigatorEnabled, name: 'assist-panel-navigator-search' }--><!-- /ko -->
  735. <!-- ko if: availablePanels.length > 1 -->
  736. <div style="position: relative; flex: 0 0 29px;" class="assist-panel-switches">
  737. <!-- ko foreach: availablePanels -->
  738. <div class="inactive-action assist-type-switch" data-bind="click: function () { $parent.visiblePanel($data); }, css: { 'blue': $parent.visiblePanel() === $data }, attr: { 'title': name }">
  739. <i class="fa fa-fw valign-middle" data-bind="css: icon"></i>
  740. </div>
  741. <!-- /ko -->
  742. </div>
  743. <!-- /ko -->
  744. <div style="position: relative; flex: 1 1 100%; overflow: hidden; padding-top: 10px;" data-bind="style: { 'padding-top': availablePanels.length > 1 ? '10px' : '5px' }, with: visiblePanel">
  745. <!-- ko template: { name: templateName, data: panelData } --><!-- /ko -->
  746. </div>
  747. </div>
  748. </script>
  749. <script type="text/html" id="nav-search-result">
  750. <div style="position:absolute; left:0; right: 0; top: 0; bottom: 0; overflow: hidden; background-color: #FFF;">
  751. <!-- ko hueSpinner: { spin: searching, center: true, size: 'large' } --><!-- /ko -->
  752. <!-- ko if: !searching() -->
  753. <!-- ko if: searchResult().length == 0 -->
  754. <div class="result-entry">${ _('No result found.') }</div>
  755. <!-- /ko -->
  756. <!-- ko foreach: searchResult -->
  757. <div class="result-entry">
  758. <div class="icon-col">
  759. <!-- ko if: type === 'FILE' -->
  760. <i class="fa fa-fw fa-file-o valign-middle"></i>
  761. <!-- /ko -->
  762. <!-- ko if: type === 'VIEW' -->
  763. <i class="fa fa-fw fa-eye valign-middle"></i>
  764. <!-- /ko -->
  765. <!-- ko if: type === 'DIRECTORY' -->
  766. <i class="fa fa-fw fa-folder-o valign-middle"></i>
  767. <!-- /ko -->
  768. <!-- ko if: type === 'TABLE' -->
  769. <i class="fa fa-fw fa-table valign-middle"></i>
  770. <!-- /ko -->
  771. <!-- ko if: type === 'DATABASE' -->
  772. <i class="fa fa-fw fa-database valign-middle"></i>
  773. <!-- /ko -->
  774. <!-- ko if: type === 'SOURCE' -->
  775. <i class="fa fa-fw fa-server valign-middle"></i>
  776. <!-- /ko -->
  777. <!-- ko if: type === 'SUB_OPERATION' -->
  778. <i class="fa fa-fw fa-code-fork valign-middle"></i>
  779. <!-- /ko -->
  780. <!-- ko if: type === 'FIELD' -->
  781. <i class="fa fa-fw fa-columns valign-middle"></i>
  782. <!-- /ko -->
  783. <!-- ko if: type === 'OPERATION_EXECUTION' -->
  784. <i class="fa fa-fw fa-cog valign-middle"></i>
  785. <!-- /ko -->
  786. <!-- ko if: type === 'OPERATION' -->
  787. <i class="fa fa-fw fa-cogs valign-middle"></i>
  788. <!-- /ko -->
  789. <!-- ko if: type === 'PARTITION' -->
  790. <i class="fa fa-fw fa-th valign-middle"></i>
  791. <!-- /ko -->
  792. </div>
  793. <div class="doc-col">
  794. <!-- ko if: typeof click !== 'undefined' -->
  795. <a class="pointer" data-bind="click: click" target="_blank" >
  796. <span data-bind="text: parentPath"></span>
  797. <span data-bind="text: originalName"></span>
  798. </a>
  799. <span data-bind="text: tags" class="badge badge-info"></span>
  800. <!-- /ko -->
  801. <!-- ko if: typeof click === 'undefined' -->
  802. <a class="pointer" data-bind="attr: { 'href': link }, text: originalName" target="_blank" ></a>
  803. <!-- /ko -->
  804. <!-- ko if: type === 'DATABASE' -->
  805. <div class="doc-desc" data-bind="text: originalDescription"></div>
  806. <!-- /ko -->
  807. <!-- ko if: type === 'TABLE' || type === 'VIEW' -->
  808. <div class="doc-desc" data-bind="text: originalDescription"></div>
  809. <!-- /ko -->
  810. <!-- ko if: type === 'FIELD' -->
  811. <div class="doc-desc" data-bind="text: originalDescription"></div>
  812. <!-- /ko -->
  813. <!-- ko if: type === 'PARTITION' -->
  814. <div class="doc-desc" data-bind="text: originalDescription"></div>
  815. <!-- /ko -->
  816. <!-- ko if: type === 'SUB_OPERATION' -->
  817. <div class="doc-desc" data-bind="text: metaClassName"></div>
  818. <!-- /ko -->
  819. <!-- ko if: type === 'SOURCE' -->
  820. <div class="doc-desc" data-bind="text: 'Cluster: ' + clusterName"></div>
  821. <!-- /ko -->
  822. <!-- ko if: type === 'FILE' || type === 'DIRECTORY' -->
  823. <div class="doc-desc" data-bind="text: parentPath"></div>
  824. <!-- /ko -->
  825. </div>
  826. </div>
  827. <!-- /ko -->
  828. <!-- /ko -->
  829. </div>
  830. </script>
  831. <script type="text/javascript" charset="utf-8">
  832. (function (factory) {
  833. if(typeof require === "function") {
  834. define('assistPanel', [
  835. 'knockout',
  836. 'desktop/js/assist/assistDbSource',
  837. 'desktop/js/assist/assistHdfsEntry',
  838. 'desktop/js/apiHelper',
  839. 'desktop/js/fileBrowser/hueFileEntry'
  840. ], factory);
  841. } else {
  842. factory(ko, AssistDbSource, AssistHdfsEntry, ApiHelper, HueFileEntry);
  843. }
  844. }(function (ko, AssistDbSource, AssistHdfsEntry, ApiHelper, HueFileEntry) {
  845. ko.bindingHandlers.assistFileDroppable = {
  846. init: function(element, valueAccessor, allBindings, boundEntry) {
  847. var dragData;
  848. huePubSub.subscribe('file.browser.dragging', function (data) {
  849. dragData = data;
  850. });
  851. var $element = $(element);
  852. if (boundEntry.isDirectory) {
  853. $element.droppable({
  854. drop: function () {
  855. if (dragData && !dragData.dragToSelect) {
  856. boundEntry.moveHere(dragData.selectedEntries);
  857. dragData.originEntry.load();
  858. }
  859. },
  860. over: function () {
  861. if (dragData && !dragData.dragToSelect) {
  862. $element.addClass('assist-file-entry-drop');
  863. }
  864. },
  865. out: function () {
  866. $element.removeClass('assist-file-entry-drop');
  867. }
  868. })
  869. }
  870. }
  871. };
  872. /**
  873. * @param {Object} options
  874. * @param {ApiHelper} options.apiHelper
  875. * @param {string} options.type
  876. * @param {number} options.minHeight
  877. * @param {string} options.icon
  878. * @param {boolean} options.visible
  879. * @param {(AssistDbPanel|AssistHdfsPanel|AssistDocumentsPanel)} panelData
  880. * @constructor
  881. */
  882. function AssistInnerPanel (options) {
  883. var self = this;
  884. self.minHeight = options.minHeight;
  885. self.icon = options.icon;
  886. self.type = options.type;
  887. self.name = options.name;
  888. self.panelData = options.panelData;
  889. self.visible = ko.observable(options.visible || true);
  890. options.apiHelper.withTotalStorage('assist', 'showingPanel_' + self.type, self.visible, false, options.visible);
  891. self.templateName = 'assist-' + self.type + '-inner-panel';
  892. var loadWhenVisible = function () {
  893. if (! self.visible()) {
  894. return;
  895. }
  896. if (self.type === 'documents' && !self.panelData.activeEntry().loaded()) {
  897. self.panelData.activeEntry().load();
  898. }
  899. };
  900. self.visible.subscribe(loadWhenVisible);
  901. loadWhenVisible();
  902. }
  903. /**
  904. * @param {Object} options
  905. * @param {ApiHelper} options.apiHelper
  906. * @param {Object} options.i18n
  907. * @param {Object[]} options.sourceTypes - All the available SQL source types
  908. * @param {string} options.sourceTypes[].name - Example: Hive SQL
  909. * @param {string} options.sourceTypes[].type - Example: hive
  910. * @param {string} [options.activeSourceType] - Example: hive
  911. * @param {Object} options.navigationSettings - enable/disable the links
  912. * @param {boolean} options.navigationSettings.openItem
  913. * @param {boolean} options.navigationSettings.showStats
  914. * @param {boolean} options.navigationSettings.pinEnabled
  915. * @constructor
  916. **/
  917. function AssistDbPanel (options) {
  918. var self = this;
  919. self.apiHelper = options.apiHelper;
  920. self.i18n = options.i18n;
  921. self.sources = ko.observableArray();
  922. var sourceIndex = {};
  923. $.each(options.sourceTypes, function (idx, sourceType) {
  924. sourceIndex[sourceType.type] = new AssistDbSource({
  925. apiHelper: self.apiHelper,
  926. i18n: self.i18n,
  927. type: sourceType.type,
  928. name: sourceType.name,
  929. navigationSettings: options.navigationSettings
  930. });
  931. self.sources.push(sourceIndex[sourceType.type]);
  932. });
  933. huePubSub.subscribe('assist.db.highlight', function (location) {
  934. var foundSource;
  935. $.each(self.sources(), function (idx, source) {
  936. if (source.sourceType === location.sourceType) {
  937. foundSource = source;
  938. return false;
  939. }
  940. });
  941. if (foundSource) {
  942. if (foundSource.hasEntries()) {
  943. self.selectedSource(foundSource);
  944. foundSource.highlightInside(location.path);
  945. } else {
  946. foundSource.initDatabases(function () {
  947. self.selectedSource(foundSource);
  948. foundSource.highlightInside(location.path);
  949. });
  950. }
  951. }
  952. });
  953. self.selectedSource = ko.observable(null);
  954. var setDatabaseWhenLoaded = function (databaseName) {
  955. if (self.selectedSource().loaded()) {
  956. self.selectedSource().setDatabase(databaseName);
  957. } else {
  958. var subscription = self.selectedSource().loaded.subscribe(function (newValue) {
  959. if (newValue) {
  960. self.selectedSource().setDatabase(databaseName);
  961. subscription.dispose();
  962. }
  963. });
  964. if (! self.selectedSource().loaded() && ! self.selectedSource().loading()) {
  965. self.selectedSource().initDatabases();
  966. }
  967. }
  968. };
  969. huePubSub.subscribe("assist.set.database", function (databaseDef) {
  970. if (! databaseDef.source || ! sourceIndex[databaseDef.source]) {
  971. return;
  972. }
  973. self.selectedSource(sourceIndex[databaseDef.source]);
  974. setDatabaseWhenLoaded(databaseDef.name);
  975. });
  976. huePubSub.subscribe("assist.get.database", function (source) {
  977. if (sourceIndex[source] && sourceIndex[source].selectedDatabase()) {
  978. huePubSub.publish("assist.database.set", {
  979. source: source,
  980. name: sourceIndex[source].selectedDatabase().databaseName
  981. });
  982. } else {
  983. huePubSub.publish("assist.database.set", {
  984. source: source,
  985. name: null
  986. });
  987. }
  988. });
  989. huePubSub.publish("assist.db.panel.ready");
  990. self.selectedSource.subscribe(function (newSource) {
  991. if (newSource) {
  992. if (newSource.databases().length === 0) {
  993. newSource.initDatabases();
  994. }
  995. self.apiHelper.setInTotalStorage('assist', 'lastSelectedSource', newSource.sourceType);
  996. } else {
  997. self.apiHelper.setInTotalStorage('assist', 'lastSelectedSource');
  998. }
  999. });
  1000. var storageSourceType = self.apiHelper.getFromTotalStorage('assist', 'lastSelectedSource');
  1001. if (! self.selectedSource()) {
  1002. if (options.activeSourceType) {
  1003. self.selectedSource(sourceIndex[options.activeSourceType]);
  1004. setDatabaseWhenLoaded();
  1005. } else if (storageSourceType && sourceIndex[storageSourceType]) {
  1006. self.selectedSource(sourceIndex[storageSourceType]);
  1007. setDatabaseWhenLoaded();
  1008. }
  1009. }
  1010. self.breadcrumb = ko.computed(function () {
  1011. if (self.selectedSource()) {
  1012. if (self.selectedSource().selectedDatabase()) {
  1013. return self.selectedSource().selectedDatabase().definition.name;
  1014. }
  1015. return self.selectedSource().name;
  1016. }
  1017. return null;
  1018. });
  1019. }
  1020. AssistDbPanel.prototype.back = function () {
  1021. var self = this;
  1022. if (self.selectedSource() && self.selectedSource().selectedDatabase()) {
  1023. self.selectedSource().selectedDatabase(null)
  1024. } else if (self.selectedSource()) {
  1025. self.selectedSource(null);
  1026. }
  1027. };
  1028. /**
  1029. * @param {Object} options
  1030. * @param {ApiHelper} options.apiHelper
  1031. * @param {string} options.user
  1032. * @param {Object} options.i18n
  1033. * @constructor
  1034. **/
  1035. function AssistDocumentsPanel (options) {
  1036. var self = this;
  1037. self.activeEntry = ko.observable();
  1038. self.activeEntry(new HueFileEntry({
  1039. activeEntry: self.activeEntry,
  1040. trashEntry: ko.observable,
  1041. apiHelper: options.apiHelper,
  1042. app: 'documents',
  1043. user: options.user,
  1044. activeSort: ko.observable('name'),
  1045. definition: {
  1046. name: '/',
  1047. type: 'directory'
  1048. }
  1049. }));
  1050. }
  1051. /**
  1052. * @param {Object} options
  1053. * @param {ApiHelper} options.apiHelper
  1054. * @constructor
  1055. **/
  1056. function AssistHdfsPanel (options) {
  1057. var self = this;
  1058. self.apiHelper = options.apiHelper;
  1059. self.selectedHdfsEntry = ko.observable();
  1060. var reload = function () {
  1061. var lastKnownPath = self.apiHelper.getFromTotalStorage('assist', 'currentHdfsPath', '/');
  1062. var parts = lastKnownPath.split('/');
  1063. parts.shift();
  1064. var currentEntry = new AssistHdfsEntry({
  1065. definition: {
  1066. name: '/',
  1067. type: 'dir'
  1068. },
  1069. parent: null,
  1070. apiHelper: self.apiHelper
  1071. });
  1072. currentEntry.loadDeep(parts, function (entry) {
  1073. self.selectedHdfsEntry(entry);
  1074. entry.open(true);
  1075. });
  1076. };
  1077. reload();
  1078. huePubSub.subscribe('assist.selectHdfsEntry', function (entry) {
  1079. self.selectedHdfsEntry(entry);
  1080. self.apiHelper.setInTotalStorage('assist', 'currentHdfsPath', entry.path);
  1081. });
  1082. huePubSub.subscribe('assist.hdfs.refresh', function () {
  1083. huePubSub.publish('assist.clear.hdfs.cache');
  1084. reload();
  1085. });
  1086. }
  1087. /**
  1088. * @param {Object} params
  1089. * @param {string} params.user
  1090. * @param {boolean} params.onlySql - For the old query editors
  1091. * @param {string[]} params.visibleAssistPanels - Panels that will initially be shown regardless of total storage
  1092. * @param {Object} params.sql
  1093. * @param {Object[]} params.sql.sourceTypes - All the available SQL source types
  1094. * @param {string} params.sql.sourceTypes[].name - Example: Hive SQL
  1095. * @param {string} params.sql.sourceTypes[].type - Example: hive
  1096. * @param {string} [params.sql.activeSourceType] - Example: hive
  1097. * @param {Object} params.sql.navigationSettings - enable/disable the links
  1098. * @param {boolean} params.sql.navigationSettings.openItem - Example: true
  1099. * @param {boolean} params.sql.navigationSettings.showStats - Example: true
  1100. * @constructor
  1101. */
  1102. function AssistPanel (params) {
  1103. var self = this;
  1104. var i18n = {
  1105. errorLoadingDatabases: "${ _('There was a problem loading the databases') }",
  1106. errorLoadingTablePreview: "${ _('There was a problem loading the table preview.') }",
  1107. documentTypes: {
  1108. 'query-hive' : "${ _('Hive Query') }",
  1109. 'query' : "${ _('Query') }",
  1110. 'notebook' : "${ _('Notebook') }"
  1111. }
  1112. };
  1113. self.apiHelper = ApiHelper.getInstance({
  1114. i18n: i18n,
  1115. user: params.user
  1116. });
  1117. self.navigatorEnabled = ko.observable('${ has_navigator() }' === 'True');
  1118. self.searchInput = ko.observable('').extend({ rateLimit: 500 });
  1119. self.searchResult = ko.observableArray();
  1120. self.navAutocompleteSource = function (request, callback) {
  1121. var term = request.term;
  1122. self.apiHelper.navSearchAutocomplete({
  1123. query: term + '*',
  1124. successCallback: function (data) {
  1125. var values = [];
  1126. if (typeof data.facets !== 'undefined') {
  1127. Object.keys(data.facets).forEach(function (facet) {
  1128. if (facet === 'tags') {
  1129. values.push({ data: { label: 'tags:', icon: 'fa-tags' }, value: 'tags:'});
  1130. }
  1131. });
  1132. }
  1133. if (typeof data.results !== 'undefined') {
  1134. data.results.forEach(function (result) {
  1135. var icon = '';
  1136. switch (result.type) {
  1137. case 'TABLE':
  1138. icon = 'fa-table';
  1139. break;
  1140. case 'VIEW':
  1141. icon = 'fa-eye';
  1142. break;
  1143. }
  1144. if (data.highlting && data.highlighting[result.identity] && data.highlighting[result.identity].originalName) {
  1145. values.push({ data: { label: data.highlighting[result.identity].originalName, icon: icon }, value: result.originalName });
  1146. } else {
  1147. values.push({ data: { label: result.originalName, icon: icon }, value: result.originalName });
  1148. }
  1149. });
  1150. callback(values);
  1151. }
  1152. },
  1153. silenceErrors: true,
  1154. errorCallback: function () {
  1155. callback([]);
  1156. }
  1157. });
  1158. };
  1159. self.searchHasFocus = ko.observable(false);
  1160. self.searching = ko.observable(false);
  1161. self.searchInput.subscribe(function (newValue) {
  1162. self.performSearch(newValue);
  1163. });
  1164. var lastQuery = -1;
  1165. self.loading = ko.observable(false);
  1166. self.availablePanels = [
  1167. new AssistInnerPanel({
  1168. panelData: new AssistDbPanel($.extend({
  1169. apiHelper: self.apiHelper,
  1170. i18n: i18n
  1171. }, params.sql)),
  1172. apiHelper: self.apiHelper,
  1173. name: '${ _("SQL") }',
  1174. type: 'hive',
  1175. icon: 'fa-database',
  1176. minHeight: 75
  1177. })
  1178. ];
  1179. % if USE_NEW_SIDE_PANELS.get():
  1180. self.availablePanels.push(new AssistInnerPanel({
  1181. panelData: new AssistHdfsPanel({
  1182. apiHelper: self.apiHelper
  1183. }),
  1184. apiHelper: self.apiHelper,
  1185. name: '${ _("HDFS") }',
  1186. type: 'hdfs',
  1187. icon: 'fa-folder-o',
  1188. minHeight: 50
  1189. }));
  1190. ## self.availablePanels.push(new AssistInnerPanel({
  1191. ## panelData: new AssistDocumentsPanel({
  1192. ## user: params.user,
  1193. ## apiHelper: self.apiHelper,
  1194. ## i18n: i18n
  1195. ## }),
  1196. ## apiHelper: self.apiHelper,
  1197. ## name: '${ _("Documents") }',
  1198. ## type: 'documents',
  1199. ## icon: 'fa-files-o',
  1200. ## minHeight: 50,
  1201. ## visible: params.visibleAssistPanels && params.visibleAssistPanels.indexOf('documents') !== -1
  1202. ## }));
  1203. % endif
  1204. self.performSearch = function () {
  1205. if (self.searchInput() === lastQuery) {
  1206. return;
  1207. }
  1208. if (self.searching()) {
  1209. window.setTimeout(function() {
  1210. self.performSearch();
  1211. }, 100);
  1212. }
  1213. lastQuery = self.searchInput();
  1214. self.searching(true);
  1215. var showInAssist = function (entry) {
  1216. self.searchInput('');
  1217. self.searchHasFocus(false);
  1218. var path = entry.parentPath.split('/').concat([entry.originalName]).splice(1);
  1219. window.setTimeout(function () {
  1220. huePubSub.publish('assist.db.highlight', { sourceType: entry.sourceType.toLowerCase(), path: path });
  1221. }, 200); // For animation effect
  1222. };
  1223. $.post('/metadata/api/navigator/search_entities', {
  1224. query_s: self.searchInput(),
  1225. limit: 25,
  1226. sources: ko.mapping.toJSON([self.visiblePanel().type])
  1227. }, function (data) {
  1228. data.entities.forEach(function (entity) {
  1229. if (entity.type === 'DATABASE') {
  1230. entity.click = function () {
  1231. showInAssist(entity);
  1232. }
  1233. } else if (entity.type === 'TABLE') {
  1234. entity.click = function () {
  1235. showInAssist(entity);
  1236. }
  1237. } else if (entity.type === 'FIELD') {
  1238. entity.click = function () {
  1239. showInAssist(entity);
  1240. }
  1241. } else if (entity.type === 'SOURCE') {
  1242. entity.link = entity.sourceUrl;
  1243. } else if (entity.type === 'OPERATION_EXECUTION') {
  1244. entity.link = '/jobbrowser/jobs/' + entity.jobID;
  1245. } else if (entity.type === 'DIRECTORY' || entity.type === 'FILE') {
  1246. entity.link = '/filebrowser/#' + entity.fileSystemPath;
  1247. } else {
  1248. entity.link = '#';
  1249. }
  1250. });
  1251. self.searchResult(data.entities);
  1252. self.searching(false);
  1253. }).fail(function (xhr, textStatus, errorThrown) {
  1254. $(document).trigger("error", xhr.responseText);
  1255. self.searching(false);
  1256. });
  1257. };
  1258. self.visiblePanel = ko.observable(self.availablePanels[0]);
  1259. self.visiblePanel.subscribe(function() {
  1260. if (self.navigatorEnabled()) {
  1261. lastQuery = 'refresh';
  1262. self.performSearch();
  1263. }
  1264. });
  1265. }
  1266. ko.components.register('assist-panel', {
  1267. viewModel: AssistPanel,
  1268. template: { element: 'assist-panel-template' }
  1269. });
  1270. }));
  1271. </script>
  1272. </%def>