HDFS-13470. RBF: Add Browse the Filesystem button to the UI.
This commit is contained in:
parent
50f7f6dfd1
commit
679631b188
@ -0,0 +1,323 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<link rel="stylesheet" type="text/css" href="/static/bootstrap-3.4.1/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/static/bootstrap-3.4.1/css/bootstrap-editable.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/static/dataTables.bootstrap.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/static/hadoop.css" />
|
||||
<title>Browsing HDFS</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header class="navbar navbar-inverse bs-docs-nav" role="banner">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<div class="navbar-brand">Hadoop</div>
|
||||
</div>
|
||||
|
||||
<ul class="nav navbar-nav" id="ui-tabs">
|
||||
<li><a href="federationhealth.html#tab-overview">Overview</a></li>
|
||||
<li><a href="federationhealth.html#tab-namenode">Subclusters</a></li>
|
||||
<li><a href="federationhealth.html#tab-router">Routers</a></li>
|
||||
<li><a href="federationhealth.html#tab-datanode">Datanodes</a></li>
|
||||
<li><a href="federationhealth.html#tab-mounttable">Mount table</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Utilities <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#">Browse the file system</a></li>
|
||||
<li><a href="logs">Logs</a></li>
|
||||
<li><a href="logLevel">Log Level</a></li>
|
||||
<li><a href="jmx">Metrics</a></li>
|
||||
<li><a href="conf">Configuration</a></li>
|
||||
<li><a href="stacks">Process Thread Dump</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="modal" id="file-info" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="file-info-title">File information</h4>
|
||||
</div>
|
||||
<div class="modal-body" id="file-info-body">
|
||||
<div class=row>
|
||||
<span class="col-xs-4">
|
||||
<a id="file-info-download">Download</a>
|
||||
</span>
|
||||
<span class="col-xs-4">
|
||||
<a id="file-info-preview-head" style="cursor:pointer">Head the file (first 32K)</a>
|
||||
</span>
|
||||
<span class="col-xs-4">
|
||||
<a id="file-info-preview-tail" style="cursor:pointer">Tail the file (last 32K)</a>
|
||||
</span>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="panel panel-success" id="file-info-blockinfo-panel">
|
||||
<div class="panel-heading">
|
||||
Block information --
|
||||
<select class="btn btn-default" id="file-info-blockinfo-list">
|
||||
</select>
|
||||
</div>
|
||||
<div class="panel-body" id="file-info-blockinfo-body"></div>
|
||||
</div>
|
||||
<div class="panel panel-info" id="file-info-tail" style="display:none">
|
||||
<div class="panel-heading">File contents</div>
|
||||
<div class="panel-body">
|
||||
<div class="input-group-sm">
|
||||
<textarea class="form-control" style="height: 150px" id="file-info-preview-body"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer"><button type="button" class="btn btn-success"
|
||||
data-dismiss="modal">Close</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="page-header">
|
||||
<h1>Browse Directory</h1>
|
||||
</div>
|
||||
<div class="alert alert-danger" id="alert-panel" style="display:none">
|
||||
<button type="button" class="close" onclick="$('#alert-panel').hide();">×</button>
|
||||
<div class="alert-body" id="alert-panel-body"></div>
|
||||
</div>
|
||||
<div class="modal" id="btn-create-directory" tabindex="-1" role="dialog"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close"
|
||||
data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title">Create Directory</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon" id="new_directory_pwd"></span>
|
||||
<input type="text" class="form-control" id="new_directory"
|
||||
placeholder="New Directory Name" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success"
|
||||
id="btn-create-directory-send" data-complete-text="Creating...">
|
||||
Create
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal" id="modal-upload-file" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header"><button type="button" class="close"
|
||||
data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="file-upload-title">Upload File</h4>
|
||||
</div>
|
||||
<div class="modal-body" id="file-upload-body">
|
||||
<input id="modal-upload-file-input" type="file" class="file" multiple>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-success" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-success" id="modal-upload-file-button" data-complete-text="Uploading...">Upload</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal" id="delete-modal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"
|
||||
aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" id="delete-modal-title">Delete</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="panel-body">
|
||||
<div id="delete-prompt"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" id="delete-button"
|
||||
data-complete-text="Deleting...">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-10 col-md-10">
|
||||
<form onsubmit="return false;">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="directory"/>
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default" type="button" id="btn-nav-directory">Go!</button>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-xs-2 col-md-2">
|
||||
<button type="button" class="btn btn-default" data-toggle="modal"
|
||||
aria-label="New Directory" data-target="#btn-create-directory"
|
||||
title="Create Directory" id="btn-create-dir">
|
||||
<span class="glyphicon glyphicon-folder-open"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default" data-toggle="modal"
|
||||
data-target="#modal-upload-file" title="Upload Files" id="btn-upload-files">
|
||||
<span class="glyphicon glyphicon-cloud-upload"></span>
|
||||
</button>
|
||||
<button class="btn btn-default dropdown-toggle" type="button"
|
||||
data-toggle="dropdown" title="Cut & Paste">
|
||||
<span class="glyphicon glyphicon-list-alt"></span></button>
|
||||
<ul class="dropdown-menu cut-paste">
|
||||
<li><a id="explorer-cut">Cut</a></li>
|
||||
<li><a id="explorer-paste">Paste</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<div id="panel"></div>
|
||||
|
||||
<div class="row">
|
||||
<hr />
|
||||
<div class="col-xs-2"><p>Hadoop, {release-year-token}.</p></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/x-template" id="explorer-popover-perm-info">
|
||||
<div class="explorer-popover-perm-body">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">User</th>
|
||||
<th class="text-center">Group</th>
|
||||
<th class="text-center">Other</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><label><input type="checkbox" data-bit="8" /> Read</label></td>
|
||||
<td><label><input type="checkbox" data-bit="5" /> Read</label></td>
|
||||
<td><label><input type="checkbox" data-bit="2" /> Read</label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label><input type="checkbox" data-bit="7" /> Write</label></td>
|
||||
<td><label><input type="checkbox" data-bit="4" /> Write</label></td>
|
||||
<td><label><input type="checkbox" data-bit="1" /> Write</label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label><input type="checkbox" data-bit="6" /> Execute</label></td>
|
||||
<td><label><input type="checkbox" data-bit="3" /> Execute</label></td>
|
||||
<td><label><input type="checkbox" data-bit="0" /> Execute</label></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="text-align: right; margin-right: 10px">
|
||||
<label><input type="checkbox" id="explorer-perm-sticky" data-bit="9" /> Sticky bit</label>
|
||||
</div>
|
||||
<hr/>
|
||||
<div style="text-align: right">
|
||||
<button type="button" class="btn" id="explorer-perm-cancel">Cancel</button>
|
||||
<button type="button" class="btn btn-success" id="explorer-set-perm-button"
|
||||
data-complete-text="Updating...">Set</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-dust-template" id="tmpl-explorer">
|
||||
<table class="table" id="table-explorer">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input type="checkbox" id="file-selector-all"></th>
|
||||
<th title="Permissions">Permission</th>
|
||||
<th>Owner</th>
|
||||
<th>Group</th>
|
||||
<th>Size</th>
|
||||
<th title="Last Modified">Last Modified</th>
|
||||
<th title="Replication">Replication</th>
|
||||
<th>Block Size</th>
|
||||
<th>Name</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#FileStatus}
|
||||
<tr inode-path="{pathSuffix}" data-permission="{permission}"
|
||||
class="explorer-entry">
|
||||
<td><input type="checkbox" class="file_selector"> </td>
|
||||
<td><span class="explorer-perm-links editable-click">
|
||||
{type|helper_to_directory}{permission|helper_to_permission}
|
||||
{aclBit|helper_to_acl_bit}
|
||||
</span></td>
|
||||
<td><span class="explorer-owner-links">{owner}</span></td>
|
||||
<td><span class="explorer-group-links">{group}</span></td>
|
||||
<td>{length}</td>
|
||||
<td>{modificationTime}</td>
|
||||
<td><span class="explorer-replication-links">{replication}</span></td>
|
||||
<td>{blockSize|fmt_bytes}</td>
|
||||
<td><a inode-type="{type}" class="explorer-browse-links">{pathSuffix}</a></td>
|
||||
<td><span class="glyphicon glyphicon-trash"></span></td>
|
||||
</tr>
|
||||
{/FileStatus}
|
||||
</tbody>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script type="text/x-dust-template" id="tmpl-block-info">
|
||||
{#block}
|
||||
<p>Block ID: {blockId}</p>
|
||||
<p>Block Pool ID: {blockPoolId}</p>
|
||||
<p>Generation Stamp: {generationStamp}</p>
|
||||
<p>Size: {numBytes}</p>
|
||||
{/block}
|
||||
<p>Availability:
|
||||
<ul>
|
||||
{#locations}
|
||||
<li>{hostName}</li>
|
||||
{/locations}
|
||||
</ul>
|
||||
</p>
|
||||
</script>
|
||||
<script type="text/javascript" src="/static/jquery-3.4.1.min.js">
|
||||
</script><script type="text/javascript" src="/static/jquery.dataTables.min.js">
|
||||
</script><script type="text/javascript" src="/static/bootstrap-3.4.1/js/bootstrap.min.js">
|
||||
</script><script type="text/javascript" src="/static/bootstrap-3.4.1/js/bootstrap-editable.min.js">
|
||||
</script><script type="text/javascript" src="/static/dataTables.bootstrap.js">
|
||||
</script><script type="text/javascript" src="/static/dust-full-2.0.0.min.js">
|
||||
</script><script type="text/javascript" src="/static/dust-helpers-1.1.1.min.js">
|
||||
</script><script type="text/javascript" src="/static/dfs-dust.js">
|
||||
</script><script type="text/javascript" src="/static/json-bignum.js">
|
||||
</script><script type="text/javascript" src="/static/rest-csrf.js">
|
||||
</script><script type="text/javascript" src="explorer.js">
|
||||
</script><script type="text/javascript" src="/static/moment.min.js">
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,552 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
// The chunk size of tailing the files, i.e., how many bytes will be shown
|
||||
// in the preview.
|
||||
var TAIL_CHUNK_SIZE = 32768;
|
||||
|
||||
//This stores the current directory which is being browsed
|
||||
var current_directory = "";
|
||||
|
||||
function show_err_msg(msg) {
|
||||
$('#alert-panel-body').html(msg);
|
||||
$('#alert-panel').show();
|
||||
}
|
||||
|
||||
$(window).bind('hashchange', function () {
|
||||
$('#alert-panel').hide();
|
||||
|
||||
var dir = decodeURIComponent(window.location.hash.slice(1));
|
||||
if(dir == "") {
|
||||
dir = "/";
|
||||
}
|
||||
if(current_directory != dir) {
|
||||
browse_directory(dir);
|
||||
}
|
||||
});
|
||||
|
||||
function network_error_handler(url) {
|
||||
return function (jqxhr, text, err) {
|
||||
switch(jqxhr.status) {
|
||||
case 401:
|
||||
var msg = '<p>Authentication failed when trying to open ' + url + ': Unauthorized.</p>';
|
||||
break;
|
||||
case 403:
|
||||
if(jqxhr.responseJSON !== undefined && jqxhr.responseJSON.RemoteException !== undefined) {
|
||||
var msg = '<p>' + jqxhr.responseJSON.RemoteException.message + "</p>";
|
||||
break;
|
||||
}
|
||||
var msg = '<p>Permission denied when trying to open ' + url + ': ' + err + '</p>';
|
||||
break;
|
||||
case 404:
|
||||
var msg = '<p>Path does not exist on HDFS or WebHDFS is disabled. Please check your path or enable WebHDFS</p>';
|
||||
break;
|
||||
default:
|
||||
var msg = '<p>Failed to retrieve data from ' + url + ': ' + err + '</p>';
|
||||
}
|
||||
show_err_msg(msg);
|
||||
};
|
||||
}
|
||||
|
||||
function append_path(prefix, s) {
|
||||
var l = prefix.length;
|
||||
var p = l > 0 && prefix[l - 1] == '/' ? prefix.substring(0, l - 1) : prefix;
|
||||
return p + '/' + s;
|
||||
}
|
||||
|
||||
function get_response(data, type) {
|
||||
return data[type] !== undefined ? data[type] : null;
|
||||
}
|
||||
|
||||
function get_response_err_msg(data) {
|
||||
return data.RemoteException !== undefined ? data.RemoteException.message : "";
|
||||
}
|
||||
|
||||
function delete_path(inode_name, absolute_file_path) {
|
||||
$('#delete-modal-title').text("Delete - " + inode_name);
|
||||
$('#delete-prompt').text("Are you sure you want to delete " + inode_name
|
||||
+ " ?");
|
||||
|
||||
$('#delete-button').click(function() {
|
||||
// DELETE /webhdfs/v1/<path>?op=DELETE&recursive=<true|false>
|
||||
var url = '/webhdfs/v1' + encode_path(absolute_file_path) +
|
||||
'?op=DELETE' + '&recursive=true';
|
||||
|
||||
$.ajax(url,
|
||||
{ type: 'DELETE'
|
||||
}).done(function(data) {
|
||||
browse_directory(current_directory);
|
||||
}).fail(network_error_handler(url)
|
||||
).always(function() {
|
||||
$('#delete-modal').modal('hide');
|
||||
$('#delete-button').button('reset');
|
||||
});
|
||||
})
|
||||
$('#delete-modal').modal();
|
||||
}
|
||||
|
||||
/* This method loads the checkboxes on the permission info modal. It accepts
|
||||
* the octal permissions, eg. '644' or '755' and infers the checkboxes that
|
||||
* should be true and false
|
||||
*/
|
||||
function view_perm_details(e, filename, abs_path, perms) {
|
||||
$('.explorer-perm-links').popover('destroy');
|
||||
e.popover({html: true, content: $('#explorer-popover-perm-info').html(), trigger: 'focus'})
|
||||
.on('shown.bs.popover', function(e) {
|
||||
var popover = $(this), parent = popover.parent();
|
||||
//Convert octal to binary permissions
|
||||
var bin_perms = parseInt(perms, 8).toString(2);
|
||||
bin_perms = bin_perms.length == 9 ? "0" + bin_perms : bin_perms;
|
||||
parent.find('#explorer-perm-cancel').on('click', function() { popover.popover('destroy'); });
|
||||
parent.find('#explorer-set-perm-button').off().click(function() { set_permissions(abs_path); });
|
||||
parent.find('input[type=checkbox]').each(function(idx, element) {
|
||||
var e = $(element);
|
||||
e.prop('checked', bin_perms.charAt(9 - e.attr('data-bit')) == '1');
|
||||
});
|
||||
})
|
||||
.popover('show');
|
||||
}
|
||||
|
||||
// Use WebHDFS to set permissions on an absolute path
|
||||
function set_permissions(abs_path) {
|
||||
var p = 0;
|
||||
$.each($('.popover .explorer-popover-perm-body input:checked'), function(idx, e) {
|
||||
p |= 1 << (+$(e).attr('data-bit'));
|
||||
});
|
||||
|
||||
var permission_mask = p.toString(8);
|
||||
|
||||
// PUT /webhdfs/v1/<path>?op=SETPERMISSION&permission=<permission>
|
||||
var url = '/webhdfs/v1' + encode_path(abs_path) +
|
||||
'?op=SETPERMISSION' + '&permission=' + permission_mask;
|
||||
|
||||
$.ajax(url, { type: 'PUT'
|
||||
}).done(function(data) {
|
||||
browse_directory(current_directory);
|
||||
}).fail(network_error_handler(url))
|
||||
.always(function() {
|
||||
$('.explorer-perm-links').popover('destroy');
|
||||
});
|
||||
}
|
||||
|
||||
function encode_path(abs_path) {
|
||||
abs_path = encodeURIComponent(abs_path);
|
||||
var re = /%2F/g;
|
||||
return abs_path.replace(re, '/');
|
||||
}
|
||||
|
||||
function view_file_details(path, abs_path) {
|
||||
function show_block_info(blocks) {
|
||||
var menus = $('#file-info-blockinfo-list');
|
||||
menus.empty();
|
||||
|
||||
menus.data("blocks", blocks);
|
||||
menus.change(function() {
|
||||
var d = $(this).data('blocks')[$(this).val()];
|
||||
if (d === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
dust.render('block-info', d, function(err, out) {
|
||||
$('#file-info-blockinfo-body').html(out);
|
||||
});
|
||||
|
||||
});
|
||||
for (var i = 0; i < blocks.length; ++i) {
|
||||
var item = $('<option value="' + i + '">Block ' + i + '</option>');
|
||||
menus.append(item);
|
||||
}
|
||||
menus.change();
|
||||
}
|
||||
|
||||
abs_path = encode_path(abs_path);
|
||||
var url = '/webhdfs/v1' + abs_path + '?op=GET_BLOCK_LOCATIONS';
|
||||
$.ajax({url: url, dataType: 'text'}).done(function(data_text) {
|
||||
var data = JSONParseBigNum(data_text);
|
||||
var d = get_response(data, "LocatedBlocks");
|
||||
if (d === null) {
|
||||
show_err_msg(get_response_err_msg(data));
|
||||
return;
|
||||
}
|
||||
|
||||
$('#file-info-tail').hide();
|
||||
$('#file-info-title').text("File information - " + path);
|
||||
|
||||
var download_url = '/webhdfs/v1' + abs_path + '?op=OPEN';
|
||||
|
||||
$('#file-info-download').attr('href', download_url);
|
||||
|
||||
var processPreview = function(url) {
|
||||
url += "&noredirect=true";
|
||||
if(request && request.readyState != 4){
|
||||
request.abort();
|
||||
}
|
||||
request = $.ajax({
|
||||
cache: false,
|
||||
type: 'GET',
|
||||
url: url,
|
||||
async: false,
|
||||
processData: false,
|
||||
crossDomain: true
|
||||
}).done(function(data, textStatus, jqXHR) {
|
||||
|
||||
url = data.Location;
|
||||
$.ajax({
|
||||
cache: false,
|
||||
type: 'GET',
|
||||
url: url,
|
||||
async: false,
|
||||
processData: false,
|
||||
crossDomain: true
|
||||
}).always(function(data, textStatus, jqXHR) {
|
||||
$('#file-info-preview-body').val(jqXHR.responseText);
|
||||
$('#file-info-tail').show();
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
show_err_msg("Couldn't preview the file. " + errorThrown);
|
||||
});
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
show_err_msg("Couldn't find datanode to read file from. " + errorThrown);
|
||||
});
|
||||
}
|
||||
|
||||
var request = null;
|
||||
$('#file-info-preview-tail')
|
||||
.off('click')
|
||||
.on('click', function() {
|
||||
var offset = d.fileLength - TAIL_CHUNK_SIZE;
|
||||
var url = offset > 0 ? download_url + '&offset=' + offset : download_url;
|
||||
processPreview(url);
|
||||
});
|
||||
$('#file-info-preview-head')
|
||||
.off('click')
|
||||
.on('click', function() {
|
||||
var url = d.fileLength > TAIL_CHUNK_SIZE ? download_url + '&length=' + TAIL_CHUNK_SIZE : download_url;
|
||||
processPreview(url);
|
||||
});
|
||||
|
||||
if (d.fileLength > 0) {
|
||||
show_block_info(d.locatedBlocks);
|
||||
$('#file-info-blockinfo-panel').show();
|
||||
} else {
|
||||
$('#file-info-blockinfo-panel').hide();
|
||||
}
|
||||
$('#file-info').modal();
|
||||
}).fail(network_error_handler(url));
|
||||
}
|
||||
|
||||
/**Use X-editable to make fields editable with a nice UI.
|
||||
* elementType is the class of element(s) you want to make editable
|
||||
* op is the WebHDFS operation that will be triggered
|
||||
* parameter is (currently the 1) parameter which will be passed along with
|
||||
* the value entered by the user
|
||||
*/
|
||||
function makeEditable(elementType, op, parameter) {
|
||||
$(elementType).each(function(index, value) {
|
||||
$(this).editable({
|
||||
url: function(params) {
|
||||
var inode_name = $(this).closest('tr').attr('inode-path');
|
||||
var absolute_file_path = append_path(current_directory, inode_name);
|
||||
var url = '/webhdfs/v1' + encode_path(absolute_file_path) + '?op=' +
|
||||
op + '&' + parameter + '=' + encodeURIComponent(params.value);
|
||||
|
||||
return $.ajax(url, { type: 'PUT', })
|
||||
.fail(network_error_handler(url))
|
||||
.done(function() {
|
||||
browse_directory(current_directory);
|
||||
});
|
||||
},
|
||||
error: function(response, newValue) {return "";}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function func_size_render(data, type, row, meta) {
|
||||
if(type == 'display') {
|
||||
return dust.filters.fmt_bytes(data);
|
||||
}
|
||||
else return data;
|
||||
}
|
||||
|
||||
// Change the format of date-time depending on how old the
|
||||
// the timestamp is. If older than 6 months, no need to be
|
||||
// show exact time.
|
||||
function func_time_render(data, type, row, meta) {
|
||||
if(type == 'display') {
|
||||
var cutoff = moment().subtract(6, 'months').unix() * 1000;
|
||||
if(data < cutoff) {
|
||||
return moment(Number(data)).format('MMM DD YYYY');
|
||||
} else {
|
||||
return moment(Number(data)).format('MMM DD HH:mm');
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function browse_directory(dir) {
|
||||
var HELPERS = {
|
||||
'helper_date_tostring' : function (chunk, ctx, bodies, params) {
|
||||
var value = dust.helpers.tap(params.value, chunk, ctx);
|
||||
return chunk.write('' + moment(Number(value)).format('ddd MMM DD HH:mm:ss ZZ YYYY'));
|
||||
}
|
||||
};
|
||||
var url = '/webhdfs/v1' + encode_path(dir) + '?op=LISTSTATUS';
|
||||
$.get(url, function(data) {
|
||||
var d = get_response(data, "FileStatuses");
|
||||
if (d === null) {
|
||||
show_err_msg(get_response_err_msg(data));
|
||||
return;
|
||||
}
|
||||
|
||||
current_directory = dir;
|
||||
$('#directory').val(dir);
|
||||
window.location.hash = dir;
|
||||
var base = dust.makeBase(HELPERS);
|
||||
dust.render('explorer', base.push(d), function(err, out) {
|
||||
$('#panel').html(out);
|
||||
|
||||
|
||||
$('.explorer-browse-links').click(function() {
|
||||
var type = $(this).attr('inode-type');
|
||||
var path = $(this).closest('tr').attr('inode-path');
|
||||
var abs_path = append_path(current_directory, path);
|
||||
if (type == 'DIRECTORY') {
|
||||
browse_directory(abs_path);
|
||||
} else {
|
||||
view_file_details(path, abs_path);
|
||||
}
|
||||
});
|
||||
|
||||
//Set the handler for changing permissions
|
||||
$('.explorer-perm-links').click(function() {
|
||||
var filename = $(this).closest('tr').attr('inode-path');
|
||||
var abs_path = append_path(current_directory, filename);
|
||||
var perms = $(this).closest('tr').attr('data-permission');
|
||||
view_perm_details($(this), filename, abs_path, perms);
|
||||
});
|
||||
|
||||
makeEditable('.explorer-owner-links', 'SETOWNER', 'owner');
|
||||
makeEditable('.explorer-group-links', 'SETOWNER', 'group');
|
||||
makeEditable('.explorer-replication-links', 'SETREPLICATION', 'replication');
|
||||
|
||||
$('.explorer-entry .glyphicon-trash').click(function() {
|
||||
var inode_name = $(this).closest('tr').attr('inode-path');
|
||||
var absolute_file_path = append_path(current_directory, inode_name);
|
||||
delete_path(inode_name, absolute_file_path);
|
||||
});
|
||||
|
||||
$('#file-selector-all').click(function() {
|
||||
$('.file_selector').prop('checked', $('#file-selector-all')[0].checked );
|
||||
});
|
||||
|
||||
//This needs to be last because it repaints the table
|
||||
$('#table-explorer').dataTable( {
|
||||
'lengthMenu': [ [25, 50, 100, -1], [25, 50, 100, "All"] ],
|
||||
'columns': [
|
||||
{ 'orderable' : false }, //select
|
||||
{'searchable': false }, //Permissions
|
||||
null, //Owner
|
||||
null, //Group
|
||||
{ 'searchable': false, 'render': func_size_render}, //Size
|
||||
{ 'searchable': false, 'render': func_time_render}, //Last Modified
|
||||
{ 'searchable': false }, //Replication
|
||||
null, //Block Size
|
||||
null, //Name
|
||||
{ 'orderable' : false } //Trash
|
||||
],
|
||||
"deferRender": true
|
||||
});
|
||||
});
|
||||
}).fail(network_error_handler(url));
|
||||
}
|
||||
|
||||
|
||||
function init() {
|
||||
dust.loadSource(dust.compile($('#tmpl-explorer').html(), 'explorer'));
|
||||
dust.loadSource(dust.compile($('#tmpl-block-info').html(), 'block-info'));
|
||||
|
||||
var b = function() { browse_directory($('#directory').val()); };
|
||||
$('#btn-nav-directory').click(b);
|
||||
//Also navigate to the directory when a user presses enter.
|
||||
$('#directory').on('keyup', function (e) {
|
||||
if (e.which == 13) {
|
||||
browse_directory($('#directory').val());
|
||||
}
|
||||
});
|
||||
var dir = window.location.hash.slice(1);
|
||||
if(dir == "") {
|
||||
window.location.hash = "/";
|
||||
} else {
|
||||
browse_directory(dir);
|
||||
}
|
||||
}
|
||||
|
||||
$('#btn-create-directory').on('show.bs.modal', function(event) {
|
||||
$('#new_directory_pwd').text(current_directory);
|
||||
});
|
||||
|
||||
$('#btn-create-directory-send').click(function () {
|
||||
$(this).prop('disabled', true);
|
||||
$(this).button('complete');
|
||||
|
||||
var url = '/webhdfs/v1' + encode_path(append_path(current_directory,
|
||||
$('#new_directory').val())) + '?op=MKDIRS';
|
||||
|
||||
$.ajax(url, { type: 'PUT' }
|
||||
).done(function(data) {
|
||||
browse_directory(current_directory);
|
||||
}).fail(network_error_handler(url)
|
||||
).always(function() {
|
||||
$('#btn-create-directory').modal('hide');
|
||||
$('#btn-create-directory-send').button('reset');
|
||||
});
|
||||
})
|
||||
|
||||
$('#btn-upload-files').click(function() {
|
||||
$('#modal-upload-file-button').prop('disabled', true).button('reset');
|
||||
$('#modal-upload-file-input').val(null);
|
||||
});
|
||||
|
||||
$('#btn-create-dir').click(function() {
|
||||
$('#btn-create-directory-send').prop('disabled', true).button('reset');
|
||||
$('#new_directory').val(null);
|
||||
});
|
||||
|
||||
$('#modal-upload-file-input').change(function() {
|
||||
if($('#modal-upload-file-input').prop('files').length >0) {
|
||||
$('#modal-upload-file-button').prop('disabled', false);
|
||||
}
|
||||
else {
|
||||
$('#modal-upload-file-button').prop('disabled', true);
|
||||
}
|
||||
});
|
||||
|
||||
$('#new_directory').on('keyup keypress blur change',function() {
|
||||
if($('#new_directory').val() == '' || $('#new_directory').val() == null) {
|
||||
$('#btn-create-directory-send').prop('disabled', true);
|
||||
}
|
||||
else {
|
||||
$('#btn-create-directory-send').prop('disabled', false);
|
||||
}
|
||||
});
|
||||
|
||||
$('#modal-upload-file-button').click(function() {
|
||||
$(this).prop('disabled', true);
|
||||
$(this).button('complete');
|
||||
var files = []
|
||||
var numCompleted = 0
|
||||
|
||||
for(var i = 0; i < $('#modal-upload-file-input').prop('files').length; i++) {
|
||||
(function() {
|
||||
var file = $('#modal-upload-file-input').prop('files')[i];
|
||||
var url = '/webhdfs/v1' + encode_path(append_path(current_directory, file.name));
|
||||
url += '?op=CREATE&noredirect=true';
|
||||
files.push( { file: file } )
|
||||
files[i].request = $.ajax({
|
||||
type: 'PUT',
|
||||
url: url,
|
||||
processData: false,
|
||||
crossDomain: true
|
||||
});
|
||||
})()
|
||||
}
|
||||
for(var f in files) {
|
||||
(function() {
|
||||
var file = files[f];
|
||||
file.request.done(function(data) {
|
||||
var url = data['Location'];
|
||||
$.ajax({
|
||||
type: 'PUT',
|
||||
url: url,
|
||||
data: file.file,
|
||||
processData: false,
|
||||
crossDomain: true
|
||||
}).always(function(data) {
|
||||
numCompleted++;
|
||||
if(numCompleted == files.length) {
|
||||
reset_upload_button();
|
||||
browse_directory(current_directory);
|
||||
}
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
numCompleted++;
|
||||
reset_upload_button();
|
||||
show_err_msg("Couldn't upload the file " + file.file.name + ". "+ errorThrown);
|
||||
});
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
numCompleted++;
|
||||
reset_upload_button();
|
||||
show_err_msg("Couldn't find datanode to write file. " + errorThrown);
|
||||
});
|
||||
})();
|
||||
}
|
||||
});
|
||||
|
||||
//Reset the upload button
|
||||
function reset_upload_button() {
|
||||
$('#modal-upload-file').modal('hide');
|
||||
$('#modal-upload-file-button').button('reset');
|
||||
}
|
||||
|
||||
//Store the list of files which have been checked into session storage
|
||||
function store_selected_files(current_directory) {
|
||||
sessionStorage.setItem("source_directory", current_directory);
|
||||
var selected_files = $("input:checked.file_selector");
|
||||
var selected_file_names = new Array();
|
||||
selected_files.each(function(index) {
|
||||
selected_file_names[index] = $(this).closest('tr').attr('inode-path');
|
||||
})
|
||||
sessionStorage.setItem("selected_file_names", JSON.stringify(selected_file_names));
|
||||
alert("Cut " + selected_file_names.length + " files/directories");
|
||||
}
|
||||
|
||||
//Retrieve the list of files from session storage and rename them to the current
|
||||
//directory
|
||||
function paste_selected_files() {
|
||||
var files = JSON.parse(sessionStorage.getItem("selected_file_names"));
|
||||
var source_directory = sessionStorage.getItem("source_directory");
|
||||
$.each(files, function(index, value) {
|
||||
var url = "/webhdfs/v1"
|
||||
+ encode_path(append_path(source_directory, value))
|
||||
+ '?op=RENAME&destination='
|
||||
+ encode_path(append_path(current_directory, value));
|
||||
$.ajax({
|
||||
type: 'PUT',
|
||||
url: url
|
||||
}).done(function(data) {
|
||||
if(index == files.length - 1) {
|
||||
browse_directory(current_directory);
|
||||
}
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
show_err_msg("Couldn't move file " + value + ". " + errorThrown);
|
||||
});
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
$('#explorer-cut').click(function() {
|
||||
store_selected_files(current_directory);
|
||||
});
|
||||
|
||||
$('#explorer-paste').click(function() {
|
||||
paste_selected_files();
|
||||
});
|
||||
|
||||
|
||||
init();
|
||||
})();
|
@ -41,9 +41,12 @@
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Utilities <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="explorer.html">Browse the file system</a></li>
|
||||
<li><a href="logs">Logs</a></li>
|
||||
<li><a href="logLevel">Log Level</a></li>
|
||||
<li><a href="jmx">Metrics</a></li>
|
||||
<li><a href="conf">Configuration</a></li>
|
||||
<li><a href="logs">Logs</a></li>
|
||||
<li><a href="stacks">Process Thread Dump</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
Loading…
Reference in New Issue
Block a user