listdir_components.mako 99 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533
  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. import datetime
  18. from django.template.defaultfilters import urlencode, stringformat, filesizeformat, date, time, escape
  19. from desktop.lib.django_util import reverse_with_get, extract_field_data
  20. from django.utils.encoding import smart_str
  21. from django.utils.translation import ugettext as _
  22. from filebrowser.conf import ENABLE_EXTRACT_UPLOADED_ARCHIVE
  23. %>
  24. <%namespace name="edit" file="editor_components.mako" />
  25. <%def name="list_table_chooser(files, path, current_request_path)">
  26. ${_table(files, path, current_request_path, 'chooser')}
  27. </%def>
  28. <%def name="list_table_browser(files, path, current_request_path, show_download_button, cwd_set=True)">
  29. ${_table(files, path, current_request_path, 'view', show_download_button)}
  30. </%def>
  31. <%def name="_table(files, path, current_request_path, view, show_download_button)">
  32. <link href="${ static('filebrowser/css/listdir_components.css') }" rel="stylesheet" type="text/css">
  33. <div data-bind="visible: isLoading">
  34. <i class="fa fa-spinner fa-spin hue-spinner-large hue-spinner-center muted"></i>
  35. </div>
  36. <table id="fileBrowserTable" class="table table-condensed table-huedatatable tablescroller-disable" data-bind="style: {'opacity': isLoading() ? '.5': '1'}">
  37. <thead>
  38. <tr>
  39. <th class="sorting_disabled" width="1%"><div data-bind="click: selectAll, css: { 'hue-checkbox': true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
  40. <th class="sortable sorting" data-sort="type" width="1%" data-bind="click: sort">&nbsp;</th>
  41. <th class="sortable sorting_asc" data-sort="name" data-bind="click: sort">${_('Name')}</th>
  42. <th class="sortable sorting" data-sort="size" width="10%" data-bind="click: sort">${_('Size')}</th>
  43. <th class="sortable sorting" data-sort="user" width="10%" data-bind="click: sort">${_('User')}</th>
  44. <th class="sortable sorting" data-sort="group" width="10%" data-bind="click: sort">${_('Group')}</th>
  45. <th class="sorting_disabled" width="10%">${_('Permissions')}</th>
  46. <th class="sortable sorting" data-sort="mtime" width="15%" data-bind="click: sort">${_('Date')}</th>
  47. </tr>
  48. </thead>
  49. <tbody id="files" data-bind="template: {name: 'fileTemplate', foreach: files}"></tbody>
  50. <tfoot>
  51. <tr data-bind="visible: files().length === 0 && !isLoading()">
  52. <td colspan="8">
  53. <div class="alert">
  54. ${_('There are no files matching the search criteria.')}
  55. </div>
  56. </td>
  57. </tr>
  58. </tfoot>
  59. </table>
  60. <div class="pagination">
  61. <div class="pull-right">
  62. <div class="form-inline pagination-input-form inline">
  63. <span>${_('Page')}</span>
  64. <input type="text" data-bind="value: page().number, valueUpdate: 'afterkeydown', event: { change: skipTo }" class="pagination-input" />
  65. <input type="hidden" id="current_page" data-bind="value: page().number" />
  66. ${_('of')} <span data-bind="text: page().num_pages"></span>
  67. </div>
  68. <ul class="inline">
  69. <li class="first-page prev" data-bind="css: { 'disabled': (page().number === page().start_index || page().num_pages <= 1) }">
  70. <a href="javascript:void(0);" data-bind="click: firstPage" title="${_('First page')}"><i class="fa fa-fast-backward"></i></a>
  71. </li>
  72. <li class="previous-page" data-bind="css: { 'disabled': (page().number === page().start_index || page().num_pages <= 1) }">
  73. <a href="javascript:void(0);" data-bind="click: previousPage" title="${_('Previous page')}"><i class="fa fa-backward"></i></a>
  74. </li>
  75. <li class="next-page" data-bind="css: { 'disabled': page().number === page().num_pages }">
  76. <a href="javascript:void(0);" data-bind="click: nextPage" title="${_('Next page')}"><i class="fa fa-forward"></i></a>
  77. </li>
  78. <li class="last-page next" data-bind="css: { 'disabled': page().number === page().num_pages }">
  79. <a href="javascript:void(0);" data-bind="click: lastPage" title="${_('Last page')}"><i class="fa fa-fast-forward"></i></a>
  80. </li>
  81. </ul>
  82. </div>
  83. <p>${_('Show')}
  84. <select class="input-mini" data-bind="options: recordsPerPageChoices, value: recordsPerPage"></select>
  85. ${_('of')} <span data-bind="text: page().total_count"></span> ${_('items')}
  86. </p>
  87. </div>
  88. <!-- extract modal -->
  89. <div id="confirmExtractModal" class="modal hide fade">
  90. <div class="modal-header">
  91. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  92. <h2 class="modal-title">${ _('Extract Archive') }</h2>
  93. </div>
  94. <!-- ko if: selectedFile -->
  95. <div class="modal-body">
  96. <p>${_('Start a task to extract the contents of this archive.')}</p>
  97. <ul>
  98. <li>
  99. <span data-bind="text: selectedFile().name"> </span>
  100. </li>
  101. </ul>
  102. </div>
  103. <div class="modal-footer">
  104. <a class="btn" data-dismiss="modal">${_('No')}</a>
  105. <input type="submit" value="${_('Yes')}" class="btn btn-primary" data-bind="click: extractSelectedArchive"/>
  106. </div>
  107. <!-- /ko -->
  108. </div>
  109. <!-- compress modal -->
  110. <div id="confirmCompressModal" class="modal hide fade">
  111. <div class="modal-header">
  112. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  113. <h2 class="modal-title">${ _('Compress Files') }</h2>
  114. </div>
  115. <!-- ko if: selectedFiles -->
  116. <div class="modal-body">
  117. <div class="form-inline">
  118. <label>${_('Archive Name')} <input data-bind="textInput: compressArchiveName" type="text" class="margin-left-5 input-xlarge"></label>
  119. <p class="margin-top-20">${_('Start a task to compress the selected file(s) and/or folder(s)')}</p>
  120. <ul data-bind="foreach: selectedFiles()">
  121. <li>
  122. <i data-bind="css: { 'fa fa-fw muted': true, 'fa-file-o': type == 'file', 'fa-folder-o': type != 'file' }"></i>
  123. <span data-bind="text: $data.name"> </span>
  124. </li>
  125. </ul>
  126. </div>
  127. </div>
  128. <div class="modal-footer">
  129. <a class="btn" data-dismiss="modal">${_('Cancel')}</a>
  130. <input type="submit" value="${_('Compress')}" class="btn btn-primary" data-bind="click: archiveOverrideWarning, enable: compressArchiveName().length > 0"/>
  131. </div>
  132. <!-- /ko -->
  133. </div>
  134. <!-- compress warning modal -->
  135. <div id="compressWarningModal" class="modal hide fade">
  136. <div class="modal-header">
  137. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  138. <h2 class="modal-title">${ _('Are you sure you want to override the existing archive?') }</h2>
  139. </div>
  140. <!-- ko if: compressArchiveName -->
  141. <div class="modal-body">
  142. <ul>
  143. <li>
  144. <span data-bind="text: compressArchiveName"> </span>
  145. </li>
  146. </ul>
  147. </div>
  148. <div class="modal-footer">
  149. <a class="btn" data-dismiss="modal" data-bind="click: confirmCompressFiles">${_('No')}</a>
  150. <input type="submit" value="${_('Yes')}" class="btn btn-danger" data-bind="click: compressSelectedFiles"/>
  151. </div>
  152. <!-- /ko -->
  153. </div>
  154. <!-- delete modal -->
  155. <div id="deleteModal" class="modal hide fade">
  156. <div class="modal-header">
  157. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  158. <h2 class="modal-title">${ _('Confirm Delete') }</h2>
  159. </div>
  160. <div class="modal-body">
  161. <!-- ko if: isS3() && isS3Root() -->
  162. <p>${_('Are you sure you want to delete these buckets?')}</p>
  163. <p class="muted">${_('Deleting a bucket will delete all of its contents and release the bucket name to be reserved by others.')}</p>
  164. <!-- /ko -->
  165. <!-- ko ifnot: isS3() && isS3Root() -->
  166. <!-- ko ifnot: $root.skipTrash -->
  167. <p>${_('Are you sure you want to delete these files?')}</p>
  168. <!-- /ko -->
  169. <!-- ko if: $root.skipTrash -->
  170. <p>${_('Are you sure you want to permanently delete these files?')}</p>
  171. <!-- /ko -->
  172. <ul data-bind="foreach: $root.selectedFiles">
  173. <li data-bind="visible: $index() <= 10">
  174. <span data-bind="text: name"></span>
  175. </li>
  176. </ul>
  177. <!-- ko if: $root.selectedFiles().length > 10 -->
  178. ${_('and')} <span data-bind="text: $root.selectedFiles().length - 10"></span> ${_('others')}.
  179. <!-- /ko -->
  180. <!-- /ko -->
  181. </div>
  182. <div class="modal-footer">
  183. <form id="deleteForm" action="/filebrowser/rmtree" method="POST" enctype="multipart/form-data" class="form-stacked">
  184. ${ csrf_token(request) | n,unicode }
  185. <a class="btn" data-dismiss="modal">${_('No')}</a>
  186. <input type="submit" value="${_('Yes')}" class="btn btn-danger" />
  187. </form>
  188. </div>
  189. </div>
  190. <!-- restore modal -->
  191. <div id="restoreTrashModal" class="modal hide fade">
  192. <div class="modal-header">
  193. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  194. <h2 class="modal-title">${ _('Confirm Restore') }</h2>
  195. </div>
  196. <div class="modal-body">
  197. <p>${_('Are you sure you want to restore these files?')}</p>
  198. </div>
  199. <div class="modal-footer">
  200. <form id="restoreTrashForm" action="/filebrowser/trash/restore" method="POST" enctype="multipart/form-data" class="form-stacked">
  201. ${ csrf_token(request) | n,unicode }
  202. <a class="btn" data-dismiss="modal">${_('No')}</a>
  203. <input type="submit" value="${_('Yes')}" class="btn btn-primary" />
  204. </form>
  205. </div>
  206. </div>
  207. <!-- purge modal -->
  208. <div id="purgeTrashModal" class="modal hide fade">
  209. <div class="modal-header">
  210. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  211. <h2 class="modal-title">${ _('Confirm empty trash') }</h2>
  212. </div>
  213. <div class="modal-body">
  214. <p>${_('Are you sure you want to permanently delete all your trash?')}</p>
  215. </div>
  216. <div class="modal-footer">
  217. <form id="purgeTrashForm" action="/filebrowser/trash/purge" method="POST" enctype="multipart/form-data" class="form-stacked">
  218. ${ csrf_token(request) | n,unicode }
  219. <a class="btn" data-dismiss="modal">${_('Cancel')}</a>
  220. <input type="submit" value="${_('Delete all')}" class="btn btn-danger" />
  221. </form>
  222. </div>
  223. </div>
  224. <!-- rename modal -->
  225. <form id="renameForm" action="/filebrowser/rename?next=${current_request_path | n,unicode }" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  226. ${ csrf_token(request) | n,unicode }
  227. <div id="renameModal" class="modal hide fade">
  228. <div class="modal-header">
  229. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  230. <h2 class="modal-title">${_('Renaming:')} <span id="renameFileName">file name</span></h2>
  231. </div>
  232. <div class="modal-body">
  233. <label>${_('New name')} <input id="newNameInput" name="dest_path" value="" type="text" class="input-xlarge"/></label>
  234. </div>
  235. <div class="modal-footer">
  236. <div id="renameNameRequiredAlert" class="hide" style="position: absolute; left: 10px;">
  237. <span class="label label-important">${_('Name is required.')}</span>
  238. </div>
  239. <div id="renameNameExistsAlert" class="hide" style="position: absolute; left: 10px;">
  240. <span class="label label-important"><span class="newName"></span> ${_('already exists.')}</span>
  241. </div>
  242. <input id="renameSrcPath" type="hidden" name="src_path">
  243. <a class="btn" data-dismiss="modal">${_('Cancel')}</a>
  244. <input type="submit" value="${_('Rename')}" class="btn btn-primary" />
  245. </div>
  246. </div>
  247. </form>
  248. <!-- set replication factor modal -->
  249. <form id="setReplicationFactorForm" action="/filebrowser/set_replication?next=${current_request_path | n,unicode }" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  250. ${ csrf_token(request) | n,unicode }
  251. <div id="setReplicationModal" class="modal hide fade">
  252. <div class="modal-header">
  253. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  254. <h2 class="modal-title">${_('Setting replication factor for :')} <span id="setReplFileName">file name</span></h2>
  255. </div>
  256. <div class="modal-body">
  257. <label>${_('Replication factor')} <input id="newRepFactorInput" name="replication_factor" value="" type="number" class="input-mini"/></label>
  258. </div>
  259. <div class="modal-footer">
  260. <div id="replicationFactorRequiredAlert" class="hide" style="position: absolute; left: 10px;">
  261. <span class="label label-important">${_('Replication factor is required.')}</span>
  262. </div>
  263. <input id="SrcPath" type="hidden" name="src_path">
  264. <a class="btn" data-dismiss="modal">${_('Cancel')}</a>
  265. <input type="submit" value="${_('Submit')}" class="btn btn-primary" />
  266. </div>
  267. </div>
  268. </form>
  269. <!-- chown modal -->
  270. % if is_fs_superuser:
  271. <form id="chownForm" action="/filebrowser/chown" method="POST" enctype="multipart/form-data" class="form-stacked form-padding-fix">
  272. ${ csrf_token(request) | n,unicode }
  273. <div id="changeOwnerModal" class="modal hide fade">
  274. <%
  275. select_filter = is_fs_superuser and 'SelectWithOther' or ''
  276. %>
  277. <div class="modal-header">
  278. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  279. <h2 class="modal-title">${_('Change Owner/Group')}</h2>
  280. </div>
  281. <div class="modal-body change-owner-modal-body clearfix" >
  282. <div class="alert alert-message block-message info">${_('Note: Only the Hadoop superuser, "%(superuser)s" or the HDFS supergroup, "%(supergroup)s" on this file system, may change the owner of a file.') % dict(superuser=superuser, supergroup=supergroup)}</div>
  283. <div style="padding-left: 15px; padding-bottom: 10px;">
  284. <label>${_('User')}</label>
  285. ${ edit.selection("user", users, user.username, "user_other") }
  286. <label>${_('Group')}</label>
  287. ${ edit.selection("group", groups, 'supergroup', "group_other") }
  288. <br />
  289. <label style="display: inline;">${_('Recursive')}</label> <input type="checkbox" name="recursive" style="margin-bottom:4px">
  290. </div>
  291. </div>
  292. <div class="modal-footer" style="padding-top: 10px;">
  293. <div id="chownRequired" class="hide" style="position: absolute; left: 10px;">
  294. <span class="label label-important">${_('Name is required.')}</span>
  295. </div>
  296. <a class="btn" onclick="$('#changeOwnerModal').modal('hide');">${_('Cancel')}</a>
  297. <input class="btn btn-primary" type="submit" value="${_('Submit')}" />
  298. </div>
  299. </div>
  300. </form>
  301. % endif
  302. <!-- chmod modal -->
  303. <form action="/filebrowser/chmod" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix" id="chmodForm">
  304. ${ csrf_token(request) | n,unicode }
  305. <div id="changePermissionModal" class="modal hide fade">
  306. <div class="modal-header">
  307. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  308. <h2 class="modal-title">${_('Change Permissions')}</h2>
  309. </div>
  310. <div class="modal-body table-margin">
  311. <table class="table table-condensed">
  312. <thead>
  313. <tr>
  314. <th>&nbsp;</th>
  315. <th class="center">${_('User')}</th>
  316. <th class="center">${_('Group')}</th>
  317. <th class="center">${_('Other')}</th>
  318. <th class="center">&nbsp;</th>
  319. <th width="120">&nbsp;</th>
  320. </tr>
  321. </thead>
  322. <tbody>
  323. <tr>
  324. <td><strong>${_('Read')}</strong></td>
  325. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="user_read"></td>
  326. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="group_read"></td>
  327. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="other_read"></td>
  328. <td colspan="2">&nbsp;</td>
  329. </tr>
  330. <tr>
  331. <td><strong>${_('Write')}</strong></td>
  332. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="user_write"></td>
  333. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="group_write"></td>
  334. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="other_write"></td>
  335. <td colspan="2">&nbsp;</td>
  336. </tr>
  337. <tr>
  338. <td><strong>${_('Execute')}</strong></td>
  339. <td class="center"><input type="checkbox" checked="" name="user_execute"></td>
  340. <td class="center"><input type="checkbox" checked="" name="group_execute"></td>
  341. <td class="center"><input type="checkbox" checked="" name="other_execute"></td>
  342. <td colspan="2">&nbsp;</td>
  343. </tr>
  344. <tr>
  345. <td><strong>${_('Sticky')}</strong></td>
  346. <td colspan="3">&nbsp;</td>
  347. <td class="center"><input type="checkbox" name="sticky"></td>
  348. <td>&nbsp;</td>
  349. </tr>
  350. <tr>
  351. <td><strong>${_('Recursive')}</strong></td>
  352. <td colspan="3">&nbsp;</td>
  353. <td class="center"><input type="checkbox" name="recursive"></td>
  354. <td>&nbsp;</td>
  355. </tr>
  356. </tbody>
  357. </table>
  358. </div>
  359. <div class="modal-footer" style="padding-top: 10px;">
  360. <a class="btn" onclick="$('#changePermissionModal').modal('hide');">${_('Cancel')}</a>
  361. <input class="btn btn-primary" type="submit" value="${_('Submit')}"/>
  362. </div>
  363. </div>
  364. </form>
  365. <!-- move modal -->
  366. <form id="moveForm" action="/filebrowser/move" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  367. ${ csrf_token(request) | n,unicode }
  368. <div id="moveModal" class="modal hide fade">
  369. <div class="modal-header">
  370. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  371. <h2 class="modal-title">${_('Move to')}</h2>
  372. </div>
  373. <div class="modal-body" style="max-height: 400px; height: 340px; overflow-x:hidden">
  374. <div id="moveFilechooser"></div>
  375. </div>
  376. <div class="modal-footer">
  377. <div>
  378. <input type="text" class="input-xlarge disable-autofocus" value="" name="dest_path" id="moveDestination" placeholder="${_('Select a folder or paste a path...')}" />
  379. <span id="moveNameRequiredAlert" class="hide label label-important">${_('Required')}</span>
  380. </div>
  381. <a class="btn" onclick="$('#moveModal').modal('hide');">${_('Cancel')}</a>
  382. <input class="btn btn-primary" type="submit" value="${_('Move')}"/>
  383. </div>
  384. </div>
  385. </form>
  386. <!-- copy modal -->
  387. <form id="copyForm" action="/filebrowser/copy" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  388. ${ csrf_token(request) | n,unicode }
  389. <div id="copyModal" class="modal hide fade">
  390. <div class="modal-header">
  391. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  392. <h2 class="modal-title">${_('Copy to')}</h2>
  393. </div>
  394. <div class="modal-body" style="max-height: 400px; height: 340px; overflow-x:hidden">
  395. <div id="copyFilechooser"></div>
  396. </div>
  397. <div class="modal-footer">
  398. <div>
  399. <input type="text" class="input-xlarge disable-autofocus" value="" name="dest_path" id="copyDestination" placeholder="${_('Select a folder or paste a path...')}" />
  400. <span id="copyNameRequiredAlert" class="hide label label-important">${_('Required')}</span>
  401. </div>
  402. <a class="btn" onclick="$('#copyModal').modal('hide');">${_('Cancel')}</a>
  403. <input class="btn btn-primary" type="submit" value="${_('Copy')}"/>
  404. </div>
  405. </div>
  406. </form>
  407. <!-- upload file modal -->
  408. <div id="uploadFileModal" class="modal hide fade">
  409. <div class="modal-header">
  410. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  411. <h2 class="modal-title">${_('Upload to')} <span data-bind="text: currentPath"></span></h2>
  412. </div>
  413. <div class="modal-body form-inline">
  414. <div id="fileUploader" class="uploader">
  415. <noscript>
  416. <p>${_('Enable JavaScript to use the file uploader.')}</p>
  417. </noscript>
  418. </div>
  419. </div>
  420. <div class="modal-footer"></div>
  421. </div>
  422. <!-- new directory modal -->
  423. <form id="createDirectoryForm" data-bind="submit: createDirectory" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  424. ${ csrf_token(request) | n,unicode }
  425. <div id="createDirectoryModal" class="modal hide fade">
  426. <div class="modal-header">
  427. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  428. <!-- ko if: !isS3() || (isS3() && !isS3Root()) -->
  429. <h2 class="modal-title">${_('Create Directory')}</h2>
  430. <!-- /ko -->
  431. <!-- ko if: isS3() && isS3Root() -->
  432. <h2 class="modal-title">${_('Create Bucket')}</h2>
  433. <!-- /ko -->
  434. </div>
  435. <div class="modal-body">
  436. <label>
  437. <!-- ko if: !isS3() || (isS3() && !isS3Root()) -->
  438. ${_('Directory Name')}
  439. <!-- /ko -->
  440. <!-- ko if: isS3() && isS3Root() -->
  441. ${_('Bucket Name')}
  442. <!-- /ko -->
  443. <input id="newDirectoryNameInput" name="name" value="" type="text" class="input-xlarge"/></label>
  444. <input type="hidden" name="path" data-bind="value: currentPath"/>
  445. </div>
  446. <div class="modal-footer">
  447. <div id="directoryNameRequiredAlert" class="hide" style="position: absolute; left: 10px;">
  448. <span class="label label-important">${_('Directory name is required.')}</span>
  449. </div>
  450. <div id="directoryNameExistsAlert" class="hide" style="position: absolute; left: 10px;">
  451. <span class="label label-important"><span class="newName"></span> ${_('already exists.')}</span>
  452. </div>
  453. <a class="btn" href="#" data-dismiss="modal">${_('Cancel')}</a>
  454. <input class="btn btn-primary" type="submit" value="${_('Create')}" />
  455. </div>
  456. </div>
  457. </form>
  458. <!-- new file modal -->
  459. <form id="createFileForm" data-bind="submit: createFile" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  460. ${ csrf_token(request) | n,unicode }
  461. <div id="createFileModal" class="modal hide fade">
  462. <div class="modal-header">
  463. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  464. <h2 class="modal-title">${_('Create File')}</h2>
  465. </div>
  466. <div class="modal-body">
  467. <label>${_('File Name')} <input id="newFileNameInput" name="name" value="" type="text" class="input-xlarge"/></label>
  468. <input type="hidden" name="path" data-bind="value: currentPath"/>
  469. </div>
  470. <div class="modal-footer">
  471. <div id="fileNameRequiredAlert" class="alert-message error hide" style="position: absolute; left: 10px;">
  472. <span class="label label-important">${_('File name is required.')}</span>
  473. </div>
  474. <div id="fileNameExistsAlert" class="hide" style="position: absolute; left: 10px;">
  475. <span class="label label-important"><span class="newName"></span> ${_('already exists.')}</span>
  476. </div>
  477. <a class="btn" href="#" data-dismiss="modal">${_('Cancel')}</a>
  478. <input class="btn btn-primary" type="submit" value="${_('Create')}" />
  479. </div>
  480. </div>
  481. </form>
  482. <!-- content summary modal -->
  483. <div id="contentSummaryModal" class="modal hide fade">
  484. <div class="modal-header">
  485. <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
  486. <!-- ko if: selectedFile -->
  487. <h2 class="modal-title" style="word-break: break-all">${_('Summary for')} <span data-bind="text: selectedFile().path"></span></h2>
  488. <!--/ko -->
  489. </div>
  490. <div class="modal-body">
  491. <div data-bind="visible: isLoadingSummary"><i class="fa fa-spin fa-spinner fa-2x fa-fw" style="color: #CCC"></i></div>
  492. <table class="table table-condensed" data-bind="visible: !isLoadingSummary()">
  493. <tr>
  494. <th>${ _('Disk space consumed') }</th>
  495. <td data-bind="text: formatBytes(contentSummary().spaceConsumed(), 4)"></td>
  496. </tr>
  497. <tr>
  498. <th>${ _('Bytes used') }</th>
  499. <td data-bind="text: formatBytes(contentSummary().length(), 4)"></td>
  500. </tr>
  501. <tr>
  502. <th>${ _('Namespace quota') }</th>
  503. <td data-bind="text: formatBytes(contentSummary().quota(), 4)"></td>
  504. </tr>
  505. <tr>
  506. <th>${ _('Disk space quota') }</th>
  507. <td data-bind="text: formatBytes(contentSummary().spaceQuota(), 4)"></td>
  508. </tr>
  509. <tr>
  510. <th>${ _('Replication factor') }</th>
  511. <td data-bind="text: contentSummary().replication()"></td>
  512. </tr>
  513. <tr>
  514. <th>${ _('Number of directories') }</th>
  515. <td data-bind="text: contentSummary().directoryCount()"></td>
  516. </tr>
  517. <tr>
  518. <th>${ _('Number of files') }</th>
  519. <td data-bind="text: contentSummary().fileCount()"></td>
  520. </tr>
  521. </table>
  522. </div>
  523. <div class="modal-footer">
  524. <a class="btn" data-dismiss="modal">${_('Close')}</a>
  525. </div>
  526. </div>
  527. <!-- actions context menu -->
  528. <ul class="context-menu dropdown-menu">
  529. <!-- ko ifnot: $root.inTrash -->
  530. <li data-bind="visible: !isS3() || (isS3() && !isS3Root()), css: {'disabled': $root.selectedFiles().length != 1 || isCurrentDirSelected().length > 0}">
  531. <a href="javascript: void(0)" title="${_('Rename')}" data-bind="click: ($root.selectedFiles().length == 1 && isCurrentDirSelected().length == 0) ? $root.renameFile: void(0)"><i class="fa fa-fw fa-font"></i>
  532. ${_('Rename')}</a></li>
  533. <li data-bind="visible: !isS3() || (isS3() && !isS3Root()), css: {'disabled': $root.selectedFiles().length == 0 || isCurrentDirSelected().length > 0}">
  534. <a href="javascript: void(0)" title="${_('Move')}" data-bind="click: ( $root.selectedFiles().length > 0 && isCurrentDirSelected().length == 0) ? $root.move: void(0)"><i class="fa fa-fw fa-random"></i> ${_('Move')}</a></li>
  535. <li data-bind="visible: !isS3() || (isS3() && !isS3Root()), css: {'disabled': $root.selectedFiles().length == 0 || isCurrentDirSelected().length > 0}">
  536. <a href="javascript: void(0)" title="${_('Copy')}" data-bind="click: ($root.selectedFiles().length > 0 && isCurrentDirSelected().length == 0) ? $root.copy: void(0)"><i class="fa fa-fw fa-files-o"></i> ${_('Copy')}</a></li>
  537. % if show_download_button:
  538. <li data-bind="css: {'disabled': $root.inTrash() || $root.selectedFiles().length != 1 || selectedFile().type != 'file'}">
  539. <a href="javascript: void(0)" title="${_('Download')}" data-bind="click: (!$root.inTrash() && $root.selectedFiles().length == 1 && selectedFile().type == 'file') ? $root.downloadFile: void(0)">
  540. <i class="fa fa-fw fa-arrow-circle-o-down"></i> ${_('Download')}</a></li>
  541. % endif
  542. <li class="divider" data-bind="visible: isPermissionEnabled()"></li>
  543. % if is_fs_superuser:
  544. <li data-bind="css: {'disabled': $root.isCurrentDirSentryManaged || selectedSentryFiles().length > 0 }, visible: isPermissionEnabled()">
  545. <a href="javascript: void(0)" data-bind="visible: !$root.inTrash(), click: $root.changeOwner, enable: $root.selectedFiles().length > 0">
  546. <i class="fa fa-fw fa-user"></i> ${_('Change owner / group')}
  547. </a>
  548. </li>
  549. % endif
  550. <li data-bind="css: {'disabled': $root.isCurrentDirSentryManaged() || selectedSentryFiles().length > 0 }, visible: isPermissionEnabled()">
  551. <a href="javascript: void(0)" data-bind="visible: !$root.inTrash(), click: $root.changePermissions, enable: $root.selectedFiles().length > 0">
  552. <i class="fa fa-fw fa-list-alt"></i> ${_('Change permissions')}
  553. </a>
  554. </li>
  555. <li class="divider" data-bind="visible: isCompressEnabled() || isReplicationEnabled() || isSummaryEnabled()"></li>
  556. % if is_trash_enabled:
  557. <li data-bind="css: {'disabled': $root.selectedFiles().length == 0 || isCurrentDirSelected().length > 0}">
  558. <a href="javascript: void(0)" data-bind="click: ($root.selectedFiles().length > 0 && isCurrentDirSelected().length == 0) ? $root.trashSelected: void(0)">
  559. <i class="fa fa-fw fa-times"></i> ${_('Move to trash')}</a></li>
  560. % endif
  561. <li><a href="javascript: void(0)" class="delete-link" title="${_('Delete forever')}" data-bind="enable: $root.selectedFiles().length > 0 && isCurrentDirSelected().length == 0, click: $root.deleteSelected"><i class="fa fa-fw fa-bolt"></i> ${_('Delete forever')}</a></li>
  562. <li class="divider" data-bind="visible: isSummaryEnabled()"></li>
  563. <li data-bind="css: {'disabled': selectedFiles().length > 1 }, visible: isSummaryEnabled()">
  564. <a class="pointer" data-bind="click: function(){ selectedFiles().length == 1 ? showSummary(): void(0)}"><i class="fa fa-fw fa-pie-chart"></i> ${_('Summary')}</a>
  565. </li>
  566. <li data-bind="css: {'disabled': inTrash() || !isReplicationEnabled() || selectedFiles().length != 1 || selectedFile().type != 'file'}">
  567. <a href="javascript: void(0)" title="${_('Set Replication')}" data-bind="click: (!inTrash() && isReplicationEnabled() && selectedFiles().length == 1 && selectedFile().type == 'file') ? setReplicationFactor: void(0)">
  568. <i class="fa fa-fw fa-hdd-o"></i> ${_('Set replication')}
  569. </a>
  570. </li>
  571. % if ENABLE_EXTRACT_UPLOADED_ARCHIVE.get():
  572. <li data-bind="css: {'disabled': ! showCompressButton}">
  573. <a href="javascript: void(0)" title="${_('Compress selection into a single archive')}" data-bind="click: function() { setCompressArchiveDefault(); confirmCompressFiles();}, visible: showCompressButton">
  574. <i class="fa fa-fw fa-file-archive-o"></i> ${_('Compress')}</a>
  575. </li>
  576. <li data-bind="css: {'disabled': selectedFiles().length != 1 || !isArchive(selectedFile().name) || !isCompressEnabled()}">
  577. <a href="javascript: void(0)" title="${_('Extract selected archive')}" data-bind="visible: selectedFiles().length == 1 && isArchive(selectedFile().name) && isCompressEnabled(), click: confirmExtractArchive">
  578. <i class="fa fa-fw fa-file-archive-o"></i> ${_('Extract')}</a>
  579. </li>
  580. % endif
  581. <!-- /ko -->
  582. <!-- ko if: $root.inTrash -->
  583. <li><a href="#" title="${_('Restore from trash')}" data-bind="visible: inRestorableTrash() && selectedFiles().length > 0 && isCurrentDirSelected().length == 0, click: restoreTrashSelected"><i class="fa fa-fw fa-cloud-upload"></i> ${_('Restore')}</a></li>
  584. <li class="divider"></li>
  585. <li><a href="#" title="${_('Empty trash')}" data-bind="visible: inTrash(), click: purgeTrash"><i class="fa fa-fw fa-fire"></i> ${_('Empty trash')}</a></li>
  586. <!-- /ko -->
  587. </ul>
  588. <div id="submit-wf-modal" class="modal hide"></div>
  589. <script id="fileTemplate" type="text/html">
  590. <tr class="row-animated" style="cursor: pointer" data-bind="drop: { enabled: name !== '.' && type !== 'file' && (!$root.isS3() || ($root.isS3() && !$root.isS3Root())), value: $data }, event: { mouseover: toggleHover, mouseout: toggleHover, contextmenu: showContextMenu }, click: $root.viewFile, css: { 'row-selected': selected(), 'row-highlighted': highlighted(), 'row-deleted': deleted() }">
  591. <td class="center" data-bind="click: name !== '..' ? handleSelect : void(0)" style="cursor: default">
  592. <div data-bind="multiCheck: '#fileBrowserTable', visible: name != '..', css: { 'hue-checkbox': name != '..', 'fa': name != '..', 'fa-check': selected }"></div>
  593. </td>
  594. <td class="left"><i data-bind="click: $root.viewFile, css: { 'fa': true,
  595. % if 'oozie' in apps:
  596. 'fa-play': $.inArray(name, ['workflow.xml', 'coordinator.xml', 'bundle.xml']) > -1,
  597. % endif
  598. 'fa-file-o': type == 'file', 'fa-folder': type != 'file', 'fa-folder-open': type != 'file' && hovered(), 'fa-cloud': type != 'file' && isBucket() }"></i></td>
  599. <td data-bind="attr: {'title': tooltip}" rel="tooltip">
  600. <!-- ko if: name == '..' -->
  601. <a href="#" data-bind="click: $root.viewFile"><i class="fa fa-level-up"></i></a>
  602. <!-- /ko -->
  603. <!-- ko if: name != '..' -->
  604. <strong><a href="#" class="draggable-fb" data-bind="drag: { enabled: (!$root.isS3() || ($root.isS3() && !$root.isS3Root())), value: $data }, click: $root.viewFile, text: name, attr: { 'draggable': $.inArray(name, ['.', '..', '.Trash']) === -1 && !isBucket()}"></a></strong>
  605. <!-- /ko -->
  606. </td>
  607. <td>
  608. <span data-bind="visible: type == 'file', text: stats.size"></span>
  609. </td>
  610. <td class="truncate-text" style="max-width: 150px">
  611. % if is_fs_superuser:
  612. <span data-bind="text: stats.user, visible: !selected() || $root.isCurrentDirSentryManaged() || isSentryManaged, attr: { 'title': stats.user }"></span>
  613. <a href="#" rel="tooltip" title="${_('Change owner')}" data-original-title="${_('Change owner')}"
  614. data-bind="text: stats.user, visible: !$root.inTrash() && selected() && !$root.isCurrentDirSentryManaged() && !isSentryManaged, click: $root.changeOwner, enable: $root.selectedFiles().length > 0, attr: { 'title': stats.user }"></a>
  615. % else:
  616. <span data-bind="text: stats.user, attr: { 'title': stats.user }"></span>
  617. % endif
  618. </td>
  619. <td class="truncate-text" style="max-width: 150px">
  620. % if is_fs_superuser:
  621. <span data-bind="text: stats.group, visible: ! selected() || $root.isCurrentDirSentryManaged() || isSentryManaged, attr: { 'title': stats.group }"></span>
  622. <a href="#" rel="tooltip" title="${_('Change group')}" data-original-title="${_('Change group')}"
  623. data-bind="text: stats.group, visible: !$root.inTrash() && selected() && !$root.isCurrentDirSentryManaged() && !isSentryManaged, click: $root.changeOwner, attr: { 'title': stats.group }"></a>
  624. % else:
  625. <span data-bind="text: stats.group, attr: { 'title': stats.group }"></span>
  626. % endif
  627. </td>
  628. <td>
  629. <span data-bind="text: permissions, visible: $root.isS3() || !selected() || $root.isCurrentDirSentryManaged() || isSentryManaged"></span>
  630. <a href="#" rel="tooltip" title="${_('Change permissions')}"
  631. data-bind="text: permissions, visible: !$root.isS3() && !$root.inTrash() && selected() && !$root.isCurrentDirSentryManaged() && !isSentryManaged, click: $root.changePermissions" data-original-title="${_('Change permissions')}"></a>
  632. </td>
  633. <td data-bind="text: stats.mtime" style="white-space: nowrap;"></td>
  634. </tr>
  635. </script>
  636. <script src="${ static('desktop/ext/js/jquery/plugins/jquery-ui-1.10.4.custom.min.js') }" type="text/javascript" charset="utf-8"></script>
  637. <script src="${ static('desktop/ext/js/datatables-paging-0.1.js') }" type="text/javascript" charset="utf-8"></script>
  638. <script>
  639. var _dragged;
  640. var _dropzone;
  641. ko.bindingHandlers.drag = {
  642. update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
  643. var dragElement = $(element);
  644. try {
  645. dragElement.draggable('destroy');
  646. }
  647. catch (e) {}
  648. var dragOptions = {
  649. helper: 'clone',
  650. revert: true,
  651. revertDuration: 0,
  652. start: function () {
  653. if ($(element).is('[draggable]')) {
  654. viewModel.selected(true);
  655. }
  656. _dragged = ko.utils.unwrapObservable(valueAccessor().value);
  657. },
  658. cursor: "move",
  659. delay: 300
  660. };
  661. dragElement.draggable(dragOptions).disableSelection();
  662. }
  663. };
  664. ko.bindingHandlers.drop = {
  665. update: function (element, valueAccessor) {
  666. var dropElement = $(element);
  667. try {
  668. dropElement.droppable('destroy');
  669. }
  670. catch (e) {}
  671. if (valueAccessor().enabled) {
  672. var dropOptions = {
  673. hoverClass: 'drag-hover',
  674. accept: '.draggable-fb',
  675. drop: function (event, ui) {
  676. var destpath = valueAccessor().value.path;
  677. dropElement.fadeOut(200, function () {
  678. dropElement.fadeIn(200);
  679. });
  680. if (destpath) {
  681. $('#moveDestination').val(destpath);
  682. viewModel.move('nomodal', _dragged);
  683. }
  684. }
  685. };
  686. dropElement.droppable(dropOptions);
  687. }
  688. }
  689. };
  690. var apiHelper = ApiHelper.getInstance({
  691. user: "${ user }"
  692. });
  693. // ajax modal windows
  694. var openChownWindow = function (path, user, group, next) {
  695. $.ajax({
  696. url: "/filebrowser/chown",
  697. data: {"path": path, "user": user, "group": group, "next": next},
  698. beforeSend: function (xhr) {
  699. xhr.setRequestHeader("X-Requested-With", "Hue");
  700. },
  701. dataType: "html",
  702. success: function (data) {
  703. $("#changeOwnerModal").html(data);
  704. $("#changeOwnerModal").modal({
  705. keyboard:true,
  706. show:true
  707. });
  708. },
  709. error: function (xhr, textStatus, errorThrown) {
  710. $(document).trigger("error", xhr.responseText);
  711. resetPrimaryButtonsStatus();
  712. }
  713. });
  714. };
  715. var fileExists = function (newName) {
  716. if (viewModel) {
  717. var files = viewModel.files();
  718. for (var i = 0; i < files.length; i++) {
  719. if (files[i].name == newName) {
  720. return true;
  721. }
  722. }
  723. }
  724. return false;
  725. };
  726. var resetActionbar = function() {
  727. $(".actionbar").attr("style", "min-width: 800px");
  728. $(".actionbar").data("originalWidth", $(".actionbar").width());
  729. $(".actionbarGhost").addClass("hide");
  730. };
  731. var stripHashes = function (str) {
  732. return str.replace(/#/gi, encodeURIComponent("#"));
  733. };
  734. var formatBytes = function (bytes, decimals) {
  735. if (bytes == -1) return "${ _('Not available.') }";
  736. if (bytes == 0) return "0 Byte";
  737. var k = 1024;
  738. var dm = decimals + 1 || 3;
  739. var sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
  740. var i = Math.floor(Math.log(bytes) / Math.log(k));
  741. return (bytes / Math.pow(k, i)).toPrecision(dm) + ' ' + sizes[i];
  742. }
  743. var updateHash = function (hash) {
  744. hash = encodeURI(hash);
  745. %if not is_embeddable:
  746. window.location.hash = hash;
  747. %else:
  748. hueUtils.changeURL('#' + hash);
  749. huePubSub.publish('fb.update.hash');
  750. %endif
  751. }
  752. var Page = function (page) {
  753. if (page != null) {
  754. return {
  755. number: page.number,
  756. num_pages: page.num_pages,
  757. previous_page_number: page.previous_page_number,
  758. next_page_number: page.next_page_number,
  759. start_index: page.start_index,
  760. end_index: page.end_index,
  761. total_count: page.total_count
  762. }
  763. }
  764. return {
  765. }
  766. };
  767. var File = function (file) {
  768. file.tooltip = "";
  769. if (file.name == "."){
  770. file.tooltip = "${_('This folder')}";
  771. }
  772. if (file.name == ".."){
  773. file.tooltip = "${_('One level up')}";
  774. }
  775. return {
  776. name: file.name,
  777. path: file.path,
  778. url: encodeURI(file.url),
  779. type: file.type,
  780. permissions: file.rwx,
  781. mode: file.mode,
  782. isSentryManaged: file.is_sentry_managed,
  783. stats: {
  784. size: file.humansize,
  785. user: file.stats.user,
  786. group: file.stats.group,
  787. mtime: file.mtime,
  788. replication: file.stats.replication
  789. },
  790. isBucket: ko.pureComputed(function(){
  791. return file.path.toLowerCase().indexOf('s3a://') == 0 && file.path.substr(6).indexOf('/') == -1
  792. }),
  793. selected: ko.observable(file.highlighted && viewModel.isArchive(file.name) || false),
  794. highlighted: ko.observable(file.highlighted || false),
  795. deleted: ko.observable(file.deleted || false),
  796. handleSelect: function (row, e) {
  797. e.preventDefault();
  798. e.stopPropagation();
  799. this.selected(!this.selected());
  800. if (!this.selected()) {
  801. hideContextMenu();
  802. }
  803. this.highlighted(false);
  804. this.deleted(false);
  805. viewModel.allSelected(false);
  806. },
  807. // display the context menu when an item is right/context clicked
  808. showContextMenu: function (row, e) {
  809. var cm = $('.context-menu'),
  810. actions = $('#ch-dropdown'),
  811. rect = document.querySelector(HUE_CONTAINER).getBoundingClientRect();
  812. e.stopPropagation();
  813. // close the actions menu from button area if open
  814. if (actions.hasClass('open')) {
  815. actions.removeClass('open');
  816. }
  817. // display context menu and ensure it is on-screen
  818. if ($.inArray(row.name, ['..', '.Trash']) === -1) {
  819. this.selected(true);
  820. var verticalCorrection = 0;
  821. %if is_embeddable:
  822. verticalCorrection = $('.page-content').scrollTop() - $('.navbar-default').height() - $('.banner').height();
  823. %endif
  824. cm.css({ display: 'block', top: e.pageY - 15 + verticalCorrection, left: (e.offsetX < rect.right - 300 ) ? e.offsetX + 100 : e.offsetX - 250 });
  825. } else {
  826. cm.css({ display: 'none' });
  827. }
  828. },
  829. hovered: ko.observable(false),
  830. toggleHover: function (row, e) {
  831. this.hovered(! this.hovered());
  832. },
  833. tooltip:file.tooltip
  834. }
  835. };
  836. var Breadcrumb = function (breadcrumb) {
  837. return {
  838. url: breadcrumb.url,
  839. label: breadcrumb.label,
  840. show: function (breadcrumb, e) {
  841. var isLeftButton = (e.which || e.button) === 1;
  842. if (isLeftButton) {
  843. if (! (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey)) {
  844. e.stopPropagation();
  845. e.preventDefault();
  846. if (this.url == null || this.url == "") {
  847. // forcing root on empty breadcrumb url
  848. this.url = "/";
  849. }
  850. viewModel.targetPageNum(1);
  851. viewModel.targetPath("${url('filebrowser.views.view', path='')}" + stripHashes(this.url));
  852. updateHash(this.url);
  853. }
  854. else {
  855. window.open($(e.target).attr('href'));
  856. }
  857. }
  858. }
  859. }
  860. };
  861. var FileBrowserModel = function (files, page, breadcrumbs, currentDirPath) {
  862. var self = this;
  863. self.page = ko.observable(new Page(page));
  864. self.recordsPerPageChoices = ["15", "30", "45", "60", "100", "200", "1000"],
  865. self.recordsPerPage = ko.observable(apiHelper.getFromTotalStorage('fb', 'records_per_page', 45));
  866. self.targetPageNum = ko.observable(1);
  867. self.targetPath = ko.observable("${current_request_path | n,unicode }");
  868. self.sortBy = ko.observable("name");
  869. self.sortDescending = ko.observable(false);
  870. self.searchQuery = ko.observable("");
  871. self.skipTrash = ko.observable(false);
  872. self.enableFilterAfterSearch = true;
  873. self.isCurrentDirSentryManaged = ko.observable(false);
  874. self.pendingUploads = ko.observable(0);
  875. self.pendingUploads.subscribe(function (val) {
  876. if (val > 0) {
  877. if ($('#uploadFileModal').data('modal')) {
  878. $('#uploadFileModal').data('modal').$element.off('keyup.dismiss.modal');
  879. if ($('#uploadFileModal').data('modal').$backdrop){
  880. $('#uploadFileModal').data('modal').$backdrop.off('click');
  881. }
  882. }
  883. }
  884. });
  885. self.filesToHighlight = ko.observableArray([]);
  886. self.fileNameSorting = function (l, r) {
  887. if (l.name == "..") {
  888. return -1;
  889. }
  890. else if (r.name == "..") {
  891. return 1;
  892. }
  893. else if (l.name == ".") {
  894. return -1;
  895. }
  896. else if (r.name == ".") {
  897. return 1;
  898. }
  899. else {
  900. var _ret = l.name > r.name ? 1 : -1;
  901. if (self.sortDescending()){
  902. _ret = _ret * -1;
  903. }
  904. return _ret;
  905. }
  906. }
  907. self.files = ko.observableArray(ko.utils.arrayMap(files, function (file) {
  908. return new File(file);
  909. }));
  910. if (self.sortBy() == "name"){
  911. self.files.sort(self.fileNameSorting);
  912. }
  913. self.homeDir = ko.observable("${home_directory}");
  914. self.breadcrumbs = ko.observableArray(ko.utils.arrayMap(breadcrumbs, function (breadcrumb) {
  915. return new Breadcrumb(breadcrumb);
  916. }));
  917. self.sort = function (viewModel, event) {
  918. var el = $(event.currentTarget);
  919. el.siblings(".sortable").attr("class", "sortable sorting");
  920. self.sortBy(el.data("sort"));
  921. el.removeClass("sorting");
  922. if (el.hasClass("sorting_asc")) {
  923. self.sortDescending(true);
  924. } else {
  925. self.sortDescending(false);
  926. }
  927. el.attr("class", "sortable");
  928. if (self.sortDescending() == true) {
  929. el.addClass("sorting_desc");
  930. } else {
  931. el.addClass("sorting_asc");
  932. }
  933. self.retrieveData();
  934. }
  935. self.isLoading = ko.observable(true);
  936. self.allSelected = ko.observable(false);
  937. self.compressArchiveName = ko.observable('');
  938. self.selectedFiles = ko.computed(function () {
  939. return ko.utils.arrayFilter(self.files(), function (file) {
  940. return file.selected();
  941. });
  942. }, self).extend({ rateLimit: { timeout: 500, method: "notifyWhenChangesStop" } });
  943. self.selectedSentryFiles = ko.computed(function () {
  944. return ko.utils.arrayFilter(self.files(), function (file) {
  945. return file.selected() && file.isSentryManaged;
  946. });
  947. }, self).extend({ rateLimit: { timeout: 500, method: "notifyWhenChangesStop" } });
  948. self.isCurrentDirSelected = ko.computed(function () {
  949. return ko.utils.arrayFilter(self.files(), function (file) {
  950. return file.name == "." && file.selected();
  951. });
  952. }, self).extend({ rateLimit: { timeout: 500, method: "notifyWhenChangesStop" } });
  953. self.selectedFile = ko.computed(function () {
  954. return self.selectedFiles()[0];
  955. }, self).extend({ rateLimit: { timeout: 500, method: "notifyWhenChangesStop" } });
  956. self.isSelectedFileSql = ko.pureComputed(function() {
  957. return self.selectedFile().name.endsWith('.sql') || self.selectedFile().name.endsWith('.hql');
  958. });
  959. self.openFileInEditor = function() {
  960. huePubSub.publish('open.editor.new.query', {'statementType': 'file', 'statementPath': self.selectedFile().path});
  961. };
  962. self.currentPath = ko.observable(currentDirPath);
  963. self.currentPath.subscribe(function (path) {
  964. $(document).trigger('currPathLoaded', { path: path });
  965. });
  966. self.isS3 = ko.pureComputed(function () {
  967. return self.currentPath().toLowerCase().indexOf('s3a://') === 0;
  968. });
  969. self.isAdls = ko.pureComputed(function () {
  970. return self.currentPath().toLowerCase().indexOf('adl:/') === 0;
  971. });
  972. self.scheme = ko.pureComputed(function () {
  973. var path = self.currentPath();
  974. return path.substring(0, path.indexOf(':/')) || "hdfs";
  975. });
  976. self.fs = ko.pureComputed(function () {
  977. var scheme = self.scheme();
  978. if (scheme === 'adl') {
  979. return 'adls';
  980. } else if (scheme === 's3a' ){
  981. return 's3';
  982. } else if (!scheme || scheme == 'hdfs') {
  983. return 'hdfs';
  984. } else {
  985. return scheme;
  986. }
  987. });
  988. function root(path) {
  989. var path = path && path.toLowerCase();
  990. if (path.indexOf('s3a://') >= 0) {
  991. return 's3a://';
  992. } else if (path.indexOf('adl:/') >= 0) {
  993. return 'adl:/';
  994. } else {
  995. return '/';
  996. }
  997. };
  998. self.rootCurrent = ko.pureComputed(function () {
  999. return root(self.currentPath());
  1000. });
  1001. self.rootTarget = ko.pureComputed(function () {
  1002. return root(self.targetPath());
  1003. });
  1004. self.isHdfs = ko.pureComputed(function () {
  1005. var currentPath = self.currentPath().toLowerCase();
  1006. return currentPath.indexOf('/') === 0 || currentPath.indexOf('hdfs') === 0
  1007. });
  1008. self.isCompressEnabled = ko.pureComputed(function () {
  1009. return !self.isS3() && !self.isAdls();
  1010. });
  1011. self.isSummaryEnabled = ko.pureComputed(function () {
  1012. return self.isHdfs();
  1013. });
  1014. self.isPermissionEnabled = ko.pureComputed(function () {
  1015. return !self.isS3();
  1016. });
  1017. self.isReplicationEnabled = ko.pureComputed(function () {
  1018. return self.isHdfs();
  1019. });
  1020. self.isS3.subscribe(function (newVal) {
  1021. if (newVal) {
  1022. huePubSub.publish('update.autocompleters');
  1023. }
  1024. });
  1025. self.isS3Root = ko.pureComputed(function () {
  1026. return self.isS3() && self.currentPath().toLowerCase() === 's3a://';
  1027. });
  1028. self.inTrash = ko.computed(function() {
  1029. return self.currentPath().match(/^\/user\/.+?\/\.Trash/);
  1030. });
  1031. self.inRestorableTrash = ko.computed(function() {
  1032. return self.currentPath().match(/^\/user\/.+?\/\.Trash\/.+?/);
  1033. });
  1034. self.isLoadingSummary = ko.observable(true);
  1035. self.contentSummary = ko.observable(ko.mapping.fromJS({
  1036. spaceConsumed: -1,
  1037. quota: -1,
  1038. spaceQuota: -1,
  1039. length: 0,
  1040. directoryCount: 0,
  1041. fileCount: 0,
  1042. replication: 0
  1043. }));
  1044. self.showSummary = function () {
  1045. self.isLoadingSummary(true);
  1046. $("#contentSummaryModal").modal("show");
  1047. $.getJSON("${url('content_summary', path='')}" + self.selectedFile().path, function (data) {
  1048. if (data.status == 0) {
  1049. self.contentSummary(ko.mapping.fromJS(data.summary));
  1050. self.isLoadingSummary(false);
  1051. } else {
  1052. $(document).trigger("error", data.message);
  1053. $("#contentSummaryModal").modal("hide");
  1054. }
  1055. }).fail(function (xhr, textStatus, errorThrown) {
  1056. $(document).trigger("error", xhr.responseText);
  1057. $("#contentSummaryModal").modal("hide");
  1058. });
  1059. }
  1060. self.getStats = function (callback) {
  1061. $.getJSON(self.targetPath() + (self.targetPath().indexOf('?') > 0 ? '&' : '?') + "pagesize=1&format=json", callback);
  1062. };
  1063. self.retrieveData = function (clearAssistCache) {
  1064. self.isLoading(true);
  1065. $.getJSON(self.targetPath() + (self.targetPath().indexOf('?') > 0 ? '&' : '?') + "pagesize=" + self.recordsPerPage() + "&pagenum=" + self.targetPageNum() + "&filter=" + self.searchQuery() + "&sortby=" + self.sortBy() + "&descending=" + self.sortDescending() + "&format=json", function (data) {
  1066. if (data.error){
  1067. $(document).trigger("error", data.error);
  1068. self.isLoading(false);
  1069. return false;
  1070. }
  1071. if (data.type != null && data.type == "file") {
  1072. window.location.href = data.url;
  1073. return false;
  1074. }
  1075. self.updateFileList(data.files, data.page, data.breadcrumbs, data.current_dir_path, data.is_sentry_managed);
  1076. if (clearAssistCache) {
  1077. huePubSub.publish('assist.'+self.fs()+'.refresh');
  1078. }
  1079. if ($("#hueBreadcrumbText").is(":visible")) {
  1080. $(".hue-breadcrumbs").show();
  1081. $("#hueBreadcrumbText").hide();
  1082. $("#editBreadcrumb").show();
  1083. }
  1084. });
  1085. };
  1086. self.updateFileList = function (files, page, breadcrumbs, currentDirPath, isSentryManaged) {
  1087. $(".tooltip").hide();
  1088. self.isCurrentDirSentryManaged(isSentryManaged);
  1089. self.page(new Page(page));
  1090. self.files(ko.utils.arrayMap(files, function (file) {
  1091. file.highlighted = self.filesToHighlight.indexOf(file.path) > -1;
  1092. var f = new File(file);
  1093. window.setTimeout(function(){
  1094. f.highlighted(false);
  1095. }, 3000);
  1096. return f;
  1097. }));
  1098. self.filesToHighlight([]);
  1099. if (self.sortBy() == "name"){
  1100. self.files.sort(self.fileNameSorting);
  1101. }
  1102. self.breadcrumbs(ko.utils.arrayMap(breadcrumbs, function (breadcrumb) {
  1103. return new Breadcrumb(breadcrumb);
  1104. }));
  1105. self.currentPath(currentDirPath);
  1106. $('.uploader').trigger('fb:updatePath', {dest:self.currentPath()});
  1107. self.isLoading(false);
  1108. $("*[rel='tooltip']").tooltip({ placement:"left" });
  1109. var $scrollable = $(window);
  1110. %if is_embeddable:
  1111. $scrollable = $('.page-content');
  1112. %endif
  1113. if ($('.row-highlighted').length > 0) {
  1114. $scrollable.scrollTop($('.row-highlighted:eq(0)').offset().top - 150);
  1115. }
  1116. else if ($('.row-deleted').length > 0) {
  1117. $scrollable.scrollTop($('.row-deleted:eq(0)').offset().top - 150);
  1118. }
  1119. else {
  1120. $scrollable.scrollTop(0);
  1121. }
  1122. resetActionbar();
  1123. };
  1124. self.recordsPerPage.subscribe(function (newValue) {
  1125. apiHelper.setInTotalStorage('fb', 'records_per_page', newValue)
  1126. self.retrieveData();
  1127. });
  1128. self.skipTo = function () {
  1129. var doc = document,
  1130. old_page = doc.querySelector('#current_page').value,
  1131. page = doc.querySelector('.pagination-input');
  1132. if (! isNaN(page.value) && (page.value > 0 && page.value <= self.page().num_pages)) {
  1133. self.goToPage(page.value);
  1134. } else {
  1135. page.value = old_page;
  1136. }
  1137. };
  1138. self.goToPage = function (pageNumber) {
  1139. self.targetPageNum(pageNumber);
  1140. self.retrieveData();
  1141. };
  1142. self.firstPage = function () {
  1143. self.goToPage(1)
  1144. };
  1145. self.previousPage = function () {
  1146. self.goToPage(self.page().previous_page_number)
  1147. };
  1148. self.nextPage = function () {
  1149. self.goToPage(self.page().next_page_number)
  1150. };
  1151. self.lastPage = function () {
  1152. self.goToPage(self.page().num_pages)
  1153. };
  1154. self.selectAll = function () {
  1155. self.allSelected(!self.allSelected());
  1156. ko.utils.arrayForEach(self.files(), function (file) {
  1157. if (file.name != "." && file.name != "..") {
  1158. file.selected(self.allSelected());
  1159. }
  1160. });
  1161. return true;
  1162. };
  1163. self.searchQuery.subscribe(function (newValue) {
  1164. if (newValue !== '' || self.enableFilterAfterSearch) {
  1165. self.filter();
  1166. }
  1167. self.enableFilterAfterSearch = true;
  1168. });
  1169. self.filter = function () {
  1170. self.targetPageNum(1);
  1171. self.retrieveData();
  1172. };
  1173. self.openDefaultFolder = function (vm, e, folderPath) {
  1174. var isLeftButton = (e.which || e.button) === 1;
  1175. if (isLeftButton) {
  1176. if (! (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey)) {
  1177. e.stopPropagation();
  1178. e.preventDefault();
  1179. viewModel.targetPageNum(1);
  1180. viewModel.targetPath("${url('filebrowser.views.view', path='')}?" + folderPath);
  1181. updateHash('');
  1182. viewModel.retrieveData();
  1183. }
  1184. else {
  1185. window.open("${url('filebrowser.views.view', path='')}?" + folderPath);
  1186. }
  1187. }
  1188. }
  1189. self.openHome = function (vm, e) {
  1190. self.openDefaultFolder(vm, e, 'default_to_home');
  1191. }
  1192. self.openTrash = function (vm, e) {
  1193. self.openDefaultFolder(vm, e, 'default_to_trash');
  1194. }
  1195. self.viewFile = function (file, e) {
  1196. e.stopImmediatePropagation();
  1197. if (file.type == "dir") {
  1198. // Reset page number so that we don't hit a page that doesn't exist
  1199. self.targetPageNum(1);
  1200. self.enableFilterAfterSearch = false;
  1201. self.searchQuery("");
  1202. self.targetPath("${url('filebrowser.views.view', path='')}" + stripHashes(file.path));
  1203. updateHash(stripHashes(file.path));
  1204. } else {
  1205. %if is_embeddable:
  1206. huePubSub.publish('open.link', file.url);
  1207. %else:
  1208. window.location.href = file.url;
  1209. %endif
  1210. }
  1211. };
  1212. self.editFile = function () {
  1213. window.location.href = "${url('filebrowser_views_edit', path='')}" + encodeURI(self.selectedFile().path);
  1214. };
  1215. self.downloadFile = function () {
  1216. window.location.href = "${url('filebrowser_views_download', path='')}" + encodeURI(self.selectedFile().path);
  1217. };
  1218. self.renameFile = function () {
  1219. $("#renameSrcPath").attr("value", self.selectedFile().path);
  1220. $("#renameFileName").text(self.selectedFile().path);
  1221. $("#newNameInput").val(self.selectedFile().name);
  1222. $("#renameForm").attr("action", "/filebrowser/rename?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1223. $('#renameForm').ajaxForm({
  1224. dataType: 'json',
  1225. success: function() {
  1226. $("#renameModal").modal('hide');
  1227. self.filesToHighlight.push(self.currentPath() + '/' + $('#newNameInput').val());
  1228. self.retrieveData(true);
  1229. }
  1230. });
  1231. $("#renameModal").modal({
  1232. keyboard:true,
  1233. show:true
  1234. });
  1235. };
  1236. self.setReplicationFactor = function () {
  1237. $("#SrcPath").attr("value", self.selectedFile().path);
  1238. $("#setReplFileName").text(self.selectedFile().path);
  1239. $("#setReplicationFactorForm").attr("action", "/filebrowser/set_replication?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1240. $('#setReplicationFactorForm').ajaxForm({
  1241. dataType: 'json',
  1242. success: function() {
  1243. $("#setReplicationModal").modal('hide');
  1244. $("#newRepFactorInput").val('');
  1245. self.retrieveData(true);
  1246. }
  1247. });
  1248. $("#setReplicationModal").modal({
  1249. keyboard:true,
  1250. show:true
  1251. }).on('shown', function(){
  1252. $('#newRepFactorInput').val(self.selectedFile().stats.replication);
  1253. });
  1254. };
  1255. self.move = function (mode, unselectedDrag) {
  1256. var paths = [];
  1257. var isMoveOnSelf = false;
  1258. $(self.selectedFiles()).each(function (index, file) {
  1259. if (file.path == $('#moveDestination').val()){
  1260. isMoveOnSelf = true;
  1261. }
  1262. paths.push(file.path);
  1263. });
  1264. if (paths.length == 0 && typeof unselectedDrag !== 'undefined'){
  1265. paths.push(_dragged.path);
  1266. }
  1267. if (!isMoveOnSelf){
  1268. hiddenFields($("#moveForm"), "src_path", paths);
  1269. $("#moveForm").attr("action", "/filebrowser/move?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1270. $('#moveForm').ajaxForm({
  1271. dataType: 'json',
  1272. success: function() {
  1273. $("#moveModal").modal('hide');
  1274. self.filesToHighlight.push(self.currentPath() + '/' + $('#moveDestination').val());
  1275. self.retrieveData(true);
  1276. },
  1277. error: function(xhr){
  1278. $.jHueNotify.error(xhr.responseText);
  1279. resetPrimaryButtonsStatus();
  1280. $('#moveDestination').val('');
  1281. }
  1282. });
  1283. if (mode === 'nomodal') {
  1284. $.jHueNotify.info('${ _('Items moving to') } "' + $('#moveDestination').val() + '"');
  1285. $("#moveForm").submit();
  1286. } else {
  1287. $("#moveModal").modal({
  1288. keyboard: true,
  1289. show: true
  1290. });
  1291. $("#moveModal").on("shown", function () {
  1292. $("#moveDestination").val('');
  1293. $("#moveNameRequiredAlert").hide();
  1294. $("#moveForm").find("input[name='*dest_path']").removeClass("fieldError");
  1295. $("#moveModal .modal-footer div").show();
  1296. $("#moveFilechooser").remove();
  1297. $("<div>").attr("id", "moveFilechooser").appendTo($("#moveModal .modal-body"));
  1298. $("#moveFilechooser").jHueFileChooser({
  1299. initialPath: paths[0] || '',
  1300. filesystemsFilter: [self.scheme()],
  1301. onNavigate: function (filePath) {
  1302. $("#moveDestination").val(filePath);
  1303. },
  1304. createFolder: false,
  1305. uploadFile: false
  1306. });
  1307. });
  1308. }
  1309. }
  1310. else {
  1311. $.jHueNotify.warn("${ _('You cannot copy a folder into itself.') }");
  1312. $('#moveDestination').val('');
  1313. }
  1314. };
  1315. self.copy = function () {
  1316. var paths = [];
  1317. $(self.selectedFiles()).each(function (index, file) {
  1318. paths.push(file.path);
  1319. });
  1320. hiddenFields($("#copyForm"), "src_path", paths);
  1321. $("#copyForm").attr("action", "/filebrowser/copy?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1322. $("#copyModal").modal({
  1323. keyboard:true,
  1324. show:true
  1325. });
  1326. $('#copyForm').ajaxForm({
  1327. dataType: 'json',
  1328. success: function() {
  1329. $("#copyModal").modal('hide');
  1330. self.filesToHighlight.push(self.currentPath() + '/' + $('#copyDestination').val());
  1331. self.retrieveData(true);
  1332. },
  1333. error: function(xhr){
  1334. $.jHueNotify.error(xhr.responseText);
  1335. resetPrimaryButtonsStatus();
  1336. }
  1337. });
  1338. $("#copyModal").on("shown", function () {
  1339. $("#copyDestination").val('');
  1340. $("#copyNameRequiredAlert").hide();
  1341. $("#copyForm").find("input[name='*dest_path']").removeClass("fieldError");
  1342. $("#copyModal .modal-footer div").show();
  1343. $("#copyFilechooser").remove();
  1344. $("<div>").attr("id", "copyFilechooser").appendTo($("#copyModal .modal-body"));
  1345. $("#copyFilechooser").jHueFileChooser({
  1346. initialPath: paths[0] || '',
  1347. filesystemsFilter: [self.scheme()],
  1348. onNavigate: function (filePath) {
  1349. $("#copyDestination").val(filePath);
  1350. },
  1351. createFolder: false,
  1352. uploadFile: false
  1353. });
  1354. });
  1355. };
  1356. self.changeOwner = function (data, event) {
  1357. if (!self.isCurrentDirSentryManaged()) {
  1358. var paths = [];
  1359. event.preventDefault();
  1360. event.stopPropagation();
  1361. $(self.selectedFiles()).each(function (index, file) {
  1362. paths.push(file.path);
  1363. });
  1364. hiddenFields($("#chownForm"), 'path', paths);
  1365. $("#chownForm").attr("action", "/filebrowser/chown?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1366. $("select[name=user]").val(self.selectedFile().stats.user);
  1367. $("#chownForm input[name='group_other']").removeClass("fieldError");
  1368. $("#chownForm input[name='user_other']").removeClass("fieldError");
  1369. $("#chownRequired").hide();
  1370. if ($("select[name=group] option:contains('" + self.selectedFile().stats.group + "')").length > 0) {
  1371. $("select[name=group]").val(self.selectedFile().stats.group);
  1372. } else {
  1373. $("select[name=group]").val("__other__");
  1374. $("input[name=group_other]").val(self.selectedFile().stats.group);
  1375. }
  1376. $("select[name=group]").change();
  1377. $("#changeOwnerModal").modal({
  1378. keyboard: true,
  1379. show: true
  1380. });
  1381. $('#chownForm').ajaxForm({
  1382. dataType: 'json',
  1383. success: function() {
  1384. $("#changeOwnerModal").modal('hide');
  1385. $(self.selectedFiles()).each(function (index, file) {
  1386. self.filesToHighlight.push(file.path);
  1387. });
  1388. self.retrieveData(true);
  1389. },
  1390. error: function (xhr, textStatus, errorThrown) {
  1391. $(document).trigger("error", xhr.responseText);
  1392. resetPrimaryButtonsStatus();
  1393. }
  1394. });
  1395. }
  1396. };
  1397. self.changePermissions = function (data, event) {
  1398. if (!self.isCurrentDirSentryManaged()) {
  1399. var paths = [];
  1400. event.preventDefault();
  1401. event.stopPropagation();
  1402. $(self.selectedFiles()).each(function (index, file) {
  1403. paths.push(file.path);
  1404. });
  1405. hiddenFields($("#chmodForm"), 'path', paths);
  1406. $("#chmodForm").attr("action", "/filebrowser/chmod?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1407. $("#changePermissionModal").modal({
  1408. keyboard: true,
  1409. show: true
  1410. });
  1411. $('#chmodForm').ajaxForm({
  1412. dataType: 'json',
  1413. success: function() {
  1414. $("#changePermissionModal").modal('hide');
  1415. $(self.selectedFiles()).each(function (index, file) {
  1416. self.filesToHighlight.push(file.path);
  1417. });
  1418. self.retrieveData(true);
  1419. },
  1420. error: function (xhr, textStatus, errorThrown) {
  1421. $(document).trigger("error", xhr.responseText);
  1422. resetPrimaryButtonsStatus();
  1423. }
  1424. });
  1425. // Initial values for form
  1426. var permissions = ["sticky", "user_read", "user_write", "user_execute", "group_read", "group_write", "group_execute", "other_read", "other_write", "other_execute"].reverse();
  1427. var mode = octal(self.selectedFile().mode) & 01777;
  1428. for (var i = 0; i < permissions.length; i++) {
  1429. if (mode & 1) {
  1430. $("#chmodForm input[name=" + permissions[i] + "]").attr("checked", true);
  1431. } else {
  1432. $("#chmodForm input[name=" + permissions[i] + "]").attr("checked", false);
  1433. }
  1434. mode >>>= 1;
  1435. }
  1436. }
  1437. };
  1438. var deleteSelected = function() {
  1439. var paths = [];
  1440. $(self.selectedFiles()).each(function (index, file) {
  1441. paths.push(file.path);
  1442. });
  1443. hiddenFields($("#deleteForm"), 'path', paths);
  1444. $("#deleteForm").attr("action", "/filebrowser/rmtree" + "?" +
  1445. (self.skipTrash() ? "skip_trash=true&" : "") +
  1446. "next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1447. $("#deleteModal").modal({
  1448. keyboard:true,
  1449. show:true
  1450. });
  1451. $('#deleteForm').ajaxForm({
  1452. dataType: 'json',
  1453. success: function() {
  1454. $("#deleteModal").modal('hide');
  1455. window.setTimeout(function () {
  1456. $(self.selectedFiles()).each(function (index, file) {
  1457. file.deleted(true);
  1458. });
  1459. var $scrollable = $(window);
  1460. %if is_embeddable:
  1461. $scrollable = $('.page-content');
  1462. %endif
  1463. if ($('.row-deleted').length > 0 && $('.row-deleted:eq(0)').offset()) {
  1464. $scrollable.scrollTop($('.row-deleted:eq(0)').offset().top - 150);
  1465. }
  1466. }, 500);
  1467. window.setTimeout(function () {
  1468. $(self.selectedFiles()).each(function (index, file) {
  1469. self.files.remove(file);
  1470. });
  1471. self.retrieveData(true);
  1472. }, 1000);
  1473. },
  1474. error: function(xhr, textStatus, errorThrown) {
  1475. $(document).trigger("error", xhr.responseText);
  1476. resetPrimaryButtonsStatus();
  1477. }
  1478. });
  1479. };
  1480. self.deleteSelected = function () {
  1481. self.skipTrash(true);
  1482. deleteSelected();
  1483. };
  1484. self.trashSelected = function () {
  1485. self.skipTrash(false);
  1486. deleteSelected();
  1487. };
  1488. self.submitSelected = function() {
  1489. % if 'oozie' in apps:
  1490. $.get("${ url('oozie:submit_external_job', application_path='/') }../" + self.selectedFile().path, {'format': IS_HUE_4 ? 'json' : 'html'}, function (response) {
  1491. $('#submit-wf-modal').html(response);
  1492. $('#submit-wf-modal').modal('show');
  1493. });
  1494. % else:
  1495. $.jHueNotify.warn("${ _('Submitting is not available as the Oozie app is disabled') }");
  1496. % endif
  1497. };
  1498. self.isArchive = function(fileName) {
  1499. return fileName.endsWith('.zip') || fileName.endsWith('.tar.gz') || fileName.endsWith('.tgz') || fileName.endsWith('.bz2') || fileName.endsWith('.bzip2');
  1500. };
  1501. self.confirmExtractArchive = function() {
  1502. $("#confirmExtractModal").modal({
  1503. keyboard:true,
  1504. show:true
  1505. });
  1506. };
  1507. self.showCompressButton = ko.computed(function() {
  1508. var fileNames = self.selectedFiles().map(function(file) {
  1509. return file.name;
  1510. });
  1511. if (fileNames.indexOf('.') !== -1) {
  1512. return false;
  1513. }
  1514. return self.isCompressEnabled() && (self.selectedFiles().length > 1 || !(self.selectedFiles().length === 1 && self.isArchive(self.selectedFile().name)));
  1515. });
  1516. self.setCompressArchiveDefault = function() {
  1517. if (self.selectedFiles().length == 1) {
  1518. self.compressArchiveName(self.selectedFile().name + '.zip');
  1519. } else {
  1520. if (self.breadcrumbs().length === 1) {
  1521. self.compressArchiveName('root.zip'); // When compressing multiple files in root directory
  1522. }
  1523. else {
  1524. self.compressArchiveName(self.breadcrumbs()[self.breadcrumbs().length - 1].label + '.zip'); // Setting to parent directory name
  1525. }
  1526. }
  1527. };
  1528. self.confirmCompressFiles = function() {
  1529. $("#confirmCompressModal").modal({
  1530. keyboard:true,
  1531. show:true
  1532. });
  1533. };
  1534. self.extractSelectedArchive = function() {
  1535. $("#confirmExtractModal").modal("hide");
  1536. $.post("/filebrowser/extract_archive", {
  1537. "archive_name": self.selectedFile().name,
  1538. "upload_path": self.currentPath(),
  1539. "start_time": ko.mapping.toJSON((new Date()).getTime())
  1540. }, function (data) {
  1541. if (data.status == 0) {
  1542. $.jHueNotify.info("${ _('Task ') }" + data.history_uuid + "${_(' submitted.') }");
  1543. huePubSub.publish('notebook.task.submitted', data.history_uuid);
  1544. } else {
  1545. $(document).trigger("error", data.message);
  1546. }
  1547. }).fail(function (xhr, textStatus, errorThrown) {
  1548. $(document).trigger("error", xhr.responseText);
  1549. });
  1550. };
  1551. self.archiveOverrideWarning = function() {
  1552. $("#confirmCompressModal").modal("hide");
  1553. var fileNames = self.files().map(function(file) {
  1554. return file.name;
  1555. });
  1556. if (fileNames.indexOf(self.compressArchiveName()) !== -1) {
  1557. $("#compressWarningModal").modal("show");
  1558. } else {
  1559. self.compressSelectedFiles();
  1560. }
  1561. }
  1562. self.compressSelectedFiles = function() {
  1563. $("#compressWarningModal").modal("hide");
  1564. var fileNames = [];
  1565. $(self.selectedFiles()).each(function (index, file) {
  1566. fileNames.push(file.name);
  1567. });
  1568. $.post("/filebrowser/compress_files", {
  1569. "files": fileNames,
  1570. "upload_path": self.currentPath(),
  1571. "archive_name": self.compressArchiveName(),
  1572. "start_time": ko.mapping.toJSON((new Date()).getTime())
  1573. }, function (data) {
  1574. if (data.status == 0) {
  1575. $.jHueNotify.info("${ _('Task ') }" + data.history_uuid + "${_(' submitted.') }");
  1576. huePubSub.publish('notebook.task.submitted', data.history_uuid);
  1577. } else {
  1578. $(document).trigger("error", data.message);
  1579. }
  1580. }).fail(function (xhr, textStatus, errorThrown) {
  1581. $(document).trigger("error", xhr.responseText);
  1582. });
  1583. };
  1584. self.createDirectory = function (formElement) {
  1585. $(formElement).attr("action", "/filebrowser/mkdir?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1586. if ($.trim($("#newDirectoryNameInput").val()) == "") {
  1587. $("#directoryNameRequiredAlert").show();
  1588. $("#newDirectoryNameInput").addClass("fieldError");
  1589. resetPrimaryButtonsStatus(); //globally available
  1590. return false;
  1591. }
  1592. if (fileExists($("#newDirectoryNameInput").val())) {
  1593. $("#directoryNameExistsAlert").find(".newName").text($("#newDirectoryNameInput").val());
  1594. $("#directoryNameExistsAlert").show();
  1595. $("#newDirectoryNameInput").addClass("fieldError");
  1596. resetPrimaryButtonsStatus(); //globally available
  1597. return false;
  1598. }
  1599. $(formElement).ajaxSubmit({
  1600. dataType: 'json',
  1601. success: function() {
  1602. self.filesToHighlight.push(self.currentPath() + '/' + $('#newDirectoryNameInput').val());
  1603. $("#createDirectoryModal").modal('hide');
  1604. self.retrieveData(true);
  1605. },
  1606. error: function (xhr, textStatus, errorThrown) {
  1607. $(document).trigger("error", xhr.responseText);
  1608. resetPrimaryButtonsStatus();
  1609. }
  1610. });
  1611. return false;
  1612. };
  1613. self.createFile = function (formElement) {
  1614. $(formElement).attr("action", "/filebrowser/touch?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1615. if ($.trim($("#newFileNameInput").val()) == "") {
  1616. $("#fileNameRequiredAlert").show();
  1617. $("#newFileNameInput").addClass("fieldError");
  1618. resetPrimaryButtonsStatus(); //globally available
  1619. return false;
  1620. }
  1621. if (fileExists($("#newFileNameInput").val())) {
  1622. $("#fileNameExistsAlert").find(".newName").text($("#newFileNameInput").val());
  1623. $("#fileNameExistsAlert").show();
  1624. $("#newFileNameInput").addClass("fieldError");
  1625. resetPrimaryButtonsStatus(); //globally available
  1626. return false;
  1627. }
  1628. $(formElement).ajaxSubmit({
  1629. dataType: 'json',
  1630. success: function() {
  1631. self.filesToHighlight.push(self.currentPath() + '/' + $('#newFileNameInput').val());
  1632. $("#createFileModal").modal('hide');
  1633. self.retrieveData(true);
  1634. },
  1635. error: function (xhr, textStatus, errorThrown) {
  1636. $(document).trigger("error", xhr.responseText);
  1637. resetPrimaryButtonsStatus();
  1638. }
  1639. });
  1640. return false;
  1641. };
  1642. self.restoreTrashSelected = function(formElement) {
  1643. var paths = [];
  1644. $(self.selectedFiles()).each(function (index, file) {
  1645. paths.push(file.path);
  1646. });
  1647. hiddenFields($("#restoreTrashForm"), 'path', paths);
  1648. $("#restoreTrashForm").attr("action", "/filebrowser/trash/restore?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1649. $("#restoreTrashModal").modal({
  1650. keyboard:true,
  1651. show:true
  1652. });
  1653. $('#restoreTrashForm').ajaxForm({
  1654. dataType: 'json',
  1655. success: function() {
  1656. $("#restoreTrashModal").modal('hide');
  1657. self.retrieveData(true);
  1658. },
  1659. error: function(xhr, textStatus, errorThrown) {
  1660. $(document).trigger("error", xhr.responseText);
  1661. resetPrimaryButtonsStatus();
  1662. }
  1663. });
  1664. };
  1665. self.purgeTrash = function(formElement) {
  1666. var paths = [];
  1667. $(self.selectedFiles()).each(function (index, file) {
  1668. paths.push(file.path);
  1669. });
  1670. hiddenFields($("#purgeTrashForm"), 'path', paths);
  1671. $("#purgeTrashForm").attr("action", "/filebrowser/trash/purge?next=${url('filebrowser.views.view', path='')}" + viewModel.homeDir() + "/.Trash");
  1672. $("#purgeTrashModal").modal({
  1673. keyboard:true,
  1674. show:true
  1675. });
  1676. $('#purgeTrashForm').ajaxForm({
  1677. dataType: 'json',
  1678. success: function() {
  1679. $("#purgeTrashModal").modal('hide');
  1680. self.retrieveData(true);
  1681. }
  1682. });
  1683. };
  1684. self.uploadFile = (function () {
  1685. self.pendingUploads(0);
  1686. var action = "/filebrowser/upload/file";
  1687. var uploader = new qq.FileUploader({
  1688. element: document.getElementById("fileUploader"),
  1689. action: action,
  1690. template: '<div class="qq-uploader" style="margin-left: 10px">' +
  1691. '<div class="qq-upload-drop-area"><span>${_('Drop the files here to upload')}</span></div>' +
  1692. '<div class="qq-upload-button qq-no-float">${_('Select files')}</div> &nbsp; <span class="muted">${_('or drag and drop them here')}</span>' +
  1693. '<ul class="qq-upload-list qq-upload-files unstyled qq-no-float" style="margin-right: 0;"></ul>' +
  1694. '</div>',
  1695. fileTemplate: '<li><span class="qq-upload-file-extended" style="display:none"></span><span class="qq-upload-spinner hide" style="display:none"></span>' +
  1696. '<div class="progress-row dz-processing">' +
  1697. '<span class="break-word qq-upload-file"></span>' +
  1698. '<div class="pull-right">' +
  1699. '<span class="muted qq-upload-size"></span>&nbsp;&nbsp;' +
  1700. '<a href="#" title="${_('Cancel')}" class="complex-layout"><i class="fa fa-fw fa-times qq-upload-cancel"></i></a>' +
  1701. '<span class="qq-upload-done" style="display:none"><i class="fa fa-fw fa-check muted"></i></span>' +
  1702. '<span class="qq-upload-failed-text">${_('Failed')}</span>' +
  1703. '</div>' +
  1704. '<div class="progress-row-bar" style="width: 0%;"></div>' +
  1705. '</div></li>',
  1706. params: {
  1707. dest: self.currentPath(),
  1708. fileFieldLabel: "hdfs_file"
  1709. },
  1710. onProgress: function (id, fileName, loaded, total) {
  1711. $('.qq-upload-files').find('li').each(function(){
  1712. var listItem = $(this);
  1713. if (listItem.find('.qq-upload-file-extended').text() == fileName){
  1714. listItem.find('.progress-row-bar').css('width', (loaded/total)*100 + '%');
  1715. }
  1716. });
  1717. },
  1718. onComplete: function (id, fileName, response) {
  1719. self.pendingUploads(self.pendingUploads() - 1);
  1720. if (response.status != 0) {
  1721. $(document).trigger('error', "${ _('Error: ') }" + response.data);
  1722. }
  1723. else {
  1724. $(document).trigger('info', response.path + "${ _(' uploaded successfully.') }");
  1725. self.filesToHighlight.push(response.path);
  1726. }
  1727. if (self.pendingUploads() == 0) {
  1728. $('#uploadFileModal').modal('hide');
  1729. self.retrieveData(true);
  1730. }
  1731. },
  1732. onSubmit: function (id, fileName, responseJSON) {
  1733. self.pendingUploads(self.pendingUploads() + 1);
  1734. },
  1735. onCancel: function (id, fileName) {
  1736. self.pendingUploads(self.pendingUploads() - 1);
  1737. },
  1738. debug: false
  1739. });
  1740. $("#fileUploader").on('fb:updatePath', function (e, options) {
  1741. uploader.setParams({
  1742. dest: options.dest,
  1743. fileFieldLabel: "hdfs_file"
  1744. });
  1745. });
  1746. return function () {
  1747. $("#uploadFileModal").modal({
  1748. show: true
  1749. });
  1750. };
  1751. })();
  1752. // Place all values into hidden fields under parent element.
  1753. // Looks for managed hidden fields and handles sizing appropriately.
  1754. var hiddenFields = function (parentEl, name, values) {
  1755. if (!(parentEl instanceof jQuery)){
  1756. parentEl = $(parentEl);
  1757. }
  1758. parentEl.find("input.hidden-field").remove();
  1759. $(values).each(function (index, value) {
  1760. var field = $("<input type='hidden' />");
  1761. field.attr("name", name);
  1762. field.attr("class", "hidden-field")
  1763. field.val(value);
  1764. parentEl.append(field);
  1765. });
  1766. };
  1767. var octal = function (strInt) {
  1768. return parseInt("0" + strInt, 8);
  1769. };
  1770. };
  1771. // hide the context menu based on specific events
  1772. var hideContextMenu = function () {
  1773. var cm = $('.context-menu');
  1774. if (cm.is(':visible')) {
  1775. cm.css({ display: 'none' });
  1776. }
  1777. };
  1778. var viewModel = new FileBrowserModel([], null, [], "/");
  1779. ko.applyBindings(viewModel, $('.filebrowser')[0]);
  1780. $(document).ready(function () {
  1781. // hide context menu
  1782. $(HUE_CONTAINER).on('click', function (e) {
  1783. hideContextMenu();
  1784. });
  1785. $(HUE_CONTAINER).on('contextmenu', function (e) {
  1786. if ($.inArray(e.toElement, $('.table-huedatatable *')) === -1) {
  1787. hideContextMenu();
  1788. }
  1789. });
  1790. $(HUE_CONTAINER).on('contextmenu', '.context-menu', function (e) {
  1791. hideContextMenu();
  1792. });
  1793. % if show_upload_button:
  1794. // Drag and drop uploads from anywhere on filebrowser screen
  1795. if (window.FileReader) {
  1796. var showHoverMsg = function (msg) {
  1797. $('.filebrowser .hoverText').html(msg);
  1798. $('.filebrowser .hoverMsg').removeClass('hide');
  1799. };
  1800. var hideHoverMsg = function () {
  1801. $('.filebrowser .hoverMsg').addClass('hide');
  1802. };
  1803. var _isDraggingOverText = false,
  1804. // determine if the item dragged originated outside DOM
  1805. _isExternalFile = true;
  1806. $('.filebrowser').on('dragstart', function (e) {
  1807. // External files being dragged into the DOM won't have a dragstart event
  1808. _isExternalFile = false;
  1809. });
  1810. $('.filebrowser').on('dragend', function (e) {
  1811. _isExternalFile = true;
  1812. });
  1813. $('.filebrowser').on('dragenter', function (e) {
  1814. e.preventDefault();
  1815. if (_isExternalFile && !($("#uploadFileModal").is(":visible")) && (!viewModel.isS3() || (viewModel.isS3() && !viewModel.isS3Root()))) {
  1816. showHoverMsg("${_('Drop files here to upload')}");
  1817. }
  1818. });
  1819. $('.filebrowser .hoverText').on('dragenter', function (e) {
  1820. e.preventDefault();
  1821. e.stopPropagation();
  1822. e.stopImmediatePropagation();
  1823. _isDraggingOverText = true;
  1824. });
  1825. $('.filebrowser .hoverText').on('dragleave', function (e) {
  1826. e.preventDefault();
  1827. e.stopPropagation();
  1828. e.stopImmediatePropagation();
  1829. _isDraggingOverText = false;
  1830. _isExternalFile = true;
  1831. });
  1832. $('.filebrowser .hoverMsg').on('dragleave', function (e) {
  1833. if (!_isDraggingOverText) {
  1834. hideHoverMsg();
  1835. }
  1836. });
  1837. $(document).on('currPathLoaded', function (e, ops) {
  1838. try {
  1839. _dropzone.destroy();
  1840. }
  1841. catch (exc) {
  1842. }
  1843. var options = {
  1844. url: '/filebrowser/upload/file?dest=' + encodeURI(ops.path),
  1845. paramName: 'hdfs_file',
  1846. params: {
  1847. dest: ops.path
  1848. },
  1849. autoDiscover: false,
  1850. maxFilesize: 5000000,
  1851. previewsContainer: '#progressStatusContent',
  1852. previewTemplate: '<div class="progress-row">' +
  1853. '<span class="break-word" data-dz-name></span>' +
  1854. '<div class="pull-right">' +
  1855. '<span class="muted" data-dz-size></span>&nbsp;&nbsp;' +
  1856. '<span data-dz-remove><a href="javascript:undefined;" title="' + HUE_I18n.dropzone.cancelUpload + '"><i class="fa fa-fw fa-times"></i></a></span>' +
  1857. '<span style="display: none" data-dz-uploaded><i class="fa fa-fw fa-check muted"></i></span>' +
  1858. '</div>' +
  1859. '<div class="progress-row-bar" data-dz-uploadprogress></div>' +
  1860. '</div>',
  1861. drop: function (e) {
  1862. $('.filebrowser .hoverMsg').addClass('hide');
  1863. // Ensure dropped item was a file
  1864. if (e.dataTransfer.files.length > 0) {
  1865. $('#progressStatus').removeClass('hide');
  1866. $('#progressStatusBar').removeClass('hide');
  1867. $('#progressStatus .progress-row').remove();
  1868. $('#progressStatusBar div').css('width', '0');
  1869. }
  1870. },
  1871. processing: function (file) {
  1872. var newDest = ops.path;
  1873. if (file.fullPath) {
  1874. newDest = ops.path + '/' + file.fullPath.substr(0, file.fullPath.length - file.name.length);
  1875. }
  1876. this.options.params.dest = newDest;
  1877. this.options.url = '/filebrowser/upload/file?dest=' + encodeURI(newDest);
  1878. },
  1879. uploadprogress: function (file, progress) {
  1880. $('[data-dz-name]').each(function (cnt, item) {
  1881. if ($(item).text() === file.name) {
  1882. $(item).parents('.progress-row').find('[data-dz-uploadprogress]').width(progress.toFixed() + '%');
  1883. if (progress.toFixed() === '100') {
  1884. $(item).parents('.progress-row').find('[data-dz-remove]').hide();
  1885. $(item).parents('.progress-row').find('[data-dz-uploaded]').show();
  1886. }
  1887. }
  1888. });
  1889. },
  1890. totaluploadprogress: function (progress) {
  1891. $('#progressStatusBar div').width(progress.toFixed() + "%");
  1892. },
  1893. canceled: function () {
  1894. $.jHueNotify.info(HUE_I18n.dropzone.uploadCanceled);
  1895. },
  1896. complete: function (data) {
  1897. if (data.xhr.response != '') {
  1898. var response = JSON.parse(data.xhr.response);
  1899. if (response && response.status != null) {
  1900. if (response.status != 0) {
  1901. $(document).trigger('error', response.data);
  1902. } else {
  1903. $(document).trigger('info', response.path + ' ' + HUE_I18n.dropzone.uploadSucceeded);
  1904. viewModel.filesToHighlight.push(response.path);
  1905. }
  1906. }
  1907. }
  1908. }
  1909. };
  1910. if (ops.path.toLowerCase() !== 's3a://') {
  1911. _dropzone = new Dropzone($('.filebrowser .hoverMsg')[0], options);
  1912. _dropzone.on('queuecomplete', function () {
  1913. setTimeout(function () {
  1914. $('#progressStatus').addClass('hide');
  1915. $('#progressStatusBar').addClass('hide');
  1916. $('#progressStatusBar div').css("width", "0");
  1917. viewModel.retrieveData(true);
  1918. },
  1919. 2500);
  1920. });
  1921. }
  1922. });
  1923. }
  1924. % endif
  1925. $("#chownForm select[name='user']").change(function () {
  1926. if ($(this).val() == "__other__") {
  1927. $("input[name='user_other']").show();
  1928. } else {
  1929. $("input[name='user_other']").hide();
  1930. }
  1931. });
  1932. $("#chownForm select[name='group']").change(function () {
  1933. if ($(this).val() == "__other__") {
  1934. $("input[name='group_other']").show();
  1935. } else {
  1936. $("input[name='group_other']").hide();
  1937. }
  1938. });
  1939. $("#chownForm").submit(function () {
  1940. if ($("#chownForm select[name='user']").val() == null) {
  1941. $("#chownRequired").find(".label").text("${_('User is required.')}");
  1942. $("#chownRequired").show();
  1943. resetPrimaryButtonsStatus(); //globally available
  1944. return false;
  1945. } else if ($("#chownForm select[name='group']").val() == null) {
  1946. $("#chownRequired").find(".label").text("${_('Group is required.')}");
  1947. $("#chownRequired").show();
  1948. resetPrimaryButtonsStatus(); //globally available
  1949. return false;
  1950. } else {
  1951. if ($("#chownForm select[name='group']").val() == "__other__" && $("input[name='group_other']").val() == "") {
  1952. $("#chownRequired").find(".label").text("${_('Specify another group.')}");
  1953. $("#chownForm input[name='group_other']").addClass("fieldError");
  1954. $("#chownRequired").show();
  1955. resetPrimaryButtonsStatus(); //globally available
  1956. return false;
  1957. }
  1958. if ($("#chownForm select[name='user']").val() == "__other__" && $("input[name='user_other']").val() == "") {
  1959. $("#chownRequired").find(".label").text("${_('Specify another user.')}");
  1960. $("#chownForm input[name='user_other']").addClass("fieldError");
  1961. $("#chownRequired").show();
  1962. return false;
  1963. resetPrimaryButtonsStatus(); //globally available
  1964. }
  1965. return true;
  1966. }
  1967. });
  1968. // Modal file chooser
  1969. // The file chooser should be at least 2 levels deeper than the modal container
  1970. $(".fileChooserBtn").on('click', function (e) {
  1971. e.preventDefault();
  1972. var _destination = $(this).attr("data-filechooser-destination");
  1973. var fileChooser = $(this).parent().parent().find(".fileChooserModal");
  1974. fileChooser.jHueFileChooser({
  1975. initialPath:$("input[name='" + _destination + "']").val(),
  1976. onFolderChange:function (folderPath) {
  1977. $("input[name='" + _destination + "']").val(folderPath);
  1978. },
  1979. onFolderChoose:function (folderPath) {
  1980. $("input[name='" + _destination + "']").val(folderPath);
  1981. fileChooser.slideUp();
  1982. },
  1983. selectFolder:true,
  1984. createFolder:true,
  1985. uploadFile:false
  1986. });
  1987. fileChooser.slideDown();
  1988. });
  1989. $("#renameForm").submit(function () {
  1990. if ($("#newNameInput").val() == "") {
  1991. $("#renameNameRequiredAlert").show();
  1992. $("#newNameInput").addClass("fieldError");
  1993. resetPrimaryButtonsStatus(); //globally available
  1994. return false;
  1995. }
  1996. if (fileExists($("#newNameInput").val())) {
  1997. $("#renameNameExistsAlert").find(".newName").text($("#newNameInput").val());
  1998. $("#renameNameExistsAlert").show();
  1999. $("#newNameInput").addClass("fieldError");
  2000. resetPrimaryButtonsStatus(); //globally available
  2001. return false;
  2002. }
  2003. return true;
  2004. });
  2005. $("#newNameInput").focus(function () {
  2006. $("#renameNameRequiredAlert").hide();
  2007. $("#renameNameExistsAlert").hide();
  2008. $("#newNameInput").removeClass("fieldError");
  2009. });
  2010. $("#moveForm").on("submit", function () {
  2011. if ($.trim($("#moveDestination").val()) == "") {
  2012. $("#moveNameRequiredAlert").show();
  2013. $("#moveForm").find("input[name='*dest_path']").addClass("fieldError");
  2014. resetPrimaryButtonsStatus(); //globally available
  2015. return false;
  2016. }
  2017. var isMoveOnSelf = false;
  2018. $(viewModel.selectedFiles()).each(function (index, file) {
  2019. if (file.path == $('#moveDestination').val()) {
  2020. isMoveOnSelf = true;
  2021. return false;
  2022. }
  2023. });
  2024. if(isMoveOnSelf){
  2025. $.jHueNotify.warn("${ _('You cannot copy a folder into itself.') }");
  2026. $('#moveDestination').val('');
  2027. return false;
  2028. }
  2029. return true;
  2030. });
  2031. $("#moveForm").bind("keypress", function(e) {
  2032. if (e.keyCode == 13) {
  2033. return false;
  2034. }
  2035. });
  2036. $("#setReplicationFactorForm").submit(function () {
  2037. if ($("#newRepFactorInput").val() == "") {
  2038. $("#replicationFactorRequiredAlert").show();
  2039. $("#newRepFactorInput").addClass("fieldError");
  2040. resetPrimaryButtonsStatus(); //globally available
  2041. return false;
  2042. }
  2043. });
  2044. $("#newRepFactorInput").focus(function () {
  2045. $("#replicationFactorRequiredAlert").hide();
  2046. $("#newRepFactorInput").removeClass("fieldError");
  2047. });
  2048. huePubSub.subscribe('fb.' + viewModel.fs() + '.refresh', function (path) {
  2049. if (path === viewModel.currentPath()) {
  2050. viewModel.retrieveData();
  2051. }
  2052. }, 'filebrowser');
  2053. huePubSub.subscribe('update.autocompleters', function(){
  2054. $("#moveDestination").jHueHdfsAutocomplete({
  2055. showOnFocus: true,
  2056. skipEnter: true,
  2057. skipKeydownEvents: true,
  2058. onEnter: function (el) {
  2059. $("#jHueHdfsAutocomplete").hide();
  2060. },
  2061. isS3: viewModel.isS3(),
  2062. root: viewModel.rootCurrent()
  2063. });
  2064. $("#copyDestination").jHueHdfsAutocomplete({
  2065. showOnFocus: true,
  2066. skipEnter: true,
  2067. skipKeydownEvents: true,
  2068. onEnter: function (el) {
  2069. $("#jHueHdfsAutocomplete").hide();
  2070. },
  2071. isS3: viewModel.isS3(),
  2072. root: viewModel.rootCurrent()
  2073. });
  2074. });
  2075. huePubSub.subscribe('submit.popup.return', function (data) {
  2076. if (data.type == 'external_workflow') {
  2077. $.jHueNotify.info('${_('Workflow submitted.')}');
  2078. huePubSub.publish('open.link', '/jobbrowser/#!id=' + data.job_id);
  2079. huePubSub.publish('browser.job.open.link', data.job_id);
  2080. $('.submit-modal').modal('hide');
  2081. $('.modal-backdrop').hide();
  2082. }
  2083. }, 'filebrowser');
  2084. $("#copyForm").on("submit", function () {
  2085. if ($.trim($("#copyDestination").val()) == "") {
  2086. $("#copyNameRequiredAlert").show();
  2087. $("#copyForm").find("input[name='*dest_path']").addClass("fieldError");
  2088. resetPrimaryButtonsStatus(); //globally available
  2089. return false;
  2090. }
  2091. return true;
  2092. });
  2093. $("#copyForm").bind("keypress", function(e) {
  2094. if (e.keyCode == 13) {
  2095. return false;
  2096. }
  2097. });
  2098. huePubSub.publish('update.autocompleters');
  2099. $(".create-directory-link").click(function () {
  2100. $("#newDirectoryNameInput").val('');
  2101. $("#createDirectoryModal").modal({
  2102. keyboard:true,
  2103. show:true
  2104. });
  2105. });
  2106. $(".create-file-link").click(function () {
  2107. $("#newFileNameInput").val('');
  2108. $("#createFileModal").modal({
  2109. keyboard:true,
  2110. show:true
  2111. });
  2112. });
  2113. $("#newDirectoryNameInput").focus(function () {
  2114. $("#newDirectoryNameInput").removeClass("fieldError");
  2115. $("#directoryNameRequiredAlert").hide();
  2116. $("#directoryNameExistsAlert").hide();
  2117. });
  2118. $("#newFileNameInput").focus(function () {
  2119. $("#newFileNameInput").removeClass("fieldError");
  2120. $("#fileNameRequiredAlert").hide();
  2121. $("#fileNameExistsAlert").hide();
  2122. });
  2123. $(".pathChooser").click(function () {
  2124. var self = this;
  2125. $("#fileChooserRename").jHueFileChooser({
  2126. initialPath:$(self).val(),
  2127. onFileChoose:function (filePath) {
  2128. $(self).val(filePath);
  2129. },
  2130. onFolderChange:function (folderPath) {
  2131. $(self).val(folderPath);
  2132. },
  2133. createFolder:false,
  2134. uploadFile:false
  2135. });
  2136. $("#fileChooserRename").slideDown();
  2137. });
  2138. $("*[rel='tooltip']").tooltip({ placement:"bottom" });
  2139. var hashchange = function () {
  2140. if (window.location.pathname.indexOf('/filebrowser') > -1) {
  2141. var targetPath = "";
  2142. var hash = window.location.hash.substring(1);
  2143. if (hash.search(/(<([^>]+)>)/ig) > -1) {
  2144. hash = encodeURI(hash);
  2145. }
  2146. if (hash != null && hash != "" && hash.indexOf('/') > -1) {
  2147. targetPath = "${url('filebrowser.views.view', path='')}";
  2148. if (hash.indexOf("!!") != 0) {
  2149. targetPath += stripHashes(hash);
  2150. }
  2151. else {
  2152. targetPath = viewModel.targetPath() + hash;
  2153. }
  2154. viewModel.targetPageNum(1)
  2155. }
  2156. if (window.location.href.indexOf("#") == -1) {
  2157. viewModel.targetPageNum(1);
  2158. targetPath = "${current_request_path | n,unicode }";
  2159. }
  2160. if (targetPath != "") {
  2161. viewModel.targetPath(targetPath);
  2162. viewModel.retrieveData();
  2163. }
  2164. }
  2165. }
  2166. huePubSub.subscribe('fb.update.hash', hashchange, 'filebrowser');
  2167. if (window.location.hash != null && window.location.hash.length > 1) {
  2168. hashchange();
  2169. }
  2170. else {
  2171. viewModel.retrieveData();
  2172. }
  2173. $("#editBreadcrumb").click(function (e) {
  2174. if ($(e.target).is('ul')){
  2175. $(this).hide();
  2176. $(".hue-breadcrumbs").hide();
  2177. $("#hueBreadcrumbText").show().focus();
  2178. }
  2179. });
  2180. $("#hueBreadcrumbText").jHueHdfsAutocomplete({
  2181. home: "/user/${ user }/",
  2182. root: viewModel.rootTarget(),
  2183. skipKeydownEvents: true,
  2184. onEnter: function (el) {
  2185. viewModel.targetPath("${url('filebrowser.views.view', path='')}" + stripHashes(el.val()));
  2186. viewModel.getStats(function (data) {
  2187. if (data.type != null && data.type == "file") {
  2188. %if is_embeddable:
  2189. huePubSub.publish('open.link', data.url);
  2190. %else:
  2191. window.location.href = data.url;
  2192. %endif
  2193. return false;
  2194. } else {
  2195. updateHash(stripHashes(el.val()));
  2196. }
  2197. $("#jHueHdfsAutocomplete").hide();
  2198. });
  2199. },
  2200. onBlur: function() {
  2201. $("#hueBreadcrumbText").hide();
  2202. $(".hue-breadcrumbs").show();
  2203. $("#editBreadcrumb").show();
  2204. },
  2205. smartTooltip: "${_('Did you know? You can use the tab key or CTRL + Space to autocomplete file and folder names')}"
  2206. });
  2207. $.ajaxSetup({
  2208. error:function (x, e) {
  2209. if (x.status == 500 && x.responseText.indexOf("jobbrowser") == -1) {
  2210. if (x.responseJSON && x.responseJSON.detail) {
  2211. $(document).trigger("error", x.responseJSON.detail);
  2212. }
  2213. else {
  2214. $(document).trigger("error", "${_('There was a problem with your request.')}");
  2215. }
  2216. $("#hueBreadcrumbText").blur();
  2217. }
  2218. }
  2219. });
  2220. $(window).bind("hashchange.fblist", hashchange);
  2221. $(".actionbar").data("originalWidth", $(".actionbar").width());
  2222. $(".actionbarGhost").height($(".actionbar").outerHeight());
  2223. resetActionbar();
  2224. %if is_embeddable:
  2225. $('.page-content').scroll(function () {
  2226. if ($('.page-content').scrollTop() > 50) {
  2227. $(".actionbar").width($(".actionbar").data("originalWidth"));
  2228. $(".actionbar").css("position", "fixed").css("top", "50px").css("zIndex", "1001");
  2229. $(".actionbarGhost").removeClass("hide");
  2230. } else {
  2231. resetActionbar();
  2232. }
  2233. });
  2234. %else:
  2235. $(window).scroll(function () {
  2236. if ($(window).scrollTop() > 20) {
  2237. $(".actionbar").width($(".actionbar").data("originalWidth"));
  2238. $(".actionbar").css("position", "fixed").css("top", "73px").css("zIndex", "1001");
  2239. $(".actionbarGhost").removeClass("hide");
  2240. } else {
  2241. resetActionbar();
  2242. }
  2243. });
  2244. %endif
  2245. $("#uploadFileModal").on("shown", function () {
  2246. if (typeof _dropzone != "undefined") {
  2247. _dropzone.disable();
  2248. }
  2249. });
  2250. $("#uploadFileModal").on("hidden", function () {
  2251. if (typeof _dropzone != "undefined") {
  2252. _dropzone.enable();
  2253. }
  2254. $(".qq-upload-list").empty();
  2255. $(".qq-upload-drop-area").hide();
  2256. });
  2257. });
  2258. </script>
  2259. </%def>