mirror of
https://github.com/fruithost/Panel.git
synced 2026-10-27 23:27:25 +09:00
210 lines
9.9 KiB
PHP
210 lines
9.9 KiB
PHP
<?php
|
|
/**
|
|
* fruithost | OpenSource Hosting
|
|
*
|
|
* @author Adrian Preuß
|
|
* @version 1.0.0
|
|
* @license MIT
|
|
*/
|
|
|
|
use fruithost\Accounting\Auth;
|
|
use fruithost\Localization\I18N;
|
|
use fruithost\UI\Icon;
|
|
|
|
$template->header();
|
|
if(!Auth::hasPermission('SERVER::LOGFILES')) {
|
|
?>
|
|
<div class="alert alert-danger mt-4" role="alert">
|
|
<strong><?php I18N::__('Access denied!'); ?></strong>
|
|
<p class="pb-0 mb-0"><?php I18N::__('You have no permissions for this page.'); ?></p>
|
|
</div>
|
|
<?php
|
|
$template->footer();
|
|
exit();
|
|
}
|
|
?>
|
|
<form method="post" action="<?php print $this->url('/server/logs'); ?>">
|
|
<section class="contentbar-content">
|
|
<header class="page-header d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3">
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb"
|
|
style="--bs-breadcrumb-divider: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Cpath d='M6.776 1.553a.5.5 0 0 1 .671.223l3 6a.5.5 0 0 1 0 .448l-3 6a.5.5 0 1 1-.894-.448L9.44 8 6.553 2.224a.5.5 0 0 1 .223-.671z' fill='%236c757d'/%3E%3C/svg%3E");">
|
|
<li class="breadcrumb-item active" aria-current="page">
|
|
<a href="<?php print $this->url('/server/logs'); ?>"><?php I18N::__('Logfiles'); ?></a>
|
|
</li>
|
|
</ol>
|
|
</nav>
|
|
<div class="btn-toolbar mb-2 mb-md-0">
|
|
<button type="submit" name="action" value="refresh"
|
|
class="btn btn-sm btn-outline-primary"><?php I18N::__('Refresh'); ?></button>
|
|
</div>
|
|
</header>
|
|
<div class="loading jumbotron text-center bg-transparent text-muted" style="display: none;">
|
|
<h2><?php I18N::__('Loading'); ?></h2>
|
|
<p class="lead">
|
|
<div class="spinner-border text-primary" role="status"></div>
|
|
</p>
|
|
</div>
|
|
<div class="no-file jumbotron text-center bg-transparent text-muted" style="display: block;">
|
|
<?php Icon::show('file'); ?>
|
|
<h2><?php I18N::__('No File selected!'); ?></h2>
|
|
<p class="lead"><?php I18N::__('Please select an Logfile from the List.'); ?></p>
|
|
</div>
|
|
<article class="editor" style="display: none;"></article>
|
|
</section>
|
|
<aside class="bg-body-tertiary border-start contentbar d-md-block">
|
|
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-2 mb-2 text-muted"
|
|
data-toggle="collapse" data-target="#collapse_account" aria-expanded="false"
|
|
aria-controls="collapse_account">
|
|
<span><?php I18N::__('Logfiles'); ?></span>
|
|
</h6>
|
|
<ul class="tree"></ul>
|
|
</aside>
|
|
</form>
|
|
<script>
|
|
(() => {
|
|
'use strict'
|
|
window.addEventListener('DOMContentLoaded', () => {
|
|
let list = JSON.parse('<?php print json_encode($list); ?>');
|
|
let parser = new Terminal();
|
|
let result = [];
|
|
let level = {result};
|
|
let paths = {};
|
|
|
|
list.forEach((path) => {
|
|
let tiles = path.split('/');
|
|
let end = tiles[tiles.length - 1];
|
|
paths[end] = path;
|
|
|
|
tiles.reduce((target, name, index, array) => {
|
|
if (!target[name]) {
|
|
target[name] = {
|
|
result: [],
|
|
path: paths[name]
|
|
};
|
|
|
|
target.result.push({
|
|
name: name,
|
|
children: target[name].result,
|
|
path: target[name].path
|
|
});
|
|
}
|
|
|
|
return target[name];
|
|
}, level);
|
|
});
|
|
|
|
function highlight(content) {
|
|
let lines = [];
|
|
|
|
content.split('\n').forEach(function (line, index) {
|
|
lines.push('<div class="line user-select-all"><div class="number">' + (index + 1) + '</div><div class="data">' + line + '</div></div>');
|
|
});
|
|
|
|
return '<div class="content">' + lines.join('') + '</div>';
|
|
}
|
|
|
|
function openFile(path) {
|
|
let no_file = document.querySelector('div.no-file');
|
|
let loading = document.querySelector('div.loading');
|
|
let editor = document.querySelector('article.editor');
|
|
|
|
no_file.style.display = 'none';
|
|
editor.style.display = 'none';
|
|
loading.style.display = 'block';
|
|
editor.innerHTML = '';
|
|
|
|
new Ajax('<?php print $this->url('/server/logs'); ?>').onError(function (event, error, response) {
|
|
console.warn(event, error, response);
|
|
}).onSuccess(function (response) {
|
|
try {
|
|
let json = response;
|
|
|
|
if (json.content === null) {
|
|
editor.innerText = 'File not exists';
|
|
} else if (json.content === false) {
|
|
editor.innerText = 'Permission denied!';
|
|
} else {
|
|
if (json.content.includes('\\033')) {
|
|
editor.innerHTML = parser.parse(json.content)
|
|
} else {
|
|
editor.innerHTML = highlight(json.content);
|
|
}
|
|
}
|
|
|
|
loading.style.display = 'none';
|
|
editor.style.display = 'flex';
|
|
} catch (e) {
|
|
console.warn(e);
|
|
}
|
|
}).post({
|
|
action: 'file',
|
|
file: path
|
|
});
|
|
}
|
|
|
|
function build(node, tree) {
|
|
tree.forEach(entry => {
|
|
let element = document.createElement('li');
|
|
let caret = document.createElement('span');
|
|
caret.classList.add('caret');
|
|
caret.innerHTML = '<i>' + entry.name + '</i>';
|
|
element.appendChild(caret);
|
|
|
|
if (entry.children.length == 1 && entry.children[0].name == '') {
|
|
caret.innerHTML = '<i>' + entry.name + '/</i>';
|
|
element.style.order = 0;
|
|
caret.dataset.content = '<strong><?php I18N::__('Directory'); ?>:</strong> ' + entry.name + (typeof (entry.path) == 'undefined' ? '' : '<br /><strong><?php I18N::__('Path'); ?>:</strong> ' + entry.path) + '<br /><small class="text-danger"><?php I18N::__('No permissions!'); ?></small>';
|
|
caret.dataset.toggle = 'popover';
|
|
element.classList.add('empty');
|
|
element.classList.add('directory');
|
|
} else if (entry.children.length > 0) {
|
|
let sub = document.createElement('ul');
|
|
caret.innerHTML = '<i>' + entry.name + '/</i>';
|
|
caret.dataset.content = '<strong><?php I18N::__('Directory'); ?>:</strong> ' + entry.name + (typeof (entry.path) == 'undefined' ? '' : '<br /><strong><?php I18N::__('Path'); ?>:</strong> ' + entry.path);
|
|
caret.dataset.toggle = 'popover';
|
|
element.style.order = 0;
|
|
sub.classList.add('nested');
|
|
element.classList.add('directory');
|
|
build(sub, entry.children);
|
|
element.appendChild(sub);
|
|
} else {
|
|
element.style.order = 1;
|
|
caret.dataset.content = '<strong><?php I18N::__('File'); ?>:</strong> ' + entry.name + '<br /><strong><?php I18N::__('Path'); ?>:</strong> ' + entry.path;
|
|
caret.dataset.toggle = 'popover';
|
|
caret.dataset.path = entry.path;
|
|
element.classList.add('file');
|
|
}
|
|
|
|
/*$(caret).popover({
|
|
container: 'body',
|
|
html: true,
|
|
placement: 'right',
|
|
trigger: 'hover',
|
|
boundary: 'viewport'
|
|
});*/
|
|
|
|
caret.addEventListener('click', function (event) {
|
|
let nested = this.parentElement.querySelector('.nested');
|
|
|
|
if (nested !== null && typeof (nested) !== 'undefined' && nested.classList !== null) {
|
|
nested.classList.toggle('active');
|
|
this.classList.toggle('caret-down');
|
|
}
|
|
|
|
if (typeof (this.dataset) !== 'undefined' && typeof (this.dataset.path) !== 'undefined' && this.dataset.path != null) {
|
|
openFile(this.dataset.path);
|
|
}
|
|
});
|
|
|
|
node.appendChild(element);
|
|
})
|
|
}
|
|
|
|
build(document.querySelector('ul.tree'), result[0].children);
|
|
});
|
|
})();
|
|
</script>
|
|
<?php
|
|
$template->footer();
|
|
?>
|