Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding filemanager with dragdrop #139

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Kudu.Services.Web/Pages/NewUI/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@
<li>
<a href="/newui/logs">Browse Logs Dir</a>
</li>
<li>
<a href="/newui/fileManager">File Manager</a>
</li>
<li>
<a href="/newui/jsonviewer?view_url=/api/scan/start">Scan file system</a>
</li>
Expand Down
91 changes: 48 additions & 43 deletions Kudu.Services.Web/Pages/NewUI/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -69,49 +69,54 @@
<div class="row">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove Browse wwwroot, Browse LogFiles from the App Essentials tab in Index.xshtml

<nav class="col-md-2 d-none d-md-block bg-light sidebar">
<div class="sidebar-sticky">
<ul class="nav flex-column" style="padding-top: 10px">
<li class="nav-item">
<a class="nav-link active" href="/newui">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>
Home <span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/newui/env">
<i class="feather fas fa-tasks clr-icon-navbar"></i> Environment
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/newui/webssh">
<i class="feather fas fa-terminal clr-icon-navbar"></i> WebSSH
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/newui/kududebug">
<i class="feather fas fa-laptop-code clr-icon-navbar"></i> Bash
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/api/logstream" title="If no log events are being generated the page may not load.">
<i class="feather fas fa-stream clr-icon-navbar"></i> Log stream
</a>
</li>
<li class="nav-item" hidden>
<a class="nav-link" href="#">
<i class="feather fas fa-user-md clr-icon-navbar"></i> App Lens
</a>
</li>
<li class="nav-item" hidden>
<a class="nav-link" href="#">
<i class="feather fas fa-globe-americas clr-icon-navbar"></i> Kudu REST APIs
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://code.visualstudio.com/docs/azure/remote-debugging">
<i class="feather fas fa-bolt clr-icon-navbar"></i> VSCode Remote Debugging
</a>
</li>
</ul>
<ul class="nav flex-column" style="padding-top: 10px">
<li class="nav-item">
<a class="nav-link active" href="/newui">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>
Home <span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/newui/env">
<i class="feather fas fa-tasks clr-icon-navbar"></i> Environment
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/newui/webssh">
<i class="feather fas fa-terminal clr-icon-navbar"></i> WebSSH
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/newui/kududebug">
<i class="feather fas fa-laptop-code clr-icon-navbar"></i> Bash
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/newui/fileManager">
<i class="feather fas fa fa-folder-open clr-icon-navbar"></i> File Manager
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/api/logstream" title="If no log events are being generated the page may not load.">
<i class="feather fas fa-stream clr-icon-navbar"></i> Log stream
</a>
</li>
<li class="nav-item" hidden>
<a class="nav-link" href="#">
<i class="feather fas fa-user-md clr-icon-navbar"></i> App Lens
</a>
</li>
<li class="nav-item" hidden>
<a class="nav-link" href="#">
<i class="feather fas fa-globe-americas clr-icon-navbar"></i> Kudu REST APIs
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://code.visualstudio.com/docs/azure/remote-debugging">
<i class="feather fas fa-bolt clr-icon-navbar"></i> VSCode Remote Debugging
</a>
</li>
</ul>
<!--
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Deploying on App Service for Linux</span>
Expand Down
278 changes: 278 additions & 0 deletions Kudu.Services.Web/Pages/NewUI/fileManager.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
@page
@using Kudu.Core;
@using Kudu.Services
@using Microsoft.Extensions.FileProviders;


<link href="~/css/dropzone.min.css" rel="stylesheet" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>

<h4>File Manager</h4>

@*anchor tag to return back to previous directory; span - 'spaddPath' is used to keep track of current directory.*@
<h6><a id="aCurPath" style="color:#0062cc; font-weight:bold;" href="#">...</a><span id="spaddPath"></span></h6>
<form id="upload-widget" method="post" action="/upload" class="dropzone" style="border:none; padding:none;">
<div id="divFileManager">
</div>
</form>

@*Calling dropzone JavaScript*@
<script src="~/Content/Scripts/dropzone.min.js"></script>

<script type="text/javascript">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's refactor this to a JS file in /Content/Scripts

Dropzone.options.uploadWidget = {
addRemoveLinks: true,
disablePreview: true,
dictDefaultMessage: 'Drag a File/Folder here to upload, or click to select one',
accept: function (file, done) {
$('.dz-preview.dz-file-preview').css("display", "none"); //removing preview element of dropzone
// Create a FormData object.
var formData = new FormData();
formData.append('file', file);
if (file.fullPath == undefined) {
var url = '/api/vfs/' + curPath + file.name;
}
else {
var url = '/api/vfs/' + curPath + file.fullPath;
}

if (formData) {
$.ajax({
url: url,
type: "PUT",
enctype: 'application/x-www-form-urlencoded; charset=UTF-8',
//headers: {
// "Content-Type": "multipart/form-data"
//},
data: file,
processData: false,
contentType: false,
success: function (res) {
$(".dz-default.dz-message").css("display", "block");
$.get(("/api/vfs" + curPath.trim()), null, function (data) {
generateDynamicTable(data);
});
},
error: function (error) {
alert("Error while PUT request!");
}
});
}
}
};
</script>
<script>
var root = "/";
var curPath = "/";

$.get("/api/vfs", null, function (data) {
generateDynamicTable(data);
});

function generateDynamicTable(fileContent) {
var dataFileManager = fileContent.length + 1;

if (dataFileManager > 0) {

//generation of dynamic table, based on data.
var table = document.createElement("table");
table.id = "fileManagerTable";
table.className = "table table-striped table-bordered table-hover table-condensed table-responsive";
table.style.width = '90%';
table.style.display = 'table';

// retrieve column header
var col = []; // define an empty array
for (var i = 0; i < dataFileManager; i++) {
for (var key in fileContent[i]) {
if (col.indexOf(key) === -1) {
col.push(key);
}
}
}

// CREATE TABLE HEAD .
var tHead = document.createElement("thead");


//Add table header row
var hRow = document.createElement("tr");

//Add an empty default column for the table
var emptyHeader = document.createElement("th");
emptyHeader.style.width = "10%";
hRow.appendChild(emptyHeader);

//Adding column headers (with header names) to the table.
for (var i = 0; i < col.length; i++) {
var th = document.createElement("th");
if ((col[i] != "name") && (col[i] != "size") && (col[i] != "mtime")) {
th.innerHTML = col[i];
th.style.display = "none";
}
if (col[i] == "name") {
th.style.width = "50%";
th.innerText = "Name";
}
if (col[i] == "size") {
th.style.width = "20%";
th.innerText = "Size";
}
if (col[i] == "mtime") {
th.style.width = "20%";
th.innerText = "Modified Time";
}
th.style.padding = "0px";
hRow.appendChild(th);
}
tHead.appendChild(hRow);
table.appendChild(tHead);

//creating table body.
var tBody = document.createElement("tbody");

//Adding column to the rows for the respective table.
for (var i = 0; i < dataFileManager; i++) {

var bRow = document.createElement("tr"); //Create a row for each record.

for (var j = -1; j < col.length; j++) {
if (fileContent[i] != undefined) { //checking the default row added for blank folders - skip assignment if data does not exist.
var td = document.createElement("td");
if (j == -1) {
td.innerHTML = "<i class='fa fa-times' style='cursor:pointer;' id='delIcon' title='delete' aria-hidden='true'></i>&nbsp;&nbsp;" +
"<a id='dwnIcon' href='#'><i class='fa fa-download' aria-hidden='true'></i></a>";
}
else if (j == 0) {
//check to set the name of the file/folder
if ((fileContent[i][col[4]]).indexOf("directory") > 0) {
td.innerHTML = "<span><i class='fa fa-folder' aria-hidden='true'></i></span>&nbsp;" +
"<a name='fname' href='#'>" + fileContent[i][col[j]] + "</a>";
}
else {
td.innerHTML = "<span><i class='fa fa-file' aria-hidden='true'></i></span>&nbsp;" +
"<a name='fname' href='#'>" + fileContent[i][col[j]] + "</a>";
}
}
else if (j == 1) {
//check to set the size of the file/folder
td.innerHTML = "<span name='fsize'>" + fileContent[i][col[j]] ? (Math.ceil(fileContent[i][col[j]] / 1024) + ' KB') : '' + "</span>";
}
else if (j == 2) {
//check to set the modified time of the file/folder
td.innerHTML = "<span name='fmdtime'>" + ((fileContent[i][col[j]] && new Date(fileContent[i][col[j]])) || new Date()).toLocaleString() + "</span>";
}
else {
td.innerHTML = fileContent[i][col[j]];
td.style.display = "none";
}
bRow.appendChild(td);
}
}
tBody.appendChild(bRow)
}
table.appendChild(tBody);


//add the dynamically created table to the div - divFileManager.
var divContainer = document.getElementById("divFileManager");
if (divContainer != null) {
if (divContainer.innerHTML.length > 0) {
divContainer.innerHTML = "";
}
divContainer.appendChild(table);
reStructure();
}

}
}

//function to put file manager div after dropzone div
function reStructure() {
$("#divFileManager").insertAfter(".dz-default.dz-message");
}

//Tracking click event on file/folder name - would be used for in page edit of files.
$(document).on("click", "a[name='fname']", function (e) {
if ((e.currentTarget.parentElement.parentElement.cells[5].innerHTML).indexOf("directory") > 0) {
curPath = curPath + e.currentTarget.parentElement.parentElement.cells[1].innerText.trim() + "/";
$("#Path").val(curPath);
$.get(e.currentTarget.parentElement.parentElement.cells[6].innerHTML, null, function (data) {
generateDynamicTable(data);
//$("#spaddPath").text(root);
if ($("#spaddPath").text() == "/") {
$("#spaddPath").text(curPath);
}
else {
$("#spaddPath").text() == "/"
$("#spaddPath").text(curPath);
}
});
}
else {
$.get(e.currentTarget.parentElement.parentElement.cells[6].innerHTML, null, function (data) {
e.currentTarget.href = e.currentTarget.parentElement.parentElement.cells[6].innerHTML;
window.open(
e.currentTarget.href,
'_blank'
);
});
}
});

//Click event of anchor tag - aCurPath; sets the path to previous directory.
$(document).on("click", "a[id='aCurPath']", function (e) {
if ($("#spaddPath").text() != '') {
curPath = curPath.split("/");
curPath.pop();
curPath.pop();
curPath = curPath.join("/").trim() + "/";
$.get(("/api/vfs" + curPath), null, function (data) {
generateDynamicTable(data);
$("#spaddPath").text(curPath);
});
}
});

//Tracking click event of delete Icon
$(document).on("click", "i[id='delIcon']", function (e) {
var url = e.currentTarget.parentElement.parentElement.cells[6].innerHTML;

if (e.currentTarget.parentElement.parentElement.cells[5].innerHTML === "inode/directory") {
url += "?recursive=true";
}
$.ajax({
url: url,
method: "DELETE",
headers: {
"If-Match": "*"
},
success: function (result) {
$.get(("/api/vfs" + curPath.trim()), null, function (data) {
generateDynamicTable(data);
});
},
error: function (error) {
alert("Error in delete request!");
}
});
});

//Tracking click event of download Icon
$(document).on("click", "a[id='dwnIcon']", function (e) {
var element = document.createElement('a');
if ((e.currentTarget.parentElement.parentElement.cells[5].innerHTML).indexOf("directory") > 0) {
var zipUrl = (e.currentTarget.parentElement.parentElement.cells[6].innerText).replace("/vfs/", "/zip/")
element.setAttribute('href', zipUrl);
element.setAttribute('download', e.currentTarget.parentElement.parentElement.cells[1].innerText.trim() + ".zip");
}
else {
element.setAttribute('href', e.currentTarget.parentElement.parentElement.cells[6].innerText);
element.setAttribute('download', e.currentTarget.parentElement.parentElement.cells[1].innerText.trim());
}
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
});
</script>
Loading