Now can see a tree view of the directory the server is in. Will do file editing now.

This commit is contained in:
LukasDoesDev 2021-01-15 14:13:06 +02:00
parent c08751c7f8
commit eba7bff050
4 changed files with 303 additions and 193 deletions

View File

@ -462,7 +462,7 @@ class Helpers:
if os.path.isdir(rel): if os.path.isdir(rel):
html += '<li>\n<span class="tree-caret">{}</span>\n<ul class="tree-nested">'.format(filename) html += '<li>\n<span class="tree-caret">{}</span>\n<ul class="tree-nested">'.format(filename)
html += helper.generate_tree(rel) html += helper.generate_tree(rel)
html += '</ul>' html += '</ul>\n</li>'
else: else:
html += '<li>{}</li>'.format(filename) html += '<li>{}</li>'.format(filename)
return html return html

View File

@ -62,24 +62,6 @@ class PanelHandler(BaseHandler):
elif page == 'file_edit': elif page == 'file_edit':
template = "panel/file_edit.html" template = "panel/file_edit.html"
elif page == 'files':
server_id = self.get_argument('id', None)
if server_id is None:
self.redirect("/panel/error?error=Invalid Server ID")
return False
else:
server_id = bleach.clean(server_id)
# does this server id exist?
if not db_helper.server_id_exists(server_id):
self.redirect("/panel/error?error=Invalid Server ID")
return False
page_data['tree_html'] = helper.generate_tree(db_helper.get_server_data_by_id(server_id)['path'])
template = "panel/files.html"
elif page == "remove_server": elif page == "remove_server":
server_id = self.get_argument('id', None) server_id = self.get_argument('id', None)
server_data = controller.get_server_data(server_id) server_data = controller.get_server_data(server_id)
@ -121,10 +103,15 @@ class PanelHandler(BaseHandler):
self.redirect("/panel/error?error=Invalid Server ID") self.redirect("/panel/error?error=Invalid Server ID")
return False return False
valid_subpages = ['term', 'logs', 'config'] valid_subpages = ['term', 'logs', 'config', 'files']
if subpage not in valid_subpages: if subpage not in valid_subpages:
console.debug('not a valid subpage')
subpage = 'term' subpage = 'term'
console.debug('Subpage: "{}"'.format(subpage))
if subpage == 'files':
console.debug('Subpage is "files"')
page_data['tree_html'] = helper.generate_tree(db_helper.get_server_data_by_id(server_id)['path'])
# server_data isn't needed since the server_stats also pulls server data # server_data isn't needed since the server_stats also pulls server data
# page_data['server_data'] = db_helper.get_server_data_by_id(server_id) # page_data['server_data'] = db_helper.get_server_data_by_id(server_id)

View File

@ -1,173 +0,0 @@
{% extends ../base.html %}
{% block meta %}
<!-- <meta http-equiv="refresh" content="60">-->
{% end %}
{% block title %}Crafty Controller - Looking at files in server -< server name >- (-< server path id >-){% end %}
{% block content %}
<div class="content-wrapper">
<!-- Page Title Header Starts-->
<div class="row page-title-header">
<div class="col-12">
<div class="page-header">
<h4 class="page-title">
Looking at files in server -< server name >- (-< server path id >-)
<br />
<small>Path: -< location relative to server directory >-</small>
</h4>
</div>
</div>
</div>
<!-- Page Title Header Ends-->
<div class="row">
<div class="col-md-6">
<noscript>
Some functionality does not work without JavaScript.
</noscript>
<ul class="tree-view">
<li>
<span class="tree-caret">Files</span>
<ul class="tree-nested">
{{ data['tree_html'] }}
</ul>
</li>
</ul>
</div>
<style>
/* Remove default bullets */
.tree-view {
list-style-type: none;
margin: 0;
padding: 0;
}
/* Style the caret/arrow */
.tree-caret {
cursor: pointer;
user-select: none; /* Prevent text selection */
}
/* Create the caret/arrow with a unicode, and style it */
.tree-caret::before {
content: "\25B6";
color: white;
display: inline-block;
margin-right: 6px;
}
/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
.tree-caret-down::before {
transform: rotate(90deg);
}
/* Hide the nested list */
.tree-nested {
display: none;
}
</style>
<div class="col-6">
</div>
<script>
var toggler = document.getElementsByClassName("tree-caret");
var i;
for (i = 0; i < toggler.length; i++) {
toggler[i].addEventListener("click", function() {
this.parentElement.querySelector(".tree-nested").classList.toggle("d-block");
this.classList.toggle("tree-caret-down");
});
}
</script>
<!-- <div class="col-sm-12 grid-margin">
<div class="card">
<div class="card-body">
<ul class="files-list list-group">
<li class="list-group-item d-flex justify-content-between align-items-center"
style="background-color: var(--dark) !important;">
<a href="/panel/file_edit?path=-< file location relative to server directory >-" class="text-white">-< name >-</a>
<span>
<a href="/panel/file_edit?path=-< file location relative to server directory >-" class="mx-1 btn btn-dark">Edit</a>
<button onclick="alert('will make a modal')" class="mx-1 btn btn-dark">Rename</button>
<button onclick="alert('will make a confirmation modal')" class="mx-1 btn btn-danger">Delete</button>
<span style="margin-left: 0.3rem;width: 5rem;display: inline-block;">
<span class="badge badge-primary badge-pill">File</span>
</span>
</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center"
style="background-color: var(--dark) !important;">
<a href="/panel/files_menu?path=-< location relative to server directory >-" class="text-white">-< name >-</a>
<span>
<a href="/panel/files_menu?path=-< location relative to server directory >-" class="mx-1 btn btn-dark">Open</a>
<button onclick="alert('will make a modal')" class="mx-1 btn btn-dark">Rename</button>
<button onclick="alert('will make a confirmation modal')" class="mx-1 btn btn-danger">Delete</button>
<span style="margin-left: 0.3rem;width: 5rem;display: inline-block;">
<span class="badge badge-primary badge-pill">Folder</span>
</span>
</span>
</li>
<a!--
File:
<li class="list-group-item d-flex justify-content-between align-items-center"
style="background-color: var(--dark) !important;">
<a href="/panel/file_edit?path=-< file location relative to server directory >-" class="text-white">-< name >-</a>
<span>
<a href="/panel/file_edit?path=-< file location relative to server directory >-" class="mx-1 btn btn-dark">Edit</a>
<button onclick="alert('will make a modal')" class="mx-1 btn btn-dark">Rename</button>
<button onclick="alert('will make a confirmation modal')" class="mx-1 btn btn-danger">Delete</button>
<span style="margin-left: 0.3rem;width: 5rem;display: inline-block;">
<span class="badge badge-primary badge-pill">File</span>
</span>
</span>
</li>
Folder:
<li class="list-group-item d-flex justify-content-between align-items-center"
style="background-color: var(--dark) !important;">
<a href="/panel/files_menu?path=-< location relative to server directory >-" class="text-white">-< name >-</a>
<span>
<a href="/panel/files_menu?path=-< location relative to server directory >-" class="mx-1 btn btn-dark">Open</a>
<button onclick="alert('will make a modal')" class="mx-1 btn btn-dark">Rename</button>
<button onclick="alert('will make a confirmation modal')" class="mx-1 btn btn-danger">Delete</button>
<span style="margin-left: 0.3rem;width: 5rem;display: inline-block;">
<span class="badge badge-primary badge-pill">Folder</span>
</span>
</span>
</li>
--a>
</ul>
</div>
</div>
</div> -->
</div>
</div>
<!-- content-wrapper ends -->
{% end %}
{% block js %}
<script>
// empty for now
</script>
{% end %}

View File

@ -0,0 +1,296 @@
{% extends ../base.html %}
{% block meta %}
<!-- <meta http-equiv="refresh" content="60">-->
{% end %}
{% block title %}Crafty Controller - Server Details{% end %}
{% block content %}
<div class="content-wrapper">
<!-- Page Title Header Starts-->
<div class="row page-title-header">
<div class="col-12">
<div class="page-header">
<h4 class="page-title">
Server Details - {{ data['server_stats'][0]['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats'][0]['server_id']['server_uuid'] }}</small>
</h4>
</div>
</div>
</div>
<!-- Page Title Header Ends-->
{% include "parts/details_stats.html %}
<div class="row">
<div class="col-sm-12 grid-margin">
<div class="card">
<div class="card-body pt-0">
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
<li class="nav-item">
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=term" role="tab" aria-selected="false">
<i class="fas fa-file-signature"></i>Terminal</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="false">
<i class="fas fa-file-signature"></i>Logs</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=tasks" role="tab" aria-selected="false">
<i class="fas fa-clock"></i>Schedule</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=backup" role="tab" aria-selected="false">
<i class="fas fa-save"></i>Backup</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=files" role="tab" aria-selected="false">
<i class="fas fa-folder-tree"></i>Files</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/panel/server_detail?id={{ data['server_stats'][0]['server_id']['server_id'] }}&subpage=config" role="tab" aria-selected="true">
<i class="fas fa-cogs"></i>Config</a>
</li>
</ul>
<div class="row">
<div class="col-md-6 col-sm-12">
<noscript>
The file manager does not work without JavaScript
</noscript>
<ul class="tree-view">
<li>
<span class="tree-caret">Files</span>
<ul class="tree-nested" id="files-tree">
<li>Error while getting files</li>
</ul>
</li>
</ul>
</div>
<style>
/* Remove default bullets */
.tree-view {
list-style-type: none;
margin: 0;
padding: 0;
}
/* Style the caret/arrow */
.tree-caret {
cursor: pointer;
user-select: none; /* Prevent text selection */
}
/* Create the caret/arrow with a unicode, and style it */
.tree-caret::before {
content: "\25B6";
color: white;
display: inline-block;
margin-right: 6px;
}
/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
.tree-caret-down::before {
transform: rotate(90deg);
}
/* Hide the nested list */
.tree-nested {
display: none;
}
</style>
<div class="col-md-6 col-sm-12">
TODO: edit files<br/><br/>
Editing file <span id="editingFile"></span>
<div id="editor">file_contents</div>
<h3 id="file_warn"></h3>
<button class="btn btn-success" onclick="save()">Save</button>
</div>
<script>
var encoded = `{{ data['tree_html'] }}`;
var elem = document.createElement('textarea');
elem.innerHTML = encoded;
var decoded = elem.value;
document.getElementById('files-tree').innerHTML = decoded;
var toggler = document.getElementsByClassName("tree-caret");
var i;
for (i = 0; i < toggler.length; i++) {
toggler[i].addEventListener("click", function() {
this.parentElement.querySelector(".tree-nested").classList.toggle("d-block");
this.classList.toggle("tree-caret-down");
});
}
</script>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- content-wrapper ends -->
{% end %}
{% block js %}
<script src="/static/assets/vendors/ace-builds/src-min/ace.js" type="text/javascript" charset="utf-8"></script>
<script>
let editor = ace.edit('editor');
editor.setTheme('ace/theme/dracula');
let extensionChanges = [
{
regex: /^js$/,
replaceWith: 'ace/mode/javascript'
},
{
regex: /^py$/,
replaceWith: 'ace/mode/python'
},
{
regex: /^html$/,
replaceWith: 'ace/mode/html'
},
{
regex: /^yml$/,
replaceWith: 'ace/mode/yaml'
},
{
regex: /^yaml$/,
replaceWith: 'ace/mode/yaml'
},
{
regex: /^txt$/,
replaceWith: 'ace/mode/text'
},
{
regex: /^json$/,
replaceWith: 'ace/mode/json'
},
{
regex: /^java$/,
replaceWith: 'ace/mode/java'
},
{
regex: /^cpp$/,
replaceWith: 'ace/mode/c_cpp'
},
{
regex: /^css$/,
replaceWith: 'ace/mode/css'
},
{
regex: /^scss$/,
replaceWith: 'ace/mode/scss'
},
{
regex: /^sass$/,
replaceWith: 'ace/mode/sass'
},
{
regex: /^lua$/,
replaceWith: 'ace/mode/lua'
},
{
regex: /^php$/,
replaceWith: 'ace/mode/php'
},
{
regex: /^ps1$/,
replaceWith: 'ace/mode/powershell'
},
{
regex: /^svg$/,
replaceWith: 'ace/mode/svg'
},
{
regex: /^sh$/,
replaceWith: 'ace/mode/sh'
},
{
regex: /^xml$/,
replaceWith: 'ace/mode/xml'
},
{
regex: /^ts$/,
replaceWith: 'ace/mode/typescript'
}
];
function setFileName(name) {
let fileName = name || 'default.txt';
document.getElementById('editingFile').innerText = fileName;
if (fileName.match('.')) {
// The pop method removes and returns the last element.
setMode(fileName
.split('.')
.pop()
.replace('ace/mode/', ''));
} else {
setMode('txt');
document
.querySelector('#file_warn')
.innerText = 'Warning: This is not a supported language';
}
}
setFileName();
function setMode (extension) {
// if the extension matches with the RegEx it will return the replaceWith
// property. else it will return the one it has. defaults to the extension.
// this runs for each element in extensionChanges.
let aceMode = extensionChanges.reduce((output, element) => {
return extension.match(element.regex)
? element.replaceWith
: output;
}, extension);
if (!aceMode.startsWith('ace/mode/')) {
document
.querySelector('#file_warn')
.innerText = 'Warning: This is not a supported language';
} else {
document
.querySelector('#file_warn')
.innerText = '';
console.log(aceMode || 'ace/mode/text');
editor.session.setMode(aceMode || 'ace/mode/text');
}
}
function save() {
let text = editor.session.getValue();
// Use AJAX or something
alert(text);
}
</script>
{% end %}