listdir_components.mako 77 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058
  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. %>
  23. <%namespace name="edit" file="editor_components.mako" />
  24. <%def name="list_table_chooser(files, path, current_request_path)">
  25. ${_table(files, path, current_request_path, 'chooser')}
  26. </%def>
  27. <%def name="list_table_browser(files, path, current_request_path, show_download_button, cwd_set=True)">
  28. ${_table(files, path, current_request_path, 'view', show_download_button)}
  29. </%def>
  30. <%def name="_table(files, path, current_request_path, view, show_download_button)">
  31. <link href="${ static('filebrowser/css/listdir_components.css') }" rel="stylesheet" type="text/css">
  32. <div data-bind="visible: isLoading">
  33. <i class="fa fa-spinner fa-spin hue-spinner-large hue-spinner-center muted"></i>
  34. </div>
  35. <table class="table table-condensed datatables tablescroller-disable" data-bind="style: {'opacity': isLoading() ? '.5': '1'}">
  36. <thead>
  37. <tr>
  38. <th width="1%"><div data-bind="click: selectAll, css: {hueCheckbox: true, 'fa': true, 'fa-check': allSelected}" class="select-all"></div></th>
  39. <th class="sortable sorting" data-sort="type" width="1%" data-bind="click: sort">&nbsp;</th>
  40. <th class="sortable sorting_asc" data-sort="name" data-bind="click: sort">${_('Name')}</th>
  41. <th class="sortable sorting" data-sort="size" width="10%" data-bind="click: sort">${_('Size')}</th>
  42. <th class="sortable sorting" data-sort="user" width="10%" data-bind="click: sort">${_('User')}</th>
  43. <th class="sortable sorting" data-sort="group" width="10%" data-bind="click: sort">${_('Group')}</th>
  44. <th width="10%">${_('Permissions')}</th>
  45. <th class="sortable sorting" data-sort="mtime" width="15%" data-bind="click: sort">${_('Date')}</th>
  46. </tr>
  47. </thead>
  48. <tbody id="files" data-bind="template: {name: 'fileTemplate', foreach: files}"></tbody>
  49. <tfoot>
  50. <tr data-bind="visible: files().length === 0 && !isLoading()">
  51. <td colspan="8">
  52. <div class="alert">
  53. ${_('There are no files matching the search criteria.')}
  54. </div>
  55. </td>
  56. </tr>
  57. </tfoot>
  58. </table>
  59. <div class="pagination">
  60. <div class="pull-right flush-right">
  61. <div class="form-inline pagination-input-form inline">
  62. <span>${_('Page')}</span>
  63. <input type="text" data-bind="value: page().number, valueUpdate: 'afterkeydown', event: { change: skipTo }" class="pagination-input" />
  64. <input type="hidden" id="current_page" data-bind="value: page().number" />
  65. of <span data-bind="text: page().num_pages"></span>
  66. </div>
  67. <ul class="inline">
  68. <li class="first-page prev" data-bind="css: { 'disabled': (page().number === page().start_index || page().num_pages <= 1) }">
  69. <a href="javascript:void(0);" data-bind="click: firstPage" title="${_('First page')}"><i class="fa fa-fast-backward"></i></a>
  70. </li>
  71. <li class="previous-page" data-bind="css: { 'disabled': (page().number === page().start_index || page().num_pages <= 1) }">
  72. <a href="javascript:void(0);" data-bind="click: previousPage" title="${_('Previous page')}"><i class="fa fa-backward"></i></a>
  73. </li>
  74. <li class="next-page" data-bind="css: { 'disabled': page().number === page().num_pages }">
  75. <a href="javascript:void(0);" data-bind="click: nextPage" title="${_('Next page')}"><i class="fa fa-forward"></i></a>
  76. </li>
  77. <li class="last-page next" data-bind="css: { 'disabled': page().number === page().num_pages }">
  78. <a href="javascript:void(0);" data-bind="click: lastPage" title="${_('Last page')}"><i class="fa fa-fast-forward"></i></a>
  79. </li>
  80. </ul>
  81. </div>
  82. <p>${_('Show')}
  83. <select class="input-mini" data-bind="options: recordsPerPageChoices, value: recordsPerPage"></select>
  84. ${_('of')} <span data-bind="text: page().total_count"></span> ${_('items')}
  85. </p>
  86. </div>
  87. <!-- delete modal -->
  88. <div id="deleteModal" class="modal hide fade">
  89. <div class="modal-header">
  90. <a href="#" class="close" data-dismiss="modal">&times;</a>
  91. <h3>${_('Confirm Delete')}</h3>
  92. </div>
  93. <div class="modal-body">
  94. <p>${_('Are you sure you want to delete these files?')}</p>
  95. </div>
  96. <div class="modal-footer">
  97. <form id="deleteForm" action="/filebrowser/rmtree" method="POST" enctype="multipart/form-data" class="form-stacked">
  98. ${ csrf_token(request) | n,unicode }
  99. <a class="btn" data-dismiss="modal">${_('No')}</a>
  100. <input type="submit" value="${_('Yes')}" class="btn btn-danger" />
  101. </form>
  102. </div>
  103. </div>
  104. <!-- restore modal -->
  105. <div id="restoreTrashModal" class="modal hide fade">
  106. <div class="modal-header">
  107. <a href="#" class="close" data-dismiss="modal">&times;</a>
  108. <h3>${_('Confirm Restore')}</h3>
  109. </div>
  110. <div class="modal-body">
  111. <p>${_('Are you sure you want to restore these files?')}</p>
  112. </div>
  113. <div class="modal-footer">
  114. <form id="restoreTrashForm" action="/filebrowser/trash/restore" method="POST" enctype="multipart/form-data" class="form-stacked">
  115. ${ csrf_token(request) | n,unicode }
  116. <a class="btn" data-dismiss="modal">${_('No')}</a>
  117. <input type="submit" value="${_('Yes')}" class="btn btn-primary" />
  118. </form>
  119. </div>
  120. </div>
  121. <!-- purge modal -->
  122. <div id="purgeTrashModal" class="modal hide fade">
  123. <div class="modal-header">
  124. <a href="#" class="close" data-dismiss="modal">&times;</a>
  125. <h3>${_('Confirm empty trash')}</h3>
  126. </div>
  127. <div class="modal-body">
  128. <p>${_('Are you sure you want to permanently delete all your trash?')}</p>
  129. </div>
  130. <div class="modal-footer">
  131. <form id="purgeTrashForm" action="/filebrowser/trash/purge" method="POST" enctype="multipart/form-data" class="form-stacked">
  132. ${ csrf_token(request) | n,unicode }
  133. <a class="btn" data-dismiss="modal">${_('Cancel')}</a>
  134. <input type="submit" value="${_('Delete all')}" class="btn btn-danger" />
  135. </form>
  136. </div>
  137. </div>
  138. <!-- rename modal -->
  139. <div id="renameModal" class="modal hide fade">
  140. <form id="renameForm" action="/filebrowser/rename?next=${current_request_path | n,unicode }" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  141. ${ csrf_token(request) | n,unicode }
  142. <div class="modal-header">
  143. <a href="#" class="close" data-dismiss="modal">&times;</a>
  144. <h3>${_('Renaming:')} <span id="renameFileName">file name</span></h3>
  145. </div>
  146. <div class="modal-body">
  147. <label>${_('New name')} <input id="newNameInput" name="dest_path" value="" type="text" class="input-xlarge"/></label>
  148. </div>
  149. <div class="modal-footer">
  150. <div id="renameNameRequiredAlert" class="hide" style="position: absolute; left: 10px;">
  151. <span class="label label-important">${_('Name is required.')}</span>
  152. </div>
  153. <div id="renameNameExistsAlert" class="hide" style="position: absolute; left: 10px;">
  154. <span class="label label-important"><span class="newName"></span> ${_('already exists.')}</span>
  155. </div>
  156. <input id="renameSrcPath" type="hidden" name="src_path" type="text">
  157. <a class="btn" data-dismiss="modal">${_('Cancel')}</a>
  158. <input type="submit" value="${_('Rename')}" class="btn btn-primary" />
  159. </div>
  160. </form>
  161. </div>
  162. <!-- chown modal -->
  163. % if is_fs_superuser:
  164. <div id="changeOwnerModal" class="modal hide fade">
  165. <%
  166. select_filter = is_fs_superuser and 'SelectWithOther' or ''
  167. %>
  168. <form id="chownForm" action="/filebrowser/chown" method="POST" enctype="multipart/form-data" class="form-stacked form-padding-fix">
  169. ${ csrf_token(request) | n,unicode }
  170. <div class="modal-header">
  171. <a href="#" class="close" data-dismiss="modal">&times;</a>
  172. <h3>${_('Change Owner/Group')}</h3>
  173. </div>
  174. <div class="modal-body change-owner-modal-body clearfix" >
  175. <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>
  176. <div style="padding-left: 15px; padding-bottom: 10px;">
  177. <label>${_('User')}</label>
  178. ${ edit.selection("user", users, user.username, "user_other") }
  179. <label>${_('Group')}</label>
  180. ${ edit.selection("group", groups, 'supergroup', "group_other") }
  181. <br />
  182. <label style="display: inline;">${_('Recursive')}</label> <input type="checkbox" name="recursive" style="margin-bottom:4px">
  183. </div>
  184. </div>
  185. <div class="modal-footer" style="padding-top: 10px;">
  186. <div id="chownRequired" class="hide" style="position: absolute; left: 10px;">
  187. <span class="label label-important">${_('Name is required.')}</span>
  188. </div>
  189. <a class="btn" onclick="$('#changeOwnerModal').modal('hide');">${_('Cancel')}</a>
  190. <input class="btn btn-primary" type="submit" value="${_('Submit')}" />
  191. </div>
  192. </form>
  193. </div>
  194. % endif
  195. <!-- chmod modal -->
  196. <div id="changePermissionModal" class="modal hide fade">
  197. <form action="/filebrowser/chmod" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix" id="chmodForm">
  198. ${ csrf_token(request) | n,unicode }
  199. <div class="modal-header">
  200. <a href="#" class="close" data-dismiss="modal">&times;</a>
  201. <h3>${_('Change Permissions:')} </h3>
  202. </div>
  203. <div class="modal-body table-margin">
  204. <table class="table table-striped">
  205. <thead>
  206. <tr>
  207. <th>&nbsp;</th>
  208. <th class="center">${_('User')}</th>
  209. <th class="center">${_('Group')}</th>
  210. <th class="center">${_('Other')}</th>
  211. <th class="center">&nbsp;</th>
  212. <th width="120">&nbsp</th>
  213. </tr>
  214. </thead>
  215. <tbody>
  216. <tr>
  217. <td><strong>${_('Read')}</strong></td>
  218. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="user_read"></td>
  219. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="group_read"></td>
  220. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="other_read"></td>
  221. <td colspan="2">&nbsp;</td>
  222. </tr>
  223. <tr>
  224. <td><strong>${_('Write')}</strong></td>
  225. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="user_write"></td>
  226. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="group_write"></td>
  227. <td class="center"><input type="checkbox" data-bind="attr: {checked: selectedFile.mode }" checked="" name="other_write"></td>
  228. <td colspan="2">&nbsp;</td>
  229. </tr>
  230. <tr>
  231. <td><strong>${_('Execute')}</strong></td>
  232. <td class="center"><input type="checkbox" checked="" name="user_execute"></td>
  233. <td class="center"><input type="checkbox" checked="" name="group_execute"></td>
  234. <td class="center"><input type="checkbox" checked="" name="other_execute"></td>
  235. <td colspan="2">&nbsp;</td>
  236. </tr>
  237. <tr>
  238. <td><strong>${_('Sticky')}</strong></td>
  239. <td colspan="3">&nbsp;</td>
  240. <td class="center"><input type="checkbox" name="sticky"></td>
  241. <td>&nbsp;</td>
  242. </tr>
  243. <tr>
  244. <td><strong>${_('Recursive')}</strong></td>
  245. <td colspan="3">&nbsp;</td>
  246. <td class="center"><input type="checkbox" name="recursive"></td>
  247. <td>&nbsp;</td>
  248. </tr>
  249. </tbody>
  250. </table>
  251. </div>
  252. <div class="modal-footer" style="padding-top: 10px;">
  253. <a class="btn" onclick="$('#changePermissionModal').modal('hide');">${_('Cancel')}</a>
  254. <input class="btn btn-primary" type="submit" value="${_('Submit')}"/>
  255. </div>
  256. </form>
  257. </div>
  258. <!-- move modal -->
  259. <div id="moveModal" class="modal hide fade">
  260. <form id="moveForm" action="/filebrowser/move" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  261. ${ csrf_token(request) | n,unicode }
  262. <div class="modal-header" style="padding-bottom: 10px">
  263. <a href="#" class="close" data-dismiss="modal">&times;</a>
  264. <h3>${_('Move to')}</h3>
  265. </div>
  266. <div class="modal-body">
  267. <div id="moveHdfsTree" style="padding-left: 15px;"></div>
  268. </div>
  269. <div class="modal-footer">
  270. <div>
  271. <input type="text" class="input-xlarge disable-autofocus" value="" name="dest_path" id="moveDestination" placeholder="${_('Select a folder or paste a path...')}" />
  272. <span id="moveNameRequiredAlert" class="hide label label-important">${_('Required')}</span>
  273. </div>
  274. <a class="btn" onclick="$('#moveModal').modal('hide');">${_('Cancel')}</a>
  275. <input class="btn btn-primary disable-enter" type="submit" value="${_('Move')}"/>
  276. </div>
  277. </form>
  278. </div>
  279. <!-- copy modal -->
  280. <div id="copyModal" class="modal hide fade">
  281. <form id="copyForm" action="/filebrowser/copy" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  282. ${ csrf_token(request) | n,unicode }
  283. <div class="modal-header" style="padding-bottom: 10px">
  284. <a href="#" class="close" data-dismiss="modal">&times;</a>
  285. <h3>${_('Copy to')}</h3>
  286. </div>
  287. <div class="modal-body">
  288. <div id="copyHdfsTree"></div>
  289. </div>
  290. <div class="modal-footer">
  291. <div>
  292. <input type="text" class="input-xlarge disable-autofocus" value="" name="dest_path" id="copyDestination" placeholder="${_('Select a folder or paste a path...')}" />
  293. <span id="copyNameRequiredAlert" class="hide label label-important">${_('Required')}</span>
  294. </div>
  295. <a class="btn" onclick="$('#copyModal').modal('hide');">${_('Cancel')}</a>
  296. <input class="btn btn-primary disable-enter" type="submit" value="${_('Copy')}"/>
  297. </div>
  298. </form>
  299. </div>
  300. <!-- upload file modal -->
  301. <div id="uploadFileModal" class="modal hide fade" data-backdrop="static">
  302. <div class="modal-header">
  303. <a href="#" class="close" data-dismiss="modal" data-bind="visible: pendingUploads() == 0">&times;</a>
  304. <h3>${_('Upload to')} <span id="uploadDirName" data-bind="text: currentPath"></span></h3>
  305. </div>
  306. <div class="modal-body form-inline">
  307. <div id="fileUploader" class="uploader">
  308. <noscript>
  309. <p>${_('Enable JavaScript to use the file uploader.')}</p>
  310. </noscript>
  311. </div>
  312. </div>
  313. <div class="modal-footer"></div>
  314. </div>
  315. <!-- upload archive modal -->
  316. <div id="uploadArchiveModal" class="modal hide fade">
  317. <div class="modal-header">
  318. <a href="#" class="close" data-dismiss="modal" data-bind="visible: pendingUploads() == 0">&times;</a>
  319. <h3>${_('Upload and extract in')} <span id="uploadDirName" data-bind="text: currentPath"></span></h3>
  320. </div>
  321. <div class="modal-body form-inline">
  322. <div id="archiveUploader" class="uploader">
  323. <noscript>
  324. <p>${_('Enable JavaScript to use the file uploader.')}</p>
  325. </noscript>
  326. </div>
  327. </div>
  328. <div class="modal-footer"></div>
  329. </div>
  330. <!-- new directory modal -->
  331. <div id="createDirectoryModal" class="modal hide fade">
  332. <form id="createDirectoryForm" data-bind="submit: createDirectory" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  333. ${ csrf_token(request) | n,unicode }
  334. <div class="modal-header">
  335. <a href="#" class="close" data-dismiss="modal">&times;</a>
  336. <h3>${_('Create Directory')}</h3>
  337. </div>
  338. <div class="modal-body">
  339. <label>${_('Directory Name')} <input id="newDirectoryNameInput" name="name" value="" type="text" class="input-xlarge"/></label>
  340. <input type="hidden" name="path" type="text" data-bind="value: currentPath"/>
  341. </div>
  342. <div class="modal-footer">
  343. <div id="directoryNameRequiredAlert" class="hide" style="position: absolute; left: 10px;">
  344. <span class="label label-important">${_('Directory name is required.')}</span>
  345. </div>
  346. <div id="directoryNameExistsAlert" class="hide" style="position: absolute; left: 10px;">
  347. <span class="label label-important"><span class="newName"></span> ${_('already exists.')}</span>
  348. </div>
  349. <a class="btn" href="#" data-dismiss="modal">${_('Cancel')}</a>
  350. <input class="btn btn-primary" type="submit" value="${_('Create')}" />
  351. </div>
  352. </form>
  353. </div>
  354. <!-- new file modal -->
  355. <div id="createFileModal" class="modal hide fade">
  356. <form id="createFileForm" data-bind="submit: createFile" method="POST" enctype="multipart/form-data" class="form-inline form-padding-fix">
  357. ${ csrf_token(request) | n,unicode }
  358. <div class="modal-header">
  359. <a href="#" class="close" data-dismiss="modal">&times;</a>
  360. <h3>${_('Create File')}</h3>
  361. </div>
  362. <div class="modal-body">
  363. <label>${_('File Name')} <input id="newFileNameInput" name="name" value="" type="text" class="input-xlarge"/></label>
  364. <input type="hidden" name="path" type="text" data-bind="value: currentPath"/>
  365. </div>
  366. <div class="modal-footer">
  367. <div id="fileNameRequiredAlert" class="alert-message error hide" style="position: absolute; left: 10px;">
  368. <span class="label label-important">${_('File name is required.')}</span>
  369. </div>
  370. <div id="fileNameExistsAlert" class="hide" style="position: absolute; left: 10px;">
  371. <span class="label label-important"><span class="newName"></span> ${_('already exists.')}</span>
  372. </div>
  373. <a class="btn" href="#" data-dismiss="modal">${_('Cancel')}</a>
  374. <input class="btn btn-primary" type="submit" value="${_('Create')}" />
  375. </div>
  376. </form>
  377. </div>
  378. <!-- content summary modal -->
  379. <div id="contentSummaryModal" class="modal hide fade">
  380. <div class="modal-header">
  381. <a href="#" class="close" data-dismiss="modal">&times;</a>
  382. <!-- ko if: selectedFile -->
  383. <h3 style="word-break: break-all">${_('Summary for')} <span data-bind="text: selectedFile().path"></span></h3>
  384. <!--/ko -->
  385. </div>
  386. <div class="modal-body">
  387. <div data-bind="visible: isLoadingSummary"><i class="fa fa-spin fa-spinner fa-2x fa-fw" style="color: #CCC"></i></div>
  388. <table class="table table-striped" data-bind="visible: !isLoadingSummary()">
  389. <tr>
  390. <th>${ _('Disk space consumed') }</th>
  391. <td data-bind="text: formatBytes(contentSummary().spaceConsumed(), 4)"></td>
  392. </tr>
  393. <tr>
  394. <th>${ _('Bytes used') }</th>
  395. <td data-bind="text: formatBytes(contentSummary().length(), 4)"></td>
  396. </tr>
  397. <tr>
  398. <th>${ _('Namespace quota') }</th>
  399. <td data-bind="text: formatBytes(contentSummary().quota(), 4)"></td>
  400. </tr>
  401. <tr>
  402. <th>${ _('Disk space quota') }</th>
  403. <td data-bind="text: formatBytes(contentSummary().spaceQuota(), 4)"></td>
  404. </tr>
  405. <tr>
  406. <th>${ _('Number of directories') }</th>
  407. <td data-bind="text: contentSummary().directoryCount()"></td>
  408. </tr>
  409. <tr>
  410. <th>${ _('Number of files') }</th>
  411. <td data-bind="text: contentSummary().fileCount()"></td>
  412. </tr>
  413. </table>
  414. </div>
  415. <div class="modal-footer">
  416. <a class="btn" data-dismiss="modal">${_('Close')}</a>
  417. </div>
  418. </div>
  419. <!-- actions context menu -->
  420. <ul class="context-menu dropdown-menu">
  421. <!-- ko ifnot: $root.inTrash -->
  422. <li><a href="#" title="${_('Rename')}" data-bind="visible: !$root.inTrash() && $root.selectedFiles().length == 1, click: $root.renameFile,
  423. enable: $root.selectedFiles().length == 1 && isCurrentDirSelected().length == 0"><i class="fa fa-fw fa-font"></i>
  424. ${_('Rename')}</a></li>
  425. <li><a href="#"title="${_('Move')}" data-bind="click: $root.move, enable: $root.selectedFiles().length > 0 &&
  426. isCurrentDirSelected().length == 0"><i class="fa fa-fw fa-random"></i> ${_('Move')}</a></li>
  427. <li><a href="#" title="${_('Copy')}" data-bind="click: $root.copy, enable: $root.selectedFiles().length > 0 &&
  428. isCurrentDirSelected().length == 0"><i class="fa fa-fw fa-files-o"></i> ${_('Copy')}</a></li>
  429. % if show_download_button:
  430. <li><a href="#" title="${_('Download')}" data-bind="visible: !$root.inTrash() && $root.selectedFiles().length == 1 && selectedFile().type == 'file', click: $root.downloadFile"><i class="fa fa-fw fa-arrow-circle-o-down"></i> ${_('Download')}</a></li>
  431. % endif
  432. <li class="divider"></li>
  433. % if is_fs_superuser:
  434. <li data-bind="css: {'disabled': $root.isCurrentDirSentryManaged || selectedSentryFiles().length > 0 }">
  435. <a href="#" data-bind="visible: !$root.inTrash(), click: $root.changeOwner, enable: $root.selectedFiles().length > 0">
  436. <i class="fa fa-fw fa-user"></i> ${_('Change owner / group')}
  437. </a>
  438. </li>
  439. % endif
  440. <li data-bind="css: {'disabled': $root.isCurrentDirSentryManaged() || selectedSentryFiles().length > 0 }">
  441. <a href="#" data-bind="visible: !$root.inTrash(), click: $root.changePermissions, enable: $root.selectedFiles().length > 0">
  442. <i class="fa fa-fw fa-list-alt"></i> ${_('Change permissions')}
  443. </a>
  444. </li>
  445. <li class="divider"></li>
  446. <li><a href="#" data-bind="enable: $root.selectedFiles().length > 0 && isCurrentDirSelected().length == 0,
  447. click: $root.trashSelected"><i class="fa fa-fw fa-times"></i> ${_('Move to trash')}</a></li>
  448. <li><a href="#" class="delete-link" title="${_('Delete forever')}" data-bind="enable: $root.selectedFiles().length > 0, click: $root.deleteSelected"><i class="fa fa-fw fa-bolt"></i> ${_('Delete forever')}</a></li>
  449. <li class="divider"></li>
  450. <li data-bind="css: {'disabled': selectedFiles().length > 1 }">
  451. <a class="pointer" data-bind="click: function(){ selectedFiles().length == 1 ? showSummary(): void(0)}"><i class="fa fa-fw fa-pie-chart"></i> ${_('Summary')}</a>
  452. </li>
  453. <!-- /ko -->
  454. <!-- ko if: $root.inTrash -->
  455. <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>
  456. <li class="divider"></li>
  457. <li><a href="#" title="${_('Empty trash')}" data-bind="visible: inTrash(), click: purgeTrash"><i class="fa fa-fw fa-fire"></i> ${_('Empty trash')}</a></li>
  458. <!-- /ko -->
  459. </ul>
  460. <div id="submit-wf-modal" class="modal hide"></div>
  461. <div id="progressStatus" class="uploadstatus well hide">
  462. <h4>${ _('Upload progress') }</h4>
  463. <div id="progressStatusBar" class="hide progress active">
  464. <div class="bar bar-upload"></div>
  465. </div>
  466. <div id="progressStatusContent" class="scrollable-uploadstatus">
  467. <div class="updateStatus"> </div>
  468. </div>
  469. <div>
  470. </div>
  471. <script id="fileTemplate" type="text/html">
  472. <tr style="cursor: pointer" data-bind="drop: { enabled: name !== '.' && type !== 'file', value: $data }, event: { mouseover: toggleHover, mouseout: toggleHover, contextmenu: showContextMenu }, click: $root.viewFile, css: { 'row-selected': selected() }">
  473. <td class="center" data-bind="click: handleSelect" style="cursor: default">
  474. <div data-bind="visible: name != '..', css: { hueCheckbox: name != '..', 'fa': name != '..', 'fa-check': selected }"></div>
  475. </td>
  476. <td class="left"><i data-bind="click: $root.viewFile, css: { 'fa': true,
  477. % if 'oozie' in apps:
  478. 'fa-play': $.inArray(name, ['workflow.xml', 'coordinator.xml', 'bundle.xml']) > -1,
  479. % endif
  480. 'fa-file-o': type == 'file', 'fa-folder': type != 'file', 'fa-folder-open': type != 'file' && hovered }"></i></td>
  481. <td data-bind="attr: {'title': tooltip}" rel="tooltip">
  482. <!-- ko if: name == '..' -->
  483. <a href="#" data-bind="click: $root.viewFile"><i class="fa fa-level-up"></i></a>
  484. <!-- /ko -->
  485. <!-- ko if: name != '..' -->
  486. <strong><a href="#" data-bind="drag: { value: $data }, click: $root.viewFile, text: name, attr: { 'draggable': $.inArray(name, ['.', '..', '.Trash']) === -1 }"></a></strong>
  487. <!-- /ko -->
  488. </td>
  489. <td>
  490. <span data-bind="visible: type == 'file', text: stats.size"></span>
  491. </td>
  492. <td>
  493. % if is_fs_superuser:
  494. <span data-bind="text: stats.user, visible: ! selected() || $root.isCurrentDirSentryManaged() || isSentryManaged"></span>
  495. <a href="#" rel="tooltip" title="${_('Change owner')}" data-original-title="${_('Change owner')}"
  496. data-bind="text: stats.user, visible: ! $root.inTrash() && selected() && ! $root.isCurrentDirSentryManaged() && ! isSentryManaged, click: $root.changeOwner, enable: $root.selectedFiles().length > 0"></a>
  497. % else:
  498. <span data-bind="text: stats.user"></span>
  499. % endif
  500. </td>
  501. <td>
  502. % if is_fs_superuser:
  503. <span data-bind="text: stats.group, visible: ! selected() || $root.isCurrentDirSentryManaged() || isSentryManaged"></span>
  504. <a href="#" rel="tooltip" title="${_('Change group')}" data-original-title="${_('Change group')}"
  505. data-bind="text: stats.group, visible: ! $root.inTrash() && selected() && ! $root.isCurrentDirSentryManaged() && ! isSentryManaged, click: $root.changeOwner"></a>
  506. % else:
  507. <span data-bind="text: stats.group"></span>
  508. % endif
  509. </td>
  510. <td>
  511. <span data-bind="text: permissions, visible: ! selected() || $root.isCurrentDirSentryManaged() || isSentryManaged"></span>
  512. <a href="#" rel="tooltip" title="${_('Change permissions')}"
  513. data-bind="text: permissions, visible: ! $root.inTrash() && selected() && ! $root.isCurrentDirSentryManaged() && ! isSentryManaged, click: $root.changePermissions" data-original-title="${_('Change permissions')}"></a>
  514. </td>
  515. <td data-bind="text: stats.mtime" style="white-space: nowrap;"></td>
  516. </tr>
  517. </script>
  518. <script src="${ static('desktop/js/jquery.hdfsautocomplete.js') }" type="text/javascript" charset="utf-8"></script>
  519. <script src="${ static('desktop/js/jquery.hdfstree.js') }" type="text/javascript" charset="utf-8"></script>
  520. <script src="${ static('desktop/ext/js/knockout.min.js') }" type="text/javascript" charset="utf-8"></script>
  521. <script src="${ static('desktop/ext/js/knockout-mapping.min.js') }" type="text/javascript" charset="utf-8"></script>
  522. <script src="${ static('desktop/ext/js/jquery/plugins/jquery-ui-1.10.4.draggable-droppable-sortable.min.js') }" type="text/javascript" charset="utf-8"></script>
  523. <script src="${ static('desktop/ext/js/datatables-paging-0.1.js') }" type="text/javascript" charset="utf-8"></script>
  524. <script src="${ static('desktop/js/dropzone.js') }" type="text/javascript" charset="utf-8"></script>
  525. <script charset="utf-8">
  526. var _dragged;
  527. var _dropzone;
  528. ko.bindingHandlers.drag = {
  529. init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
  530. var dragElement = $(element);
  531. var dragOptions = {
  532. helper: 'clone',
  533. revert: true,
  534. revertDuration: 0,
  535. start: function() {
  536. if ($(element).is('[draggable]')) {
  537. viewModel.selected(true);
  538. }
  539. _dragged = ko.utils.unwrapObservable(valueAccessor().value);
  540. },
  541. cursor: "move",
  542. delay: 300
  543. };
  544. dragElement.draggable(dragOptions).disableSelection();
  545. }
  546. };
  547. ko.bindingHandlers.drop = {
  548. init: function(element, valueAccessor) {
  549. var dropElement = $(element);
  550. if (valueAccessor().enabled){
  551. var dropOptions = {
  552. hoverClass: 'drag-hover',
  553. drop: function(event, ui) {
  554. var destpath = valueAccessor().value.path;
  555. dropElement.fadeOut(200, function(){
  556. dropElement.fadeIn(200);
  557. });
  558. if (destpath) {
  559. $('#moveDestination').val(destpath);
  560. viewModel.move('nomodal');
  561. }
  562. }
  563. };
  564. dropElement.droppable(dropOptions);
  565. }
  566. }
  567. };
  568. var getHistory = function () {
  569. return $.totalStorage('hue_fb_history') || [];
  570. };
  571. var showHistory = function () {
  572. var history = getHistory().slice(0, 10),
  573. frag = $('<ul/>', {
  574. 'id': 'hashHistory',
  575. 'class': 'dropdown-menu',
  576. 'role': 'menu',
  577. 'aria-labelledby': 'historyDropdown'
  578. });
  579. $('#hashHistory').remove();
  580. history.forEach(function (item) {
  581. var url = '/filebrowser/#' + item,
  582. list = $('<li><a href="' + url + '">' + item + '</a></li>');
  583. $(list).appendTo(frag);
  584. });
  585. $('<li>', {
  586. 'class': 'divider'
  587. }).appendTo(frag);
  588. $('<li><a href="javascript:void(0)">${ _("Clear history...") }</a></li>')
  589. .appendTo(frag)
  590. .on('click', function(){
  591. $.totalStorage('hue_fb_history', null);
  592. $('.history').addClass('no-history');
  593. });
  594. $(frag).appendTo('.history');
  595. return this;
  596. };
  597. var addPathToHistory = function (path) {
  598. $('.history').removeClass('no-history');
  599. var history = getHistory();
  600. if (path != '/filebrowser/') {
  601. var _basePath = '${url('filebrowser.views.view', path='')}';
  602. if (path.indexOf(_basePath) > -1) {
  603. path = path.substr(_basePath.length);
  604. }
  605. // ensure no duplicates are pushed to $.totalStorage()
  606. if (history.indexOf(path) === -1) {
  607. history.unshift(path);
  608. $('.history').removeClass('no-history');
  609. } else {
  610. history.unshift(history.splice(history.indexOf(path), 1)[0]);
  611. }
  612. $.totalStorage('hue_fb_history', history.slice(0, 10));
  613. }
  614. };
  615. // ajax modal windows
  616. var openChownWindow = function (path, user, group, next) {
  617. $.ajax({
  618. url: "/filebrowser/chown",
  619. data: {"path": path, "user": user, "group": group, "next": next},
  620. beforeSend: function (xhr) {
  621. xhr.setRequestHeader("X-Requested-With", "Hue");
  622. },
  623. dataType: "html",
  624. success: function (data) {
  625. $("#changeOwnerModal").html(data);
  626. $("#changeOwnerModal").modal({
  627. keyboard:true,
  628. show:true
  629. });
  630. }
  631. });
  632. };
  633. var fileExists = function (newName) {
  634. if (viewModel) {
  635. var files = viewModel.files();
  636. for (var i = 0; i < files.length; i++) {
  637. if (files[i].name == newName) {
  638. return true;
  639. }
  640. }
  641. }
  642. return false;
  643. };
  644. var resetActionbar = function() {
  645. $(".actionbar").attr("style", "min-width: 1190px");
  646. $(".actionbar").data("originalWidth", $(".actionbar").width());
  647. $(".actionbarGhost").addClass("hide");
  648. };
  649. var stripHashes = function (str) {
  650. return str.replace(/#/gi, encodeURIComponent("#"));
  651. };
  652. var formatBytes = function (bytes, decimals) {
  653. if (bytes == -1) return "${ _('Not available.') }";
  654. if (bytes == 0) return "0 Byte";
  655. var k = 1024;
  656. var dm = decimals + 1 || 3;
  657. var sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
  658. var i = Math.floor(Math.log(bytes) / Math.log(k));
  659. return (bytes / Math.pow(k, i)).toPrecision(dm) + ' ' + sizes[i];
  660. }
  661. var Page = function (page) {
  662. if (page != null) {
  663. return {
  664. number: page.number,
  665. num_pages: page.num_pages,
  666. previous_page_number: page.previous_page_number,
  667. next_page_number: page.next_page_number,
  668. start_index: page.start_index,
  669. end_index: page.end_index,
  670. total_count: page.total_count
  671. }
  672. }
  673. return {
  674. }
  675. };
  676. var File = function (file) {
  677. file.tooltip = "";
  678. if (file.name == "."){
  679. file.tooltip = "${_('This folder')}";
  680. }
  681. if (file.name == ".."){
  682. file.tooltip = "${_('One level up')}";
  683. }
  684. return {
  685. name: file.name,
  686. path: file.path,
  687. url: file.url,
  688. type: file.type,
  689. permissions: file.rwx,
  690. mode: file.mode,
  691. isSentryManaged: file.is_sentry_managed,
  692. stats: {
  693. size: file.humansize,
  694. user: file.stats.user,
  695. group: file.stats.group,
  696. mtime: file.mtime
  697. },
  698. selected: ko.observable(false),
  699. handleSelect: function (row, e) {
  700. e.preventDefault();
  701. e.stopPropagation();
  702. this.selected(! this.selected());
  703. viewModel.allSelected(false);
  704. },
  705. // display the context menu when an item is right/context clicked
  706. showContextMenu: function (row, e) {
  707. var cm = $('.context-menu'),
  708. actions = $('#ch-dropdown'),
  709. rect = document.querySelector('body').getBoundingClientRect();
  710. e.stopPropagation();
  711. // close the actions menu from button area if open
  712. if (actions.hasClass('open')) {
  713. actions.removeClass('open');
  714. }
  715. // display context menu and ensure it is on-screen
  716. if ($.inArray(row.name, ['..', '.', '.Trash']) === -1) {
  717. this.selected(true);
  718. cm.css({ display: 'block', top: e.pageY - 15, left: (e.pageX < rect.right - 200 ) ? e.pageX : e.pageX - 250 });
  719. } else {
  720. cm.css({ display: 'none' });
  721. }
  722. },
  723. hovered: ko.observable(false),
  724. toggleHover: function (row, e) {
  725. this.hovered(! this.hovered());
  726. },
  727. tooltip:file.tooltip
  728. }
  729. };
  730. var Breadcrumb = function (breadcrumb) {
  731. return {
  732. url: breadcrumb.url,
  733. label: breadcrumb.label,
  734. show: function () {
  735. if (this.url == null || this.url == "") {
  736. // forcing root on empty breadcrumb url
  737. this.url = "/";
  738. }
  739. viewModel.targetPageNum(1);
  740. viewModel.targetPath("${url('filebrowser.views.view', path='')}" + stripHashes(this.url));
  741. location.hash = this.url;
  742. }
  743. }
  744. };
  745. var FileBrowserModel = function (files, page, breadcrumbs, currentDirPath) {
  746. var self = this;
  747. if (! $.cookie("hueFilebrowserRecordsPerPage")){
  748. $.cookie("hueFilebrowserRecordsPerPage", "45");
  749. }
  750. self.page = ko.observable(new Page(page));
  751. self.recordsPerPageChoices = ["15", "30", "45", "60", "100", "200", "1000"],
  752. self.recordsPerPage = ko.observable($.cookie("hueFilebrowserRecordsPerPage"));
  753. self.targetPageNum = ko.observable(1);
  754. self.targetPath = ko.observable("${current_request_path | n,unicode }");
  755. self.sortBy = ko.observable("name");
  756. self.sortDescending = ko.observable(false);
  757. self.searchQuery = ko.observable("");
  758. self.isCurrentDirSentryManaged = ko.observable(false);
  759. self.pendingUploads = ko.observable(0);
  760. self.fileNameSorting = function (l, r) {
  761. if (l.name == "..") {
  762. return -1;
  763. }
  764. else if (r.name == "..") {
  765. return 1;
  766. }
  767. else if (l.name == ".") {
  768. return -1;
  769. }
  770. else if (r.name == ".") {
  771. return 1;
  772. }
  773. else {
  774. var _ret = l.name > r.name ? 1 : -1;
  775. if (self.sortDescending()){
  776. _ret = _ret * -1;
  777. }
  778. return _ret;
  779. }
  780. }
  781. self.files = ko.observableArray(ko.utils.arrayMap(files, function (file) {
  782. return new File(file);
  783. }));
  784. if (self.sortBy() == "name"){
  785. self.files.sort(self.fileNameSorting);
  786. }
  787. self.homeDir = ko.observable("${home_directory}");
  788. self.breadcrumbs = ko.observableArray(ko.utils.arrayMap(breadcrumbs, function (breadcrumb) {
  789. return new Breadcrumb(breadcrumb);
  790. }));
  791. self.sort = function (viewModel, event) {
  792. var el = $(event.currentTarget);
  793. el.siblings(".sortable").attr("class", "sortable sorting");
  794. self.sortBy(el.data("sort"));
  795. el.removeClass("sorting");
  796. if (el.hasClass("sorting_asc")) {
  797. self.sortDescending(true);
  798. } else {
  799. self.sortDescending(false);
  800. }
  801. el.attr("class", "sortable");
  802. if (self.sortDescending() == true) {
  803. el.addClass("sorting_desc");
  804. } else {
  805. el.addClass("sorting_asc");
  806. }
  807. self.retrieveData();
  808. }
  809. self.isLoading = ko.observable(true);
  810. self.allSelected = ko.observable(false);
  811. self.selectedFiles = ko.computed(function () {
  812. return ko.utils.arrayFilter(self.files(), function (file) {
  813. return file.selected();
  814. });
  815. }, self);
  816. self.selectedSentryFiles = ko.computed(function () {
  817. return ko.utils.arrayFilter(self.files(), function (file) {
  818. return file.selected() && file.isSentryManaged;
  819. });
  820. }, self);
  821. self.isCurrentDirSelected = ko.computed(function () {
  822. return ko.utils.arrayFilter(self.files(), function (file) {
  823. return file.name == "." && file.selected();
  824. });
  825. }, self);
  826. self.selectedFile = ko.computed(function () {
  827. return self.selectedFiles()[0];
  828. }, self);
  829. self.currentPath = ko.observable(currentDirPath);
  830. self.currentPath.subscribe(function (path) {
  831. $(document).trigger('currPathLoaded', { path: path });
  832. });
  833. self.inTrash = ko.computed(function() {
  834. return self.currentPath().match(/^\/user\/.+?\/\.Trash/);
  835. });
  836. self.inRestorableTrash = ko.computed(function() {
  837. return self.currentPath().match(/^\/user\/.+?\/\.Trash\/.+?/);
  838. });
  839. self.isLoadingSummary = ko.observable(true);
  840. self.contentSummary = ko.observable(ko.mapping.fromJS({
  841. spaceConsumed: -1,
  842. quota: -1,
  843. spaceQuota: -1,
  844. length: 0,
  845. directoryCount: 0,
  846. fileCount: 0
  847. }));
  848. self.showSummary = function () {
  849. self.isLoadingSummary(true);
  850. $("#contentSummaryModal").modal("show");
  851. $.getJSON("${url('filebrowser.views.content_summary', path='')}" + self.selectedFile().path, function (data) {
  852. self.contentSummary(ko.mapping.fromJS(data));
  853. self.isLoadingSummary(false);
  854. });
  855. }
  856. self.getStats = function (callback) {
  857. $.getJSON(self.targetPath() + "?pagesize=1&format=json", callback);
  858. };
  859. self.retrieveData = function () {
  860. self.isLoading(true);
  861. $.getJSON(self.targetPath() + "?pagesize=" + self.recordsPerPage() + "&pagenum=" + self.targetPageNum() + "&filter=" + self.searchQuery() + "&sortby=" + self.sortBy() + "&descending=" + self.sortDescending() + "&format=json", function (data) {
  862. if (data.error){
  863. $(document).trigger("error", data.error);
  864. self.isLoading(false);
  865. return false;
  866. }
  867. if (data.type != null && data.type == "file") {
  868. location.href = data.url;
  869. return false;
  870. }
  871. self.updateFileList(data.files, data.page, data.breadcrumbs, data.current_dir_path, data.is_sentry_managed);
  872. if ($("#hueBreadcrumbText").is(":visible")) {
  873. $(".hueBreadcrumb").show();
  874. $("#hueBreadcrumbText").hide();
  875. $("#editBreadcrumb").show();
  876. }
  877. });
  878. };
  879. self.updateFileList = function (files, page, breadcrumbs, currentDirPath, isSentryManaged) {
  880. $(".tooltip").hide();
  881. self.isCurrentDirSentryManaged(isSentryManaged);
  882. self.page(new Page(page));
  883. self.files(ko.utils.arrayMap(files, function (file) {
  884. return new File(file);
  885. }));
  886. if (self.sortBy() == "name"){
  887. self.files.sort(self.fileNameSorting);
  888. }
  889. self.breadcrumbs(ko.utils.arrayMap(breadcrumbs, function (breadcrumb) {
  890. return new Breadcrumb(breadcrumb);
  891. }));
  892. self.currentPath(currentDirPath);
  893. $('.uploader').trigger('fb:updatePath', {dest:self.currentPath()});
  894. self.isLoading(false);
  895. $("*[rel='tooltip']").tooltip({ placement:"left" });
  896. $(window).scrollTop(0);
  897. resetActionbar();
  898. };
  899. self.recordsPerPage.subscribe(function (newValue) {
  900. $.cookie("hueFilebrowserRecordsPerPage", newValue);
  901. self.retrieveData();
  902. });
  903. self.skipTo = function () {
  904. var doc = document,
  905. old_page = doc.querySelector('#current_page').value,
  906. page = doc.querySelector('.pagination-input');
  907. if (! isNaN(page.value) && (page.value > 0 && page.value <= self.page().num_pages)) {
  908. self.goToPage(page.value);
  909. } else {
  910. page.value = old_page;
  911. }
  912. };
  913. self.goToPage = function (pageNumber) {
  914. self.targetPageNum(pageNumber);
  915. if (location.hash.indexOf("!!") > -1){
  916. location.hash = location.hash.substring(0, location.hash.indexOf("!!")) + "!!" + pageNumber;
  917. } else {
  918. location.hash += "!!" + pageNumber;
  919. }
  920. };
  921. self.firstPage = function () {
  922. self.goToPage(1)
  923. };
  924. self.previousPage = function () {
  925. self.goToPage(self.page().previous_page_number)
  926. };
  927. self.nextPage = function () {
  928. self.goToPage(self.page().next_page_number)
  929. };
  930. self.lastPage = function () {
  931. self.goToPage(self.page().num_pages)
  932. };
  933. self.selectAll = function () {
  934. self.allSelected(! self.allSelected());
  935. ko.utils.arrayForEach(self.files(), function (file) {
  936. if (file.name != "." && file.name != "..") {
  937. file.selected(self.allSelected());
  938. }
  939. });
  940. return true;
  941. };
  942. self.searchQuery.subscribe(function (newValue) {
  943. self.filter();
  944. });
  945. self.filter = function () {
  946. self.targetPageNum(1);
  947. self.retrieveData();
  948. };
  949. self.viewFile = function (file) {
  950. if (file.type == "dir") {
  951. // Reset page number so that we don't hit a page that doesn't exist
  952. self.targetPageNum(1);
  953. self.searchQuery("");
  954. self.targetPath("${url('filebrowser.views.view', path='')}" + stripHashes(file.path));
  955. location.hash = stripHashes(file.path);
  956. } else {
  957. location.href = file.url;
  958. }
  959. };
  960. self.editFile = function () {
  961. location.href = "${url('filebrowser.views.edit', path='')}" + self.selectedFile().path;
  962. };
  963. self.downloadFile = function () {
  964. location.href = "${url('filebrowser.views.download', path='')}" + self.selectedFile().path;
  965. };
  966. self.renameFile = function () {
  967. $("#renameSrcPath").attr("value", self.selectedFile().path);
  968. $("#renameFileName").text(self.selectedFile().path);
  969. $("#newNameInput").val(self.selectedFile().name);
  970. $("#renameForm").attr("action", "/filebrowser/rename?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  971. $("#renameModal").modal({
  972. keyboard:true,
  973. show:true
  974. });
  975. };
  976. self.move = function (mode) {
  977. var paths = [];
  978. var isMoveOnSelf = false;
  979. $(self.selectedFiles()).each(function (index, file) {
  980. if (file.path == $('#moveDestination').val()){
  981. isMoveOnSelf = true;
  982. }
  983. paths.push(file.path);
  984. });
  985. if (!isMoveOnSelf){
  986. hiddenFields($("#moveForm"), "src_path", paths);
  987. $("#moveForm").attr("action", "/filebrowser/move?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  988. if (mode === 'nomodal') {
  989. $.jHueNotify.info('${ _('Items moving to') } "' + $('#moveDestination').val() + '"');
  990. $("#moveForm").submit();
  991. } else {
  992. $("#moveModal").modal({
  993. keyboard: true,
  994. show: true
  995. });
  996. $("#moveModal").on("shown", function () {
  997. $("#moveModal .modal-footer div").show();
  998. $("#moveHdfsTree").remove();
  999. $("<div>").attr("id", "moveHdfsTree").appendTo($("#moveModal .modal-body"));
  1000. $("#moveHdfsTree").jHueHdfsTree({
  1001. home: "/user/${ user }",
  1002. initialPath: viewModel.currentPath(),
  1003. onPathChange: function (path) {
  1004. $("#moveDestination").val((path.indexOf("/") == 0 ? "" : "/") + path);
  1005. $("#moveNameRequiredAlert").hide();
  1006. }
  1007. });
  1008. });
  1009. }
  1010. }
  1011. else {
  1012. $.jHueNotify.warn("${ _('You cannot copy a folder into itself.') }");
  1013. }
  1014. };
  1015. self.copy = function () {
  1016. var paths = [];
  1017. $(self.selectedFiles()).each(function (index, file) {
  1018. paths.push(file.path);
  1019. });
  1020. hiddenFields($("#copyForm"), "src_path", paths);
  1021. $("#copyForm").attr("action", "/filebrowser/copy?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1022. $("#copyModal").modal({
  1023. keyboard:true,
  1024. show:true
  1025. });
  1026. $("#copyModal").on("shown", function(){
  1027. $("#copyModal .modal-footer div").show();
  1028. $("#copyHdfsTree").remove();
  1029. $("<div>").attr("id", "copyHdfsTree").appendTo($("#copyModal .modal-body"));
  1030. $("#copyHdfsTree").jHueHdfsTree({
  1031. home: "/user/${ user }",
  1032. initialPath: viewModel.currentPath(),
  1033. onPathChange: function(path){
  1034. $("#copyDestination").val((path.indexOf("/") == 0 ? "" : "/") + path);
  1035. $("#copyNameRequiredAlert").hide();
  1036. }
  1037. });
  1038. });
  1039. };
  1040. self.changeOwner = function (data, event) {
  1041. if (!self.isCurrentDirSentryManaged()) {
  1042. var paths = [];
  1043. event.preventDefault();
  1044. event.stopPropagation();
  1045. $(self.selectedFiles()).each(function (index, file) {
  1046. paths.push(file.path);
  1047. });
  1048. hiddenFields($("#chownForm"), 'path', paths);
  1049. $("#chownForm").attr("action", "/filebrowser/chown?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1050. $("select[name=user]").val(self.selectedFile().stats.user);
  1051. if ($("select[name=group] option:contains('" + self.selectedFile().stats.group + "')").length > 0) {
  1052. $("select[name=group]").val(self.selectedFile().stats.group);
  1053. } else {
  1054. $("select[name=group]").val("__other__");
  1055. $("input[name=group_other]").val(self.selectedFile().stats.group);
  1056. }
  1057. $("select[name=group]").change();
  1058. $("#changeOwnerModal").modal({
  1059. keyboard: true,
  1060. show: true
  1061. });
  1062. }
  1063. };
  1064. self.changePermissions = function (data, event) {
  1065. if (!self.isCurrentDirSentryManaged()) {
  1066. var paths = [];
  1067. var allFileType = true;
  1068. event.preventDefault();
  1069. event.stopPropagation();
  1070. $(self.selectedFiles()).each(function (index, file) {
  1071. if ("dir" == file.type) {
  1072. allFileType = false;
  1073. }
  1074. paths.push(file.path);
  1075. });
  1076. hiddenFields($("#chmodForm"), 'path', paths);
  1077. $("#chmodForm").attr("action", "/filebrowser/chmod?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1078. $("#changePermissionModal").modal({
  1079. keyboard: true,
  1080. show: true
  1081. });
  1082. // Initial values for form
  1083. var permissions = ["sticky", "user_read", "user_write", "user_execute", "group_read", "group_write", "group_execute", "other_read", "other_write", "other_execute"].reverse();
  1084. var mode = octal(self.selectedFile().mode) & 01777;
  1085. for (var i = 0; i < permissions.length; i++) {
  1086. if (mode & 1) {
  1087. $("#chmodForm input[name=" + permissions[i] + "]").attr("checked", true);
  1088. } else {
  1089. $("#chmodForm input[name=" + permissions[i] + "]").attr("checked", false);
  1090. }
  1091. mode >>>= 1;
  1092. }
  1093. if (allFileType) {
  1094. $("#chmodForm input[name='user_execute']").attr("disabled", "disabled");
  1095. $("#chmodForm input[name='group_execute']").attr("disabled", "disabled");
  1096. $("#chmodForm input[name='other_execute']").attr("disabled", "disabled");
  1097. } else {
  1098. $("#chmodForm input[name='user_execute']").removeAttr("disabled");
  1099. $("#chmodForm input[name='group_execute']").removeAttr("disabled");
  1100. $("#chmodForm input[name='other_execute']").removeAttr("disabled");
  1101. }
  1102. }
  1103. };
  1104. var deleteSelected = function(skip_trash) {
  1105. var paths = [];
  1106. $(self.selectedFiles()).each(function (index, file) {
  1107. paths.push(file.path);
  1108. });
  1109. hiddenFields($("#deleteForm"), 'path', paths);
  1110. $("#deleteForm").attr("action", "/filebrowser/rmtree" + "?" +
  1111. (skip_trash ? "skip_trash=true&" : "") +
  1112. "next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1113. $("#deleteModal").modal({
  1114. keyboard:true,
  1115. show:true
  1116. });
  1117. };
  1118. self.deleteSelected = function () {
  1119. deleteSelected(true);
  1120. };
  1121. self.trashSelected = function () {
  1122. deleteSelected();
  1123. };
  1124. self.submitSelected = function() {
  1125. % if 'oozie' in apps:
  1126. $.get("${ url('oozie:submit_external_job', application_path='/') }../" + self.selectedFile().path, function (response) {
  1127. $('#submit-wf-modal').html(response);
  1128. $('#submit-wf-modal').modal('show');
  1129. });
  1130. % else:
  1131. $.jHueNotify.warn("${ _('Submitting is not available as the Oozie app is disabled') }");
  1132. % endif
  1133. };
  1134. self.createDirectory = function (formElement) {
  1135. $(formElement).attr("action", "/filebrowser/mkdir?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1136. return true;
  1137. };
  1138. self.createFile = function (formElement) {
  1139. $(formElement).attr("action", "/filebrowser/touch?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1140. return true;
  1141. };
  1142. self.restoreTrashSelected = function(formElement) {
  1143. var paths = [];
  1144. $(self.selectedFiles()).each(function (index, file) {
  1145. paths.push(file.path);
  1146. });
  1147. hiddenFields($("#restoreTrashForm"), 'path', paths);
  1148. $("#restoreTrashForm").attr("action", "/filebrowser/trash/restore?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
  1149. $("#restoreTrashModal").modal({
  1150. keyboard:true,
  1151. show:true
  1152. });
  1153. };
  1154. self.purgeTrash = function(formElement) {
  1155. var paths = [];
  1156. $(self.selectedFiles()).each(function (index, file) {
  1157. paths.push(file.path);
  1158. });
  1159. hiddenFields($("#purgeTrashForm"), 'path', paths);
  1160. $("#purgeTrashForm").attr("action", "/filebrowser/trash/purge?next=${url('filebrowser.views.view', path='')}" + viewModel.homeDir() + "/.Trash");
  1161. $("#purgeTrashModal").modal({
  1162. keyboard:true,
  1163. show:true
  1164. });
  1165. };
  1166. self.uploadFile = (function () {
  1167. self.pendingUploads(0);
  1168. var action = "/filebrowser/upload/file";
  1169. var uploader = new qq.FileUploader({
  1170. element: document.getElementById("fileUploader"),
  1171. action: action,
  1172. template: '<div class="qq-uploader" style="margin-left: 10px">' +
  1173. '<div class="qq-upload-drop-area"><span>${_('Drop the files here to upload')}</span></div>' +
  1174. '<div class="qq-upload-button">${_('Select files')}</div> &nbsp; <span class="muted">or drag and drop them here</span>' +
  1175. '<ul class="qq-upload-list qq-upload-files unstyled" style="margin-right: 0;"></ul>' +
  1176. '</div>',
  1177. fileTemplate: '<li><span class="qq-upload-file-extended" style="display:none"></span><span class="qq-upload-spinner hide" style="display:none"></span>' +
  1178. '<div class="progress-row dz-processing">' +
  1179. '<span class="break-word qq-upload-file"></span>' +
  1180. '<div class="pull-right">' +
  1181. '<span class="muted qq-upload-size"></span>&nbsp;&nbsp;' +
  1182. '<a href="#" title="${_('Cancel')}" class="complex-layout"><i class="fa fa-fw fa-times qq-upload-cancel"></i></a>' +
  1183. '<span class="qq-upload-done" style="display:none"><i class="fa fa-fw fa-check muted"></i></span>' +
  1184. '<span class="qq-upload-failed-text">${_('Failed')}</span>' +
  1185. '</div>' +
  1186. '<div class="progress-row-bar" style="width: 0%;"></div>' +
  1187. '</div></li>',
  1188. params: {
  1189. dest: self.currentPath(),
  1190. fileFieldLabel: "hdfs_file"
  1191. },
  1192. onProgress: function (id, fileName, loaded, total) {
  1193. $('.qq-upload-files').find('li').each(function(){
  1194. var listItem = $(this);
  1195. if (listItem.find('.qq-upload-file-extended').text() == fileName){
  1196. listItem.find('.progress-row-bar').css('width', (loaded/total)*100 + '%');
  1197. }
  1198. });
  1199. },
  1200. onComplete: function (id, fileName, response) {
  1201. self.pendingUploads(self.pendingUploads() - 1);
  1202. if (response.status != 0) {
  1203. $(document).trigger('error', "${ _('Error: ') }" + response.data);
  1204. }
  1205. else {
  1206. $(document).trigger('info', response.path + "${ _(' uploaded successfully.') }");
  1207. }
  1208. if (self.pendingUploads() == 0) {
  1209. $('#uploadFileModal').modal('hide');
  1210. self.retrieveData();
  1211. }
  1212. },
  1213. onSubmit: function (id, fileName, responseJSON) {
  1214. self.pendingUploads(self.pendingUploads() + 1);
  1215. },
  1216. onCancel: function (id, fileName) {
  1217. self.pendingUploads(self.pendingUploads() - 1);
  1218. },
  1219. debug: false
  1220. });
  1221. $("#fileUploader").on('fb:updatePath', function (e, options) {
  1222. uploader.setParams({
  1223. dest: options.dest,
  1224. fileFieldLabel: "hdfs_file"
  1225. });
  1226. });
  1227. return function () {
  1228. $("#uploadFileModal").modal({
  1229. keyboard: false,
  1230. backdrop: 'static',
  1231. show: true
  1232. });
  1233. };
  1234. })();
  1235. self.uploadArchive = (function () {
  1236. self.pendingUploads(0);
  1237. var uploader = new qq.FileUploader({
  1238. element: document.getElementById("archiveUploader"),
  1239. action: "/filebrowser/upload/archive",
  1240. template: '<div class="qq-uploader" style="margin-left: 10px">' +
  1241. '<div class="qq-upload-drop-area"><span>${_('Drop the archives here to upload and extract them')}</span></div>' +
  1242. '<div class="qq-upload-button">${_('Select ZIP, TGZ or BZ2 files')}</div> &nbsp; <span class="muted">or drag and drop them here</span>' +
  1243. '<ul class="qq-upload-list qq-upload-archives unstyled" style="margin-right: 0;"></ul>' +
  1244. '</div>',
  1245. fileTemplate: '<li><span class="qq-upload-file-extended" style="display:none"></span><span class="qq-upload-spinner hide" style="display:none"></span>' +
  1246. '<div class="progress-row dz-processing">' +
  1247. '<span class="break-word qq-upload-file"></span>' +
  1248. '<div class="pull-right">' +
  1249. '<span class="muted qq-upload-size"></span>&nbsp;&nbsp;' +
  1250. '<a href="#" title="${_('Cancel')}" class="complex-layout"><i class="fa fa-fw fa-times qq-upload-cancel"></i></a>' +
  1251. '<span class="qq-upload-done" style="display:none"><i class="fa fa-fw fa-check muted"></i></span>' +
  1252. '<span class="qq-upload-failed-text">${_('Failed')}</span>' +
  1253. '</div>' +
  1254. '<div class="progress-row-bar" style="width: 0%;"></div>' +
  1255. '</div></li>',
  1256. params: {
  1257. dest: self.currentPath(),
  1258. fileFieldLabel: "archive"
  1259. },
  1260. onProgress: function (id, fileName, loaded, total) {
  1261. $('.qq-upload-archives').find('li').each(function(){
  1262. var listItem = $(this);
  1263. if (listItem.find('.qq-upload-file-extended').text() == fileName){
  1264. listItem.find('.progress-row-bar').css('width', (loaded/total)*100 + '%');
  1265. }
  1266. });
  1267. },
  1268. onComplete: function (id, fileName, response) {
  1269. self.pendingUploads(self.pendingUploads() - 1);
  1270. if (response.status != 0) {
  1271. $(document).trigger('error', "${ _('Error: ') }" + response.data);
  1272. }
  1273. else {
  1274. $(document).trigger('info', response.path + "${ _(' uploaded successfully.') }");
  1275. }
  1276. if (self.pendingUploads() == 0) {
  1277. $('#uploadArchiveModal').modal('hide');
  1278. self.retrieveData();
  1279. }
  1280. },
  1281. onSubmit: function (id, fileName, responseJSON) {
  1282. self.pendingUploads(self.pendingUploads() + 1);
  1283. },
  1284. onCancel: function (id, fileName) {
  1285. self.pendingUploads(self.pendingUploads() - 1);
  1286. },
  1287. debug: false
  1288. });
  1289. $("#archiveUploader").on('fb:updatePath', function (e, options) {
  1290. uploader.setParams({
  1291. dest: options.dest,
  1292. fileFieldLabel: "archive"
  1293. });
  1294. });
  1295. return function () {
  1296. $("#uploadArchiveModal").modal({
  1297. keyboard: false,
  1298. backdrop: 'static',
  1299. show: true
  1300. });
  1301. };
  1302. })();
  1303. // Place all values into hidden fields under parent element.
  1304. // Looks for managed hidden fields and handles sizing appropriately.
  1305. var hiddenFields = function (parentEl, name, values) {
  1306. parentEl = $(parentEl);
  1307. parentEl.find("input.hidden-field").remove();
  1308. $(values).each(function (index, value) {
  1309. var field = $("<input type='hidden' />");
  1310. field.attr("name", name);
  1311. field.attr("class", "hidden-field")
  1312. field.val(value);
  1313. parentEl.append(field);
  1314. });
  1315. };
  1316. var octal = function (strInt) {
  1317. return parseInt("0" + strInt, 8);
  1318. };
  1319. };
  1320. // hide the context menu based on specific events
  1321. var hideContextMenu = function () {
  1322. var cm = $('.context-menu');
  1323. if (cm.is(':visible')) {
  1324. cm.css({ display: 'none' });
  1325. }
  1326. };
  1327. var viewModel = new FileBrowserModel([], null, [], "/");
  1328. ko.applyBindings(viewModel);
  1329. $(document).ready(function () {
  1330. if (getHistory().length == 0) {
  1331. $('.history').addClass('no-history');
  1332. }
  1333. $('.historyLink').on('click', function (e) {
  1334. if(getHistory().length > 0) {
  1335. showHistory();
  1336. } else {
  1337. e.preventDefault();
  1338. e.stopPropagation();
  1339. }
  1340. });
  1341. // hide context menu
  1342. $('body').on('click', function (e) {
  1343. hideContextMenu();
  1344. });
  1345. $('body').on('contextmenu', function (e) {
  1346. if ($.inArray(e.toElement, $('.datatables *')) === -1) {
  1347. hideContextMenu();
  1348. }
  1349. });
  1350. $('body').on('contextmenu', '.context-menu', function (e) {
  1351. hideContextMenu();
  1352. });
  1353. // Drag and drop uploads from anywhere on filebrowser screen
  1354. if (window.FileReader) {
  1355. var showHoverMsg = function (msg) {
  1356. $('.hoverText').html(msg);
  1357. $('.hoverMsg').removeClass('hide');
  1358. };
  1359. var hideHoverMsg = function () {
  1360. $('.hoverMsg').addClass('hide');
  1361. };
  1362. var _isDraggingOverText = false,
  1363. // determine if the item dragged originated outside DOM
  1364. _isExternalFile = true;
  1365. $('body').on('dragstart', function (e) {
  1366. // External files being dragged into the DOM won't have a dragstart event
  1367. _isExternalFile = false;
  1368. });
  1369. $('body').on('dragend', function (e) {
  1370. _isExternalFile = true;
  1371. });
  1372. $('body').on('dragenter', function (e) {
  1373. e.preventDefault();
  1374. if (_isExternalFile && !($("#uploadFileModal").is(":visible")) && !($("#uploadArchiveModal").is(":visible"))) {
  1375. showHoverMsg("${_('Drop files here to upload')}");
  1376. }
  1377. });
  1378. $('.hoverText').on('dragenter', function (e) {
  1379. e.preventDefault();
  1380. e.stopPropagation();
  1381. e.stopImmediatePropagation();
  1382. _isDraggingOverText = true;
  1383. });
  1384. $('.hoverText').on('dragleave', function (e) {
  1385. e.preventDefault();
  1386. e.stopPropagation();
  1387. e.stopImmediatePropagation();
  1388. _isDraggingOverText = false;
  1389. _isExternalFile = true;
  1390. });
  1391. $('.hoverMsg').on('dragleave', function (e) {
  1392. if (!_isDraggingOverText) {
  1393. hideHoverMsg();
  1394. }
  1395. });
  1396. $(document).on('currPathLoaded', function (e, ops) {
  1397. try {
  1398. _dropzone.destroy();
  1399. }
  1400. catch (e) {
  1401. }
  1402. var options = {
  1403. url: '/filebrowser/upload/file?dest=' + ops.path,
  1404. paramName: 'hdfs_file',
  1405. params: {
  1406. dest: ops.path
  1407. },
  1408. autoDiscover: false,
  1409. maxFilesize: 5000000,
  1410. previewsContainer: '#progressStatusContent',
  1411. previewTemplate: '<div class="progress-row">' +
  1412. '<span class="break-word" data-dz-name></span>' +
  1413. '<div class="pull-right">' +
  1414. '<span class="muted" data-dz-size></span>&nbsp;&nbsp;' +
  1415. '<span data-dz-remove><a href="javascript:undefined;" title="${ _('Cancel upload') }"><i class="fa fa-fw fa-times"></i></a></span>' +
  1416. '<span style="display: none" data-dz-uploaded><i class="fa fa-fw fa-check muted"></i></span>' +
  1417. '</div>' +
  1418. '<div class="progress-row-bar" data-dz-uploadprogress></div>' +
  1419. '</div>',
  1420. drop: function (e) {
  1421. $('.hoverMsg').addClass('hide');
  1422. // Ensure dropped item was a file
  1423. if (e.dataTransfer.files.length > 0) {
  1424. $('#progressStatus').removeClass('hide');
  1425. $('#progressStatusBar').removeClass('hide');
  1426. $('#progressStatusBar div').css("width", "0");
  1427. }
  1428. },
  1429. uploadprogress: function (file, progress) {
  1430. $("[data-dz-name]").each(function (cnt, item) {
  1431. if ($(item).text() === file.name) {
  1432. $(item).parents(".progress-row").find("[data-dz-uploadprogress]").width(progress.toFixed() + "%");
  1433. if (progress.toFixed() === "100"){
  1434. $(item).parents(".progress-row").find("[data-dz-remove]").hide();
  1435. $(item).parents(".progress-row").find("[data-dz-uploaded]").show();
  1436. }
  1437. }
  1438. });
  1439. },
  1440. totaluploadprogress: function (progress) {
  1441. $('#progressStatusBar div').animate({
  1442. "width": progress.toFixed() + "%"
  1443. }, 100);
  1444. },
  1445. canceled: function () {
  1446. $.jHueNotify.info("${_('Upload has been canceled')}");
  1447. },
  1448. complete: function (data) {
  1449. if (data.xhr.response != '') {
  1450. var response = JSON.parse(data.xhr.response);
  1451. if (response && response.status != null) {
  1452. if (response.status != 0) {
  1453. $(document).trigger('error', response.data);
  1454. }
  1455. else {
  1456. $(document).trigger('info', response.path + "${ _(' uploaded successfully.') }");
  1457. }
  1458. }
  1459. }
  1460. }
  1461. };
  1462. _dropzone = new Dropzone(document.body, options);
  1463. _dropzone.on('queuecomplete', function () {
  1464. setTimeout(function () {
  1465. $('#progressStatus').addClass('hide');
  1466. $('#progressStatusBar').addClass('hide');
  1467. $('#progressStatusBar div').css("width", "0");
  1468. viewModel.retrieveData();
  1469. },
  1470. 2500);
  1471. });
  1472. });
  1473. }
  1474. $("#chownForm select[name='user']").change(function () {
  1475. if ($(this).val() == "__other__") {
  1476. $("input[name='user_other']").show();
  1477. } else {
  1478. $("input[name='user_other']").hide();
  1479. }
  1480. });
  1481. $("#chownForm select[name='group']").change(function () {
  1482. if ($(this).val() == "__other__") {
  1483. $("input[name='group_other']").show();
  1484. } else {
  1485. $("input[name='group_other']").hide();
  1486. }
  1487. });
  1488. $("#chownForm").submit(function () {
  1489. if ($("#chownForm select[name='user']").val() == null) {
  1490. $("#chownRequired").find(".label").text("${_('User is required.')}");
  1491. $("#chownRequired").show();
  1492. resetPrimaryButtonsStatus(); //globally available
  1493. return false;
  1494. } else if ($("#chownForm select[name='group']").val() == null) {
  1495. $("#chownRequired").find(".label").text("${_('Group is required.')}");
  1496. $("#chownRequired").show();
  1497. resetPrimaryButtonsStatus(); //globally available
  1498. return false;
  1499. } else {
  1500. if ($("#chownForm select[name='group']").val() == "__other__" && $("input[name='group_other']").val() == "") {
  1501. $("#chownRequired").find(".label").text("${_('Specify another group.')}");
  1502. $("#chownForm input[name='group_other']").addClass("fieldError");
  1503. $("#chownRequired").show();
  1504. resetPrimaryButtonsStatus(); //globally available
  1505. return false;
  1506. }
  1507. if ($("#chownForm select[name='user']").val() == "__other__" && $("input[name='user_other']").val() == "") {
  1508. $("#chownRequired").find(".label").text("${_('Specify another user.')}");
  1509. $("#chownForm input[name='user_other']").addClass("fieldError");
  1510. $("#chownRequired").show();
  1511. return false;
  1512. resetPrimaryButtonsStatus(); //globally available
  1513. }
  1514. return true;
  1515. }
  1516. });
  1517. // Modal file chooser
  1518. // The file chooser should be at least 2 levels deeper than the modal container
  1519. $(".fileChooserBtn").on('click', function (e) {
  1520. e.preventDefault();
  1521. var _destination = $(this).attr("data-filechooser-destination");
  1522. var fileChooser = $(this).parent().parent().find(".fileChooserModal");
  1523. fileChooser.jHueFileChooser({
  1524. initialPath:$("input[name='" + _destination + "']").val(),
  1525. onFolderChange:function (folderPath) {
  1526. $("input[name='" + _destination + "']").val(folderPath);
  1527. },
  1528. onFolderChoose:function (folderPath) {
  1529. $("input[name='" + _destination + "']").val(folderPath);
  1530. fileChooser.slideUp();
  1531. },
  1532. selectFolder:true,
  1533. createFolder:true,
  1534. uploadFile:false
  1535. });
  1536. fileChooser.slideDown();
  1537. });
  1538. $("#renameForm").submit(function () {
  1539. if ($("#newNameInput").val() == "") {
  1540. $("#renameNameRequiredAlert").show();
  1541. $("#newNameInput").addClass("fieldError");
  1542. resetPrimaryButtonsStatus(); //globally available
  1543. return false;
  1544. }
  1545. if (fileExists($("#newNameInput").val())) {
  1546. $("#renameNameExistsAlert").find(".newName").text($("#newNameInput").val());
  1547. $("#renameNameExistsAlert").show();
  1548. $("#newNameInput").addClass("fieldError");
  1549. resetPrimaryButtonsStatus(); //globally available
  1550. return false;
  1551. }
  1552. return true;
  1553. });
  1554. $("#newNameInput").focus(function () {
  1555. $("#renameNameRequiredAlert").hide();
  1556. $("#renameNameExistsAlert").hide();
  1557. $("#newNameInput").removeClass("fieldError");
  1558. });
  1559. $("#moveForm").on("submit", function () {
  1560. if ($.trim($("#moveDestination").val()) == "") {
  1561. $("#moveNameRequiredAlert").show();
  1562. $("#moveForm").find("input[name='*dest_path']").addClass("fieldError");
  1563. resetPrimaryButtonsStatus(); //globally available
  1564. return false;
  1565. }
  1566. return true;
  1567. });
  1568. $("#moveForm").bind("keypress", function(e) {
  1569. if (e.keyCode == 13) {
  1570. return false;
  1571. }
  1572. });
  1573. $("#moveDestination").jHueHdfsAutocomplete({
  1574. showOnFocus: true,
  1575. skipKeydownEvents: true,
  1576. onEnter: function (el) {
  1577. $("#jHueHdfsAutocomplete").hide();
  1578. }
  1579. });
  1580. $("#copyForm").on("submit", function () {
  1581. if ($.trim($("#copyDestination").val()) == "") {
  1582. $("#copyNameRequiredAlert").show();
  1583. $("#copyForm").find("input[name='*dest_path']").addClass("fieldError");
  1584. resetPrimaryButtonsStatus(); //globally available
  1585. return false;
  1586. }
  1587. return true;
  1588. });
  1589. $("#copyForm").bind("keypress", function(e) {
  1590. if (e.keyCode == 13) {
  1591. return false;
  1592. }
  1593. });
  1594. $("#copyDestination").jHueHdfsAutocomplete({
  1595. showOnFocus: true,
  1596. skipKeydownEvents: true,
  1597. onEnter: function (el) {
  1598. $("#jHueHdfsAutocomplete").hide();
  1599. }
  1600. });
  1601. $(".create-directory-link").click(function () {
  1602. $("#createDirectoryModal").modal({
  1603. keyboard:true,
  1604. show:true
  1605. });
  1606. });
  1607. $(".create-file-link").click(function () {
  1608. $("#newFileNameInput").val('');
  1609. $("#createFileModal").modal({
  1610. keyboard:true,
  1611. show:true
  1612. });
  1613. });
  1614. $("#createDirectoryForm").submit(function () {
  1615. if ($.trim($("#newDirectoryNameInput").val()) == "") {
  1616. $("#directoryNameRequiredAlert").show();
  1617. $("#newDirectoryNameInput").addClass("fieldError");
  1618. resetPrimaryButtonsStatus(); //globally available
  1619. return false;
  1620. }
  1621. if (fileExists($("#newDirectoryNameInput").val())) {
  1622. $("#directoryNameExistsAlert").find(".newName").text($("#newDirectoryNameInput").val());
  1623. $("#directoryNameExistsAlert").show();
  1624. $("#newDirectoryNameInput").addClass("fieldError");
  1625. resetPrimaryButtonsStatus(); //globally available
  1626. return false;
  1627. }
  1628. return true;
  1629. });
  1630. $("#newDirectoryNameInput").focus(function () {
  1631. $("#newDirectoryNameInput").removeClass("fieldError");
  1632. $("#directoryNameRequiredAlert").hide();
  1633. $("#directoryNameExistsAlert").hide();
  1634. });
  1635. $("#createFileForm").submit(function () {
  1636. if ($.trim($("#newFileNameInput").val()) == "") {
  1637. $("#fileNameRequiredAlert").show();
  1638. $("#newFileNameInput").addClass("fieldError");
  1639. resetPrimaryButtonsStatus(); //globally available
  1640. return false;
  1641. }
  1642. if (fileExists($("#newFileNameInput").val())) {
  1643. $("#fileNameExistsAlert").find(".newName").text($("#newFileNameInput").val());
  1644. $("#fileNameExistsAlert").show();
  1645. $("#newFileNameInput").addClass("fieldError");
  1646. resetPrimaryButtonsStatus(); //globally available
  1647. return false;
  1648. }
  1649. return true;
  1650. });
  1651. $("#newFileNameInput").focus(function () {
  1652. $("#newFileNameInput").removeClass("fieldError");
  1653. $("#fileNameRequiredAlert").hide();
  1654. $("#fileNameExistsAlert").hide();
  1655. });
  1656. $(".pathChooser").click(function () {
  1657. var self = this;
  1658. $("#fileChooserRename").jHueFileChooser({
  1659. initialPath:$(self).val(),
  1660. onFileChoose:function (filePath) {
  1661. $(self).val(filePath);
  1662. },
  1663. onFolderChange:function (folderPath) {
  1664. $(self).val(folderPath);
  1665. },
  1666. createFolder:false,
  1667. uploadFile:false
  1668. });
  1669. $("#fileChooserRename").slideDown();
  1670. });
  1671. $("*[rel='tooltip']").tooltip({ placement:"bottom" });
  1672. if (location.hash != null && location.hash.length > 1) {
  1673. var targetPath = "";
  1674. var hash = window.location.hash.substring(1).replace(/(<([^>]+)>)/ig, "");
  1675. if (hash != null && hash != "") {
  1676. targetPath = "${url('filebrowser.views.view', path='')}";
  1677. if (hash.indexOf("!!") != 0) {
  1678. targetPath += stripHashes(hash);
  1679. }
  1680. else {
  1681. targetPath = viewModel.targetPath() + hash;
  1682. }
  1683. if (targetPath.indexOf("!!") > -1) {
  1684. viewModel.targetPageNum(targetPath.substring(targetPath.indexOf("!!") + 2) * 1)
  1685. targetPath = targetPath.substring(0, targetPath.indexOf("!!"));
  1686. }
  1687. else {
  1688. viewModel.targetPageNum(1)
  1689. }
  1690. }
  1691. if (window.location.href.indexOf("#") == -1) {
  1692. viewModel.targetPageNum(1);
  1693. targetPath = "${current_request_path | n,unicode }";
  1694. }
  1695. if (targetPath != "") {
  1696. viewModel.targetPath(targetPath);
  1697. }
  1698. }
  1699. addPathToHistory(viewModel.targetPath())
  1700. viewModel.retrieveData();
  1701. $(".search-query").jHueDelayedInput(function(){
  1702. viewModel.searchQuery($(".search-query").val());
  1703. viewModel.filter();
  1704. }, 500);
  1705. $("#editBreadcrumb").click(function () {
  1706. $(this).hide();
  1707. $(".hueBreadcrumb").hide();
  1708. $("#hueBreadcrumbText").show().focus();
  1709. });
  1710. $("#hueBreadcrumbText").jHueHdfsAutocomplete({
  1711. home: "/user/${ user }/",
  1712. skipKeydownEvents: true,
  1713. onEnter: function (el) {
  1714. viewModel.targetPath("${url('filebrowser.views.view', path='')}" + stripHashes(el.val()));
  1715. viewModel.getStats(function (data) {
  1716. if (data.type != null && data.type == "file") {
  1717. location.href = data.url;
  1718. return false;
  1719. } else {
  1720. location.hash = stripHashes(el.val());
  1721. }
  1722. $("#jHueHdfsAutocomplete").hide();
  1723. });
  1724. },
  1725. onBlur: function() {
  1726. $("#hueBreadcrumbText").hide();
  1727. $(".hueBreadcrumb").show();
  1728. $("#editBreadcrumb").show();
  1729. },
  1730. smartTooltip: "${_('Did you know? You can use the tab key or CTRL + Space to autocomplete file and folder names')}"
  1731. });
  1732. $.ajaxSetup({
  1733. error:function (x, e) {
  1734. if (x.status == 500 && x.responseText.indexOf("jobbrowser") == -1) {
  1735. $(document).trigger("error", "${_('There was a problem with your request.')}");
  1736. $("#hueBreadcrumbText").blur();
  1737. }
  1738. }
  1739. });
  1740. $(window).bind("hashchange", function () {
  1741. var targetPath = "";
  1742. var hash = window.location.hash.substring(1).replace(/(<([^>]+)>)/ig, "");
  1743. if (hash != null && hash != "") {
  1744. addPathToHistory(hash);
  1745. targetPath = "${url('filebrowser.views.view', path='')}";
  1746. if (hash.indexOf("!!") != 0) {
  1747. targetPath += stripHashes(hash);
  1748. }
  1749. else {
  1750. targetPath = viewModel.targetPath() + hash;
  1751. }
  1752. if (targetPath.indexOf("!!") > -1) {
  1753. viewModel.targetPageNum(targetPath.substring(targetPath.indexOf("!!") + 2) * 1)
  1754. targetPath = targetPath.substring(0, targetPath.indexOf("!!"));
  1755. }
  1756. else {
  1757. viewModel.targetPageNum(1)
  1758. }
  1759. }
  1760. if (window.location.href.indexOf("#") == -1) {
  1761. viewModel.targetPageNum(1);
  1762. targetPath = "${current_request_path | n,unicode }";
  1763. }
  1764. if (targetPath != "") {
  1765. viewModel.targetPath(targetPath);
  1766. viewModel.retrieveData();
  1767. }
  1768. });
  1769. $(".actionbar").data("originalWidth", $(".actionbar").width());
  1770. $(".actionbarGhost").height($(".actionbar").outerHeight());
  1771. resetActionbar();
  1772. $(window).scroll(function () {
  1773. if ($(window).scrollTop() > 20) {
  1774. $(".actionbar").width($(".actionbar").data("originalWidth"));
  1775. $(".actionbar").css("position", "fixed").css("top", "73px").css("zIndex", "1001");
  1776. $(".actionbarGhost").removeClass("hide");
  1777. } else {
  1778. resetActionbar();
  1779. }
  1780. });
  1781. $("#uploadFileModal").on("shown", function () {
  1782. if (typeof _dropzone != "undefined") {
  1783. _dropzone.disable();
  1784. }
  1785. });
  1786. $("#uploadFileModal").on("hidden", function () {
  1787. if (typeof _dropzone != "undefined") {
  1788. _dropzone.enable();
  1789. }
  1790. $(".qq-upload-list").empty();
  1791. $(".qq-upload-drop-area").hide();
  1792. });
  1793. $("#uploadArchiveModal").on("shown", function () {
  1794. if (typeof _dropzone != "undefined") {
  1795. _dropzone.disable();
  1796. }
  1797. });
  1798. $("#uploadArchiveModal").on("hidden", function () {
  1799. if (typeof _dropzone != "undefined") {
  1800. _dropzone.enable();
  1801. }
  1802. $(".qq-upload-list").empty();
  1803. $(".qq-upload-drop-area").hide();
  1804. });
  1805. });
  1806. </script>
  1807. </%def>