metastore.mako 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. ## Licensed to Cloudera, Inc. under one
  2. ## or more contributor license agreements. See the NOTICE file
  3. ## distributed with this work for additional information
  4. ## regarding copyright ownership. Cloudera, Inc. licenses this file
  5. ## to you under the Apache License, Version 2.0 (the
  6. ## "License"); you may not use this file except in compliance
  7. ## with the License. You may obtain a copy of the License at
  8. ##
  9. ## http://www.apache.org/licenses/LICENSE-2.0
  10. ##
  11. ## Unless required by applicable law or agreed to in writing, software
  12. ## distributed under the License is distributed on an "AS IS" BASIS,
  13. ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ## See the License for the specific language governing permissions and
  15. ## limitations under the License.
  16. <%!
  17. from django.utils.html import escape
  18. from desktop import conf
  19. from desktop.lib.i18n import smart_unicode
  20. from desktop.views import commonheader, commonfooter, _ko
  21. from django.utils.translation import ugettext as _
  22. %>
  23. <%namespace name="actionbar" file="actionbar.mako" />
  24. <%namespace name="components" file="components.mako" />
  25. <%namespace name="assist" file="/assist.mako" />
  26. <%namespace name="tableStats" file="/table_stats.mako" />
  27. <%namespace name="require" file="/require.mako" />
  28. ${ commonheader(_("Metastore"), app_name, user) | n,unicode }
  29. ${ components.menubar() }
  30. ${ require.config() }
  31. ${ tableStats.tableStats() }
  32. ${ assist.assistPanel() }
  33. <script src="${ static('desktop/ext/js/bootstrap-editable.min.js') }" type="text/javascript" charset="utf-8"></script>
  34. <script src="${ static('desktop/ext/js/d3.v3.js') }" type="text/javascript" charset="utf-8"></script>
  35. <script src="${ static('beeswax/js/stats.utils.js') }"></script>
  36. <link rel="stylesheet" href="${ static('desktop/ext/css/bootstrap-editable.css') }">
  37. <link rel="stylesheet" href="${ static('metastore/css/metastore.css') }" type="text/css">
  38. <link rel="stylesheet" href="${ static('notebook/css/notebook.css') }">
  39. <style type="text/css">
  40. % if conf.CUSTOM.BANNER_TOP_HTML.get():
  41. .show-assist {
  42. top: 110px!important;
  43. }
  44. .main-content {
  45. top: 112px!important;
  46. }
  47. % endif
  48. </style>
  49. <script type="text/html" id="metastore-breadcrumbs">
  50. <ul class="nav nav-pills hueBreadcrumbBar" id="breadcrumbs">
  51. <li>
  52. <a href="javascript:void(0);" data-bind="click: databasesBreadcrumb">${_('Databases')}</a>
  53. <!-- ko if: database -->
  54. <span class="divider">&gt;</span>
  55. <!-- /ko -->
  56. </li>
  57. <!-- ko with: database -->
  58. <li>
  59. <a href="javascript:void(0);" data-bind="text: name, click: $root.tablesBreadcrumb"></a>
  60. <!-- ko if: table -->
  61. <span class="divider">&gt;</span>
  62. <!-- /ko -->
  63. </li>
  64. <!-- ko with: table -->
  65. <li>
  66. <span style="padding-left:12px" data-bind="text: name"></span>
  67. </li>
  68. <!-- /ko -->
  69. <!-- /ko -->
  70. </ul>
  71. </script>
  72. <script type="text/html" id="metastore-columns-table">
  73. <table class="table table-striped table-condensed table-nowrap">
  74. <thead>
  75. <tr>
  76. <th width="1%">&nbsp;</th>
  77. ## no stats for partition key type
  78. <th width="1%" class="no-sort">&nbsp;</th>
  79. <th width="1%">&nbsp;</th>
  80. <th width="17%">${_('Name')}</th>
  81. <th width="30%">${_('Type')}</th>
  82. <th width="50%">${_('Comment')}</th>
  83. </tr>
  84. </thead>
  85. <tbody data-bind="hueach: {data: $data, itemHeight: 29, scrollable: '.right-panel', scrollableOffset: 200}">
  86. <tr>
  87. ## start at 1
  88. <td data-bind="text: $index()+$indexOffset()+1"></td>
  89. ## no stats for partition key type
  90. <td>
  91. <span class="blue" data-bind="component: { name: 'table-stats', params: {
  92. alwaysActive: true,
  93. statsVisible: true,
  94. sourceType: 'hive',
  95. databaseName: table.database.name,
  96. tableName: table.name,
  97. columnName: name,
  98. fieldType: type,
  99. assistHelper: table.assistHelper
  100. } }"></span>
  101. </td>
  102. <td class="pointer" data-bind="click: function() { favourite(!favourite()) }"><i style="color: #338bb8" class="fa" data-bind="css: {'fa-star': favourite, 'fa-star-o': !favourite() }"></i></td>
  103. <td title="${ _("Scroll to the column") }">
  104. <a href="javascript:void(0)" class="column-selector" data-bind="text: name"></a>
  105. </td>
  106. <td data-bind="text: type"></td>
  107. <td>
  108. <span data-bind="editable: comment, editableOptions: {enabled: true, placement: 'left', emptytext: '${ _ko('Add a comment...') }' }" class="editable editable-click editable-empty">
  109. ${ _('Add a comment...') }</span>
  110. </td>
  111. </tr>
  112. </tbody>
  113. </table>
  114. </script>
  115. <script type="text/html" id="metastore-partition-columns-table">
  116. <div style="overflow: auto">
  117. <table class="table table-striped table-condensed table-nowrap">
  118. <thead>
  119. <tr>
  120. <th style="width: 10px"></th>
  121. <th>${_('Name')}</th>
  122. <th>${_('Type')}</th>
  123. </tr>
  124. </thead>
  125. <tbody>
  126. <!-- ko foreach: detailedKeys -->
  127. <tr>
  128. <td data-bind="text: $index() + 1"></td>
  129. <td data-bind="text: $data.name"></td>
  130. <td data-bind="text: $data.type"></td>
  131. </tr>
  132. <!-- /ko -->
  133. </tbody>
  134. </table>
  135. </div>
  136. </script>
  137. <script type="text/html" id="metastore-partition-values-table">
  138. <div style="overflow: auto">
  139. <table class="table table-striped table-condensed table-nowrap">
  140. <thead>
  141. <tr>
  142. <th style="width: 10px"></th>
  143. <th>${_('Values')}</th>
  144. <th>${_('Spec')}</th>
  145. <th>${_('Browse')}</th>
  146. </tr>
  147. </thead>
  148. <tbody>
  149. <!-- ko foreach: values -->
  150. <tr>
  151. <td data-bind="text: $index()+1"></td>
  152. <td><a data-bind="attr: {'href': readUrl }, text: '[\'' + columns.join('\',\'') + '\']'"></a></td>
  153. <td data-bind="text: partitionSpec"></td>
  154. <td>
  155. <a data-bind="attr: {'href': readUrl }"><i class="fa fa-th"></i> ${_('Data')}</a>
  156. <a data-bind="attr: {'href': browseUrl }"><i class="fa fa-file-o"></i> ${_('Files')}</a>
  157. </td>
  158. </tr>
  159. <!-- /ko -->
  160. </tbody>
  161. </table>
  162. </div>
  163. </script>
  164. <script type="text/html" id="metastore-samples-table">
  165. <div style="overflow: auto">
  166. <table class="table table-striped table-condensed table-nowrap">
  167. <thead>
  168. <tr>
  169. <th style="width: 10px"></th>
  170. <!-- ko foreach: headers -->
  171. <th data-bind="text: $data"></th>
  172. <!-- /ko -->
  173. </tr>
  174. </thead>
  175. <tbody>
  176. <!-- ko foreach: rows -->
  177. <tr>
  178. <td data-bind="text: $index()+1"></td>
  179. <!-- ko foreach: $data -->
  180. <td data-bind="text: $data"></td>
  181. <!-- /ko -->
  182. </tr>
  183. <!-- /ko -->
  184. </tbody>
  185. </table>
  186. </div>
  187. <div id="jumpToColumnAlert" class="alert hide" style="margin-top: 12px;">
  188. <button type="button" class="close" data-dismiss="alert">&times;</button>
  189. <strong>${_('Did you know?')}</strong>
  190. <ul>
  191. <li>${ _('If the sample contains a large number of columns, click a row to select a column to jump to') }</li>
  192. </ul>
  193. </div>
  194. </script>
  195. <script type="text/html" id="metastore-table-properties">
  196. <!-- ko with: tableDetails -->
  197. <h4>${ _('Properties') }</h4>
  198. <div class="row-fluid">
  199. <div title="${ _('Type') }">
  200. <!-- ko if: is_view -->
  201. <i class="fa fa-fw fa-eye muted"></i> ${ _('View') }
  202. <!-- /ko -->
  203. <!-- ko ifnot: is_view -->
  204. <i class="fa fa-fw fa-table muted"></i> ${ _('Table') }
  205. <!-- /ko -->
  206. </div>
  207. <div title="${ _('Owner') }">
  208. <i class="fa fa-fw fa-user muted"></i> <a data-bind="text: details.properties.owner, attr: { 'href': '/useradmin/users/view/' + details.properties.owner }"></a>
  209. </div>
  210. <div title="${ _('Created') }"><i class="fa fa-fw fa-clock-o muted"></i> <span data-bind="text: details.properties.create_time"></span></div>
  211. <div title="${ _('Format') }">
  212. <i class="fa fa-fw fa-file-o muted"></i> <span data-bind="text: details.properties.format"></span>
  213. <i class="fa fa-fw fa-archive muted"></i> <span data-bind="visible: details.properties.compressed" style="display:none;">${_('Compressed')}</span>
  214. <span data-bind="visible: !details.stats.compressed" style="display:none;">${_('Not compressed')}</span>
  215. </div>
  216. </div>
  217. <!-- /ko -->
  218. </script>
  219. <script type="text/html" id="metastore-table-stats">
  220. <!-- ko if: tableDetails() && ! tableDetails().is_view -->
  221. <!-- ko with: tableDetails -->
  222. <h4>${ _('Stats') }
  223. <!-- ko ifnot: partition_keys.length -->
  224. <!-- ko if: $parent.refreshingTableStats -->
  225. <i class="fa fa-refresh fa-spin"></i>
  226. <!-- /ko -->
  227. <!-- ko ifnot: $parent.refreshingTableStats() || is_view -->
  228. <a class="pointer" href="javascript: void(0);" data-bind="click: $parent.refreshTableStats"><i class="fa fa-refresh"></i></a>
  229. <!-- /ko -->
  230. <span data-bind="visible: ! details.stats.COLUMN_STATS_ACCURATE && ! is_view" rel="tooltip" data-placement="top" title="${ _('The column stats for this table are not accurate') }"><i class="fa fa-exclamation-triangle"></i></span>
  231. <!-- /ko -->
  232. </h4>
  233. <div class="row-fluid">
  234. <div>
  235. <i class="fa fa-fw fa-hdd-o muted"></i> <a data-bind="attr: {'href': hdfs_link, 'rel': path_location}">${_('Location')}</a>
  236. </div>
  237. <!-- ko with: $parent.tableStats -->
  238. <!-- ko if: typeof numFiles !== 'undefined' -->
  239. <div title="${ _('Number of files') }"><i class="fa fa-fw fa-files-o muted"></i> <span data-bind="text: numFiles"></span> ${ _('files') }</div>
  240. <!-- /ko -->
  241. <!-- ko if: typeof numRows !== 'undefined' -->
  242. <div title="${ _('Number of rows') }"><i class="fa fa-fw fa-list muted"></i> <span data-bind="text: numRows"></span> ${ _('rows') }</div>
  243. <!-- /ko -->
  244. <!-- ko if: typeof totalSize !== 'undefined' -->
  245. <div title="${ _('Total size') }"><i class="fa fa-fw fa-tasks muted"></i> <span data-bind="text: totalSize"></span> ${ _('bytes') }</div>
  246. <!-- /ko -->
  247. <!-- /ko -->
  248. </div>
  249. <!-- /ko -->
  250. <!-- /ko -->
  251. </script>
  252. <a title="${_('Toggle Assist')}" class="pointer show-assist" data-bind="visible: !$root.isLeftPanelVisible() && $root.assistAvailable(), click: function() { $root.isLeftPanelVisible(true); }">
  253. <i class="fa fa-chevron-right"></i>
  254. </a>
  255. <script type="text/html" id="metastore-databases">
  256. <div class="actionbar-actions">
  257. <input class="input-xlarge search-query margin-left-10" type="text" placeholder="${ _('Search for a database...') }" data-bind="clearable: databaseQuery, value: databaseQuery, valueUpdate: 'afterkeydown'"/>
  258. % if has_write_access:
  259. <button class="btn toolbarBtn margin-left-20" title="${_('Drop the selected databases')}" data-bind="click: function () { $('#dropDatabase').modal('show'); }, disable: selectedDatabases().length === 0"><i class="fa fa-times"></i> ${_('Drop')}</button>
  260. <div id="dropDatabase" class="modal hide fade">
  261. <form id="dropDatabaseForm" action="/metastore/databases/drop" method="POST">
  262. ${ csrf_token(request) | n,unicode }
  263. <div class="modal-header">
  264. <a href="#" class="close" data-dismiss="modal">&times</a>
  265. <h3 id="dropDatabaseMessage">${ _('Do you really want to delete the database(s)?') }</h3>
  266. </div>
  267. <div class="modal-footer">
  268. <input type="button" class="btn" data-dismiss="modal" value="Cancel">
  269. <input type="submit" data-bind="click: function () { huePubSub.publish('assist.refresh'); selectedDatabases([]); return true; }" class="btn btn-danger" value="${_('Yes')}"/>
  270. </div>
  271. <!-- ko foreach: selectedDatabases -->
  272. <input type="hidden" name="database_selection" data-bind="value: name" />
  273. <!-- /ko -->
  274. </form>
  275. </div>
  276. % endif
  277. </div>
  278. <table id="databasesTable" class="table table-condensed datatables" style="margin-bottom: 10px" data-bind="visible: filteredDatabases().length > 0">
  279. <thead>
  280. <tr>
  281. <th width="1%" style="text-align: center"><div class="hueCheckbox fa" data-bind="hueCheckAll: { allValues: filteredDatabases, selectedValues: selectedDatabases }"></div></th>
  282. <th>${ _('Database Name') }</th>
  283. </tr>
  284. </thead>
  285. <tbody data-bind="hueach: {data: filteredDatabases, itemHeight: 29, scrollable: '.right-panel', scrollableOffset: 145}">
  286. <tr>
  287. <td width="1%" style="text-align: center">
  288. <div class="hueCheckbox fa" data-bind="multiCheck: '#databasesTable', value: $data, hueChecked: $parent.selectedDatabases"></div>
  289. </td>
  290. <td>
  291. <a href="javascript: void(0);" data-bind="text: name, click: function () { $parent.setDatabase($data, function(){ huePubSub.publish('metastore.url.change'); }) }"></a>
  292. </td>
  293. </tr>
  294. </tbody>
  295. </table>
  296. <span class="margin-left-10" data-bind="visible: filteredDatabases().length === 0" style="font-style: italic; display: none;">${_('No databases found')}</span>
  297. </script>
  298. <script type="text/html" id="metastore-tables">
  299. <!-- ko with: stats -->
  300. <div class="row-fluid">
  301. <div class="span12 tile">
  302. <h4>${ _('Stats') }</h4>
  303. <div class="row-fluid">
  304. <div class="span6">
  305. <div title="${ _('Comment') }"><i class="fa fa-fw fa-comment muted"></i>
  306. <!-- ko if: comment -->
  307. <span data-bind="text: comment"></span>
  308. <!-- /ko -->
  309. <!-- ko ifnot: comment -->
  310. <i>${_('No comment.')}</i>
  311. <!-- /ko -->
  312. </div>
  313. </div>
  314. <div class="span3">
  315. <div title="${ _('Owner') }">
  316. <i class="fa fa-fw fa-user muted"></i> <a data-bind="attr: { 'href': '/useradmin/users/view/' + owner_name }">
  317. <span data-bind="text: owner_name"></span> (<span data-bind="text: owner_type"></span>)
  318. </a>
  319. </div>
  320. </div>
  321. <div class="span3">
  322. <div>
  323. <i class="fa fa-fw fa-hdd-o muted"></i> <a data-bind="attr: {'href': hdfs_link, 'rel': location }"> ${_('Location')}</a>
  324. </div>
  325. </div>
  326. </div>
  327. <!-- ko with: parameters -->
  328. <div class="row-fluid">
  329. <div class="span12">
  330. <div title="${ _('Parameters') }">
  331. <!-- ko template: { name: 'metastore-databases-parameters', data: hueUtils.parseHivePseudoJson($data) }--><!-- /ko -->
  332. </div>
  333. </div>
  334. </div>
  335. <!-- /ko -->
  336. </div>
  337. </div>
  338. <!-- /ko -->
  339. <div class="row-fluid">
  340. <div class="span12 tile">
  341. <h4>${ _('Tables') }</h4>
  342. <div class="actionbar-actions" data-bind="visible: tables().length > 0">
  343. <input class="input-xlarge search-query margin-left-10" type="text" placeholder="${ _('Search for a table...') }" data-bind="clearable: tableQuery, value: tableQuery, valueUpdate: 'afterkeydown'"/>
  344. <button class="btn toolbarBtn margin-left-20" title="${_('Browse the selected table')}" data-bind="click: function () { setTable(selectedTables()[0]); selectedTables([]); }, disable: selectedTables().length !== 1"><i class="fa fa-eye"></i> ${_('View')}</button>
  345. <button class="btn toolbarBtn" title="${_('Browse the selected table')}" data-bind="click: function () { location.href = '/notebook/browse/' + name + '/' + selectedTables()[0].name; }, disable: selectedTables().length !== 1">
  346. <i class="fa fa-list"></i> ${_('Browse Data')}
  347. </button>
  348. % if has_write_access:
  349. <button id="dropBtn" class="btn toolbarBtn" title="${_('Delete the selected tables')}" data-bind="click: function () { $('#dropTable').modal('show'); }, disable: selectedTables().length === 0"><i class="fa fa-times"></i> ${_('Drop')}</button>
  350. <div id="dropTable" class="modal hide fade">
  351. <form data-bind="attr: { 'action': '/metastore/tables/drop/' + name }" method="POST">
  352. ${ csrf_token(request) | n,unicode }
  353. <div class="modal-header">
  354. <a href="#" class="close" data-dismiss="modal">&times;</a>
  355. <h3 id="dropTableMessage">${_('Do you really want to drop the selected table(s)?')}</h3>
  356. </div>
  357. <div class="modal-footer">
  358. <input type="button" class="btn" data-dismiss="modal" value="${_('Cancel')}" />
  359. <input type="submit" data-bind="click: function () { huePubSub.publish('assist.refresh'); selectedTables([]); return true; }" class="btn btn-danger" value="${_('Yes')}"/>
  360. </div>
  361. <!-- ko foreach: selectedTables -->
  362. <input type="hidden" name="table_selection" data-bind="value: name" />
  363. <!-- /ko -->
  364. </form>
  365. </div>
  366. % endif
  367. </div>
  368. <table id="tablesTable" class="table table-striped table-condensed table-nowrap" style="margin-bottom: 10px; width: 100%" data-bind="visible: filteredTables().length > 0">
  369. <thead>
  370. <tr>
  371. <th width="1%" style="text-align: center"><div class="hueCheckbox fa" data-bind="hueCheckAll: { allValues: filteredTables, selectedValues: selectedTables }"></div></th>
  372. <th>&nbsp;</th>
  373. <th>${ _('Table Name') }</th>
  374. <th width="50%">${ _('Comment') }</th>
  375. <th width="1%">${ _('Type') }</th>
  376. </tr>
  377. </thead>
  378. <tbody data-bind="hueach: {data: filteredTables, itemHeight: 29, scrollable: '.right-panel', scrollableOffset: 277}">
  379. <tr>
  380. <td width="1%" style="text-align: center">
  381. <div class="hueCheckbox fa" data-bind="multiCheck: '#tablesTable', value: $data, hueChecked: $parent.selectedTables"></div>
  382. </td>
  383. <td width="1%"><span class="blue" data-bind="component: { name: 'table-stats', params: {
  384. alwaysActive: true,
  385. statsVisible: true,
  386. sourceType: 'hive',
  387. databaseName: database.name,
  388. tableName: name,
  389. fieldType: type,
  390. assistHelper: assistHelper
  391. } }"></span></td>
  392. <td>
  393. <a class="tableLink" href="javascript:void(0);" data-bind="text: name, click: function() { $parent.setTable($data, function(){ huePubSub.publish('metastore.url.change'); }) }"></a>
  394. </td>
  395. <td data-bind="text: comment"></td>
  396. <td class="center">
  397. <!-- ko if: type == 'Table' -->
  398. <i class="fa fa-fw fa-table muted" title="${ _('Table') }"></i>
  399. <!-- /ko -->
  400. <!-- ko if: type == 'View' -->
  401. <i class="fa fa-fw fa-eye muted" title="${ _('View') }"></i>
  402. <!-- /ko -->
  403. </td>
  404. </tr>
  405. </tbody>
  406. </table>
  407. <span data-bind="visible: filteredTables().length === 0, css: {'margin-left-10': tables().length > 0}" style="font-style: italic; display: none;">${_('No tables found.')}</span>
  408. </div>
  409. </div>
  410. </script>
  411. <script type="text/html" id="metastore-databases-parameters">
  412. <div data-bind="toggleOverflow: {height: 24}">
  413. <div class="inline margin-right-20"><i class="fa fa-fw fa-cog muted"></i></div>
  414. <!-- ko foreach: Object.keys($data) -->
  415. <div class="inline margin-right-20"><strong data-bind="text: $data"></strong>: <span data-bind="text: $parent[$data]"></span></div>
  416. <!-- /ko -->
  417. </div>
  418. </script>
  419. <script type="text/html" id="metastore-databases-actions">
  420. <div class="inline-block pull-right">
  421. <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.refresh'); }"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : $root.reloading }" title="${_('Refresh')}"></i></a>
  422. % if has_write_access:
  423. <a class="inactive-action margin-left-10" href="${ url('beeswax:create_database') }" title="${_('Create a new database')}"><i class="fa fa-plus-circle"></i></a>
  424. % endif
  425. </div>
  426. </script>
  427. <script type="text/html" id="metastore-tables-actions">
  428. <div class="inline-block pull-right">
  429. <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.refresh'); }"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : $root.reloading }" title="${_('Refresh')}"></i></a>
  430. % if has_write_access:
  431. <a class="inactive-action margin-left-10" data-bind="attr: { 'href': '/beeswax/create/import_wizard/' + database().name }" title="${_('Create a new table from a file')}"><i class="fa fa-files-o"></i></a>
  432. <a class="inactive-action margin-left-10" data-bind="attr: { 'href': '/beeswax/create/create_table/' + database().name }" title="${_('Create a new table manually')}"><i class="fa fa-wrench"></i></a>
  433. % endif
  434. </div>
  435. </script>
  436. <script type="text/html" id="metastore-describe-table-actions">
  437. <div class="inline-block pull-right">
  438. <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.refresh'); }"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : $root.reloading }" title="${_('Refresh')}"></i></a>
  439. <!-- ko with: database -->
  440. <!-- ko with: table -->
  441. <a class="inactive-action margin-left-10" href="javascript: void(0);"><i class="fa fa-star"></i></a>
  442. <a class="inactive-action margin-left-10" href="#" data-bind="click: showImportData" title="${_('Import Data')}"><i class="fa fa-upload"></i></a>
  443. <a class="inactive-action margin-left-10" data-bind="attr: { 'href': '/notebook/browse/' + database.name + '/' + name }" title="${_('Browse Data')}"><i class="fa fa-list"></i></a>
  444. % if has_write_access:
  445. <a class="inactive-action margin-left-10" href="#dropSingleTable" data-toggle="modal" data-bind="attr: { 'title' : tableDetails() && tableDetails().is_view ? '${_('Drop View')}' : '${_('Drop Table')}' }"><i class="fa fa-times"></i></a>
  446. % endif
  447. <!-- ko if: tableDetails() -->
  448. <a class="inactive-action margin-left-10" data-bind="visible: tableDetails().hdfs_link, attr: {'href': tableDetails().hdfs_link, 'rel': tableDetails().path_location}" title="${_('View File Location')}"><i class="fa fa-fw fa-hdd-o"></i></a>
  449. <!-- ko if: tableDetails().partition_keys.length -->
  450. <a class="inactive-action margin-left-10" data-bind="attr: { 'href': '/metastore/table/' + database.name + '/' + name + '/partitions' }" title="${_('Show Partitions')}"><i class="fa fa-sitemap"></i></a>
  451. <!-- /ko -->
  452. <!-- /ko -->
  453. <!-- /ko -->
  454. <!-- /ko -->
  455. </div>
  456. </script>
  457. <script type="text/html" id="metastore-overview-tab">
  458. <div class="row-fluid margin-top-10">
  459. <div class="span3 tile">
  460. <!-- ko template: 'metastore-table-properties' --><!-- /ko -->
  461. </div>
  462. <div class="span3 tile">
  463. <!-- ko template: 'metastore-table-stats' --><!-- /ko -->
  464. </div>
  465. <div class="span6 tile">
  466. <h4>${ _('Tagging') }</h4>
  467. <div title="${ _('Tags') }"><i class="fa fa-fw fa-tags muted"></i> ${ _('No tags') }</div>
  468. </div>
  469. </div>
  470. <div class="tile">
  471. <h4>${ _('Columns') } (<span data-bind="text: columns().length"></span>)</h4>
  472. <!-- ko with: favouriteColumns -->
  473. <!-- ko template: "metastore-columns-table" --><!-- /ko -->
  474. <!-- /ko -->
  475. <a class="pointer" data-bind="visible: columns().length >= 3, click: function() { $('li a[href=\'#columns\']').click(); }">
  476. ${_('View more...')}
  477. </a>
  478. </div>
  479. <div class="tile">
  480. <h4>${ _('Sample') } <i data-bind="visible: samples.loading" class='fa fa-spinner fa-spin' style="display: none;"></i></h4>
  481. <!-- ko with: samples -->
  482. <!-- ko if: loaded -->
  483. <!-- ko with: preview -->
  484. <!-- ko template: { if: rows().length, name: 'metastore-samples-table' } --><!-- /ko -->
  485. <a class="pointer" data-bind="visible: rows().length >= 3, click: function() { $('li a[href=\'#sample\']').click(); }" style="display: none;">
  486. ${_('View more...')}
  487. </a>
  488. <!-- /ko -->
  489. <div data-bind="visible: !rows().length && metastoreTable.tableDetails().is_view" style="display: none;">${ _('The view does not contain any data.') }</div>
  490. <div data-bind="visible: !rows().length && !metastoreTable.tableDetails().is_view" style="display: none;">${ _('The table does not contain any data.') }</div>
  491. <!-- /ko -->
  492. <!-- /ko -->
  493. </div>
  494. <div class="tile" data-bind="visible: tableDetails() && tableDetails().partition_keys.length" style="display: none;">
  495. <!-- ko with: partitions -->
  496. <h4>${ _('Partitions') } <i data-bind="visible: loading" class='fa fa-spinner fa-spin' style="display: none;"></i></h4>
  497. <!-- ko if: loaded -->
  498. <!-- ko with: preview -->
  499. <!-- ko template: { if: values().length, name: 'metastore-partition-values-table' } --><!-- /ko -->
  500. <a class="pointer" data-bind="visible: values().length >= 3, click: function() { $('li a[href=\'#partitions\']').click(); }" style="display: none;">
  501. ${_('View more...')}
  502. </a>
  503. <!-- /ko -->
  504. <span data-bind="visible: !values().length" style="display: none;">${ _('The partition does not contain any values') }</span>
  505. <!-- /ko -->
  506. <!-- /ko -->
  507. </div>
  508. </script>
  509. <script type="text/html" id="metastore-columns-tab">
  510. <!-- ko with: columns -->
  511. <!-- ko template: "metastore-columns-table" --><!-- /ko -->
  512. <!-- /ko -->
  513. </script>
  514. <script type="text/html" id="metastore-partitions-tab">
  515. <!-- ko with: partitions -->
  516. <div class="tile" data-bind="visible: true" style="display: none;">
  517. <h4>${ _('Columns') }</h4>
  518. <!-- ko template: 'metastore-partition-columns-table' --><!-- /ko -->
  519. </div>
  520. <div class="tile" data-bind="visible: true" style="display: none;">
  521. <h4>${ _('Partitions') } <i data-bind="visible: loading" class='fa fa-spinner fa-spin' style="display: none;"></i></h4>
  522. <!-- ko if: loaded -->
  523. <!-- ko template: { if: values().length, name: 'metastore-partition-values-table' } --><!-- /ko -->
  524. <span data-bind="visible: !values().length" style="display: none;">${ _('The partition does not contain any values') }</span>
  525. <!-- /ko -->
  526. </div>
  527. <!-- /ko -->
  528. <a data-bind="attr: { 'href': '/metastore/table/' + database.name + '/' + name + '/partitions' }">${ _('View all') }</a>
  529. </script>
  530. <script type="text/html" id="metastore-sample-tab">
  531. <!-- ko with: samples -->
  532. <!-- ko if: loading -->
  533. <div class="empty-message">
  534. <i data-bind="visible: loading" class='fa fa-spinner fa-spin' style="display: none;"></i>
  535. </div>
  536. <!-- /ko -->
  537. <!-- ko if: loaded -->
  538. <!-- ko template: { if: rows().length, name: 'metastore-samples-table' } --><!-- /ko -->
  539. <div data-bind="visible: !rows().length && metastoreTable.tableDetails().is_view" style="display: none;" class="empty-message">${ _('The view does not contain any data.') }</div>
  540. <div data-bind="visible: !rows().length && !metastoreTable.tableDetails().is_view" style="display: none;" class="empty-message">${ _('The table does not contain any data.') }</div>
  541. <!-- /ko -->
  542. <!-- /ko -->
  543. </script>
  544. <script type="text/html" id="metastore-queries-tab">
  545. <i class="fa fa-spinner fa-spin" data-bind="visible: $root.loadingQueries"></i>
  546. <table data-bind="visible: !$root.loadingQueries() && $root.queries().length > 0" class="table table-condensed">
  547. <thead>
  548. <tr>
  549. <th width="20%">${ _('Name') }</th>
  550. <th>${ _('Query') }</th>
  551. <th width="20%">${ _('Owner') }</th>
  552. </tr>
  553. </thead>
  554. <tbody data-bind="hueach: {data: $root.queries, itemHeight: 29, scrollable: '.right-panel', scrollableOffset: 200}">
  555. <tr class="pointer" data-bind="click: function(){ location.href=doc.absoluteUrl; }">
  556. <td data-bind="text: doc.name"></td>
  557. <td><code data-bind="text: data.snippets[0].statement_raw"></code></td>
  558. <td><code data-bind="text: doc.owner"></code></td>
  559. </tr>
  560. </tbody>
  561. </table>
  562. <div data-bind="visible: !$root.loadingQueries() && $root.queries().length == 0" class="empty-message">
  563. ${ _('No queries found for the current table.') }
  564. </div>
  565. </script>
  566. <script type="text/html" id="metastore-details-tab">
  567. <!-- ko with: tableDetails -->
  568. <table class="properties-table">
  569. <tbody data-bind="foreach: properties">
  570. <!-- ko if: col_name.indexOf('#') === 0 -->
  571. <tr>
  572. <td colspan="3"><h4 data-bind="text: col_name.substring(1)"></h4></td>
  573. </tr>
  574. <!-- /ko -->
  575. <!-- ko ifnot: col_name.indexOf('#') === 0 -->
  576. <tr>
  577. <td class="property-name" data-bind="text: col_name || '&nbsp;'"></td>
  578. <td data-bind="text: data_type || '&nbsp;'"></td>
  579. <td data-bind="text: comment || '&nbsp;'"></td>
  580. </tr>
  581. <!-- /ko -->
  582. </tbody>
  583. </table>
  584. <!-- /ko -->
  585. </script>
  586. <script type="text/html" id="metastore-describe-table">
  587. <div class="clearfix"></div>
  588. <span data-bind="editable: comment, editableOptions: {enabled: true, placement: 'right', emptytext: '${ _ko('Add a description...') }' }" class="editable editable-click editable-empty">
  589. ${ _('Add a description...') }
  590. </span>
  591. <ul class="nav nav-pills margin-top-30">
  592. <li><a href="#overview" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-overview'); }">${_('Overview')}</a></li>
  593. <li><a href="#columns" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-columns'); }">${_('Columns')} (<span data-bind="text: columns().length"></span>)</a></li>
  594. <!-- ko if: tableDetails() && tableDetails().partition_keys.length -->
  595. <li><a href="#partitions" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-partitions'); }">${_('Partitions')} <span data-bind="text: '(' + partitions.values().length + ')'"></span></a></li>
  596. <!-- /ko -->
  597. <li><a href="#sample" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-sample'); }">${_('Sample')}</a></li>
  598. <li><a href="#permissions" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-permissions'); }">${_('Permissions')}</a></li>
  599. <li><a href="#queries" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-queries'); }">${_('Queries')}</a></li>
  600. <li><a href="#analysis" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-analysis'); }">${_('Analyze')}</a></li>
  601. <li><a href="#lineage" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-lineage'); }">${_('Lineage')}</a></li>
  602. <li><a href="#details" data-toggle="tab" data-bind="click: function(){ $root.currentTab('table-details'); }">${ _('Details') }</a></li>
  603. </ul>
  604. <div class="tab-content margin-top-10" style="border: none">
  605. <div class="tab-pane" id="overview">
  606. <!-- ko if: $root.currentTab() == 'table-overview' -->
  607. <!-- ko template: 'metastore-overview-tab' --><!-- /ko -->
  608. <!-- /ko -->
  609. </div>
  610. <div class="tab-pane" id="columns">
  611. <!-- ko if: $root.currentTab() == 'table-columns' -->
  612. <!-- ko template: 'metastore-columns-tab' --><!-- /ko -->
  613. <!-- /ko -->
  614. </div>
  615. <div class="tab-pane" id="partitions">
  616. <!-- ko if: $root.currentTab() == 'table-partitions' -->
  617. <!-- ko template: 'metastore-partitions-tab' --><!-- /ko -->
  618. <!-- /ko -->
  619. </div>
  620. <div class="tab-pane" id="sample">
  621. <!-- ko if: $root.currentTab() == 'table-sample' -->
  622. <!-- ko template: 'metastore-sample-tab' --><!-- /ko -->
  623. <!-- /ko -->
  624. </div>
  625. <div class="tab-pane" id="permissions">
  626. <div class="empty-message">${ _('Currently not available.') }</div>
  627. </div>
  628. <div class="tab-pane" id="queries">
  629. <!-- ko if: $root.currentTab() == 'table-queries' -->
  630. <!-- ko template: 'metastore-queries-tab' --><!-- /ko -->
  631. <!-- /ko -->
  632. </div>
  633. <div class="tab-pane" id="analysis">
  634. <div class="empty-message">${ _('Currently not available.') }</div>
  635. </div>
  636. <div class="tab-pane" id="lineage">
  637. <div class="empty-message">${ _('Currently not available.') }</div>
  638. </div>
  639. <div class="tab-pane" id="details">
  640. <!-- ko if: $root.currentTab() == 'table-details' -->
  641. <!-- ko template: 'metastore-details-tab' --><!-- /ko -->
  642. <!-- /ko -->
  643. </div>
  644. </div>
  645. </script>
  646. <div class="main-content">
  647. <div class="vertical-full container-fluid" data-bind="style: { 'padding-left' : $root.isLeftPanelVisible() ? '0' : '20px' }">
  648. <div class="vertical-full row-fluid panel-container">
  649. <div class="assist-container left-panel" data-bind="visible: $root.isLeftPanelVisible() && $root.assistAvailable()">
  650. <a title="${_('Toggle Assist')}" class="pointer hide-assist" data-bind="click: function() { $root.isLeftPanelVisible(false) }">
  651. <i class="fa fa-chevron-left"></i>
  652. </a>
  653. <div class="assist" data-bind="component: {
  654. name: 'assist-panel',
  655. params: {
  656. user: '${user.username}',
  657. sql: {
  658. sourceTypes: [{
  659. name: 'hive',
  660. type: 'hive'
  661. }],
  662. navigationSettings: {
  663. openItem: true,
  664. showPreview: true,
  665. showStats: false
  666. }
  667. },
  668. visibleAssistPanels: ['sql']
  669. }
  670. }"></div>
  671. </div>
  672. <div class="resizer" data-bind="visible: $root.isLeftPanelVisible() && $root.assistAvailable(), splitDraggable : { appName: 'notebook', leftPanelVisible: $root.isLeftPanelVisible }"><div class="resize-bar">&nbsp;</div></div>
  673. <div class="right-panel">
  674. <div class="metastore-main">
  675. <h3>
  676. <!-- ko template: { if: database() !== null && database().table() !== null, name: 'metastore-describe-table-actions' }--><!-- /ko -->
  677. <!-- ko template: { if: database() !== null && database().table() === null, name: 'metastore-tables-actions' }--><!-- /ko -->
  678. <!-- ko template: { if: database() === null, name: 'metastore-databases-actions' }--><!-- /ko -->
  679. <!-- ko template: 'metastore-breadcrumbs' --><!-- /ko -->
  680. </h3>
  681. <i data-bind="visible: loading" class="fa fa-spinner fa-spin fa-2x margin-left-10" style="color: #999; display: none;"></i>
  682. <!-- ko template: { if: !loading() && database() === null, name: 'metastore-databases' } --><!-- /ko -->
  683. <!-- ko with: database -->
  684. <i data-bind="visible: loading" class="fa fa-spinner fa-spin fa-2x margin-left-10" style="color: #999; display: none;"></i>
  685. <!-- ko template: { if: !loading() && table() === null, name: 'metastore-tables' } --><!-- /ko -->
  686. <!-- ko with: table -->
  687. <!-- ko template: 'metastore-describe-table' --><!-- /ko -->
  688. <!-- /ko -->
  689. <!-- /ko -->
  690. </div>
  691. </div>
  692. </div>
  693. </div>
  694. <div id="dropSingleTable" class="modal hide fade">
  695. <form method="POST">
  696. ${ csrf_token(request) | n,unicode }
  697. <div class="modal-header">
  698. <a href="#" class="close" data-dismiss="modal">&times;</a>
  699. <h3>${_('Drop Table')}</h3>
  700. </div>
  701. <div class="modal-body">
  702. <div>${_('Do you really want to drop the table')} <span style="font-weight: bold;" data-bind="text: database() && database().table() ? database().table().name : ''"></span>?</div>
  703. </div>
  704. <div class="modal-footer">
  705. <input type="hidden" name="table_selection" data-bind="value: database() && database().table() ? database().table().name : ''" />
  706. <input type="button" class="btn" data-dismiss="modal" value="${_('Cancel')}"/>
  707. <input type="submit" data-bind="click: function (vm, e) { var $form = $(e.target).parents('form'); $form.attr('action', '/metastore/tables/drop/' + vm.database().name); return true; }" class="btn btn-danger" value="${_('Yes, drop this table')}"/>
  708. </div>
  709. </form>
  710. </div>
  711. <div id="import-data-modal" class="modal hide fade"></div>
  712. </div>
  713. <script type="text/javascript" charset="utf-8">
  714. require([
  715. 'knockout',
  716. 'metastore/js/metastore.ko',
  717. 'ko.charts',
  718. 'assistPanel',
  719. 'tableStats',
  720. 'knockout-mapping',
  721. 'knockout-sortable',
  722. 'ko.editable',
  723. 'ko.hue-bindings'
  724. ], function (ko, MetastoreViewModel) {
  725. ko.options.deferUpdates = true;
  726. $(document).ready(function () {
  727. var options = {
  728. user: '${ user.username }',
  729. i18n: {
  730. errorFetchingTableDetails: '${_('An error occurred fetching the table details. Please try again.')}',
  731. errorFetchingTableFields: '${_('An error occurred fetching the table fields. Please try again.')}',
  732. errorFetchingTableSample: '${_('An error occurred fetching the table sample. Please try again.')}',
  733. errorRefreshingTableStats: '${_('An error occurred refreshing the table stats. Please try again.')}',
  734. errorLoadingDatabases: '${ _('There was a problem loading the databases. Please try again.') }',
  735. errorLoadingTablePreview: '${ _('There was a problem loading the table preview. Please try again.') }'
  736. }
  737. };
  738. var viewModel = new MetastoreViewModel(options);
  739. ko.applyBindings(viewModel);
  740. if (location.getParameter('refresh') === 'true') {
  741. huePubSub.publish('assist.refresh');
  742. hueUtils.replaceURL('?');
  743. }
  744. // TODO: Use ko for this and the put the queries in the MetastoreTable
  745. $('a[data-toggle="tab"]').on('shown', function (e) {
  746. if ($(e.target).attr("href") == "#queries") {
  747. viewModel.loadingQueries(true);
  748. $.getJSON('/metastore/table/' + viewModel.database().name + '/' + viewModel.database().table().name + '/queries', function (data) {
  749. viewModel.queries(data.queries);
  750. viewModel.loadingQueries(false);
  751. });
  752. }
  753. });
  754. });
  755. });
  756. </script>
  757. ${ commonfooter(request, messages) | n,unicode }