fix the console rendering 🚤
This commit is contained in:
parent
9515128b8a
commit
7463bea101
6 changed files with 178 additions and 124 deletions
|
@ -4,8 +4,12 @@ This file is a running track of new features and fixes to each version of the pa
|
||||||
This project follows [Semantic Versioning](http://semver.org) guidelines.
|
This project follows [Semantic Versioning](http://semver.org) guidelines.
|
||||||
|
|
||||||
## v0.6.4 (Courageous Carniadactylus)
|
## v0.6.4 (Courageous Carniadactylus)
|
||||||
|
###
|
||||||
|
* Fixed the console rendering on page load, I guess people don't like watching it load line-by-line for 10 minutes. Who would have guessed...
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* Panel API for Daemon now responds with a `HTTP/401 Unauthorized` error when unable to locate a node with a given authentication token, rather than a `HTTP/404 Not Found` response.
|
* Panel API for Daemon now responds with a `HTTP/401 Unauthorized` error when unable to locate a node with a given authentication token, rather than a `HTTP/404 Not Found` response.
|
||||||
|
* Added better colors and styling for the terminal that can be adjusted per-theme.
|
||||||
|
|
||||||
## v0.6.3 (Courageous Carniadactylus)
|
## v0.6.3 (Courageous Carniadactylus)
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -257,22 +257,6 @@ span[aria-labelledby="select2-pUserId-container"] {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.terminal-notify {
|
|
||||||
position: absolute;
|
|
||||||
right: 27px;
|
|
||||||
bottom: 10px;
|
|
||||||
padding: 3.5px 7px;
|
|
||||||
border-radius: 3px 3px 0 0;
|
|
||||||
background: #ccc;
|
|
||||||
color: #000;
|
|
||||||
opacity: .5;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-notify:hover {
|
|
||||||
opacity: .9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-margin-bottom {
|
.no-margin-bottom {
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
@ -311,90 +295,3 @@ input.form-autocomplete-stop[readonly] {
|
||||||
background: white;
|
background: white;
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#terminal {
|
|
||||||
font-family: monospace;
|
|
||||||
color: #aaa;
|
|
||||||
background: #000;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 14px;
|
|
||||||
padding: 10px 10px 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
height: 500px;
|
|
||||||
max-height: 500px;
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
|
||||||
border-radius: 5px 5px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#terminal > .cmd {
|
|
||||||
padding: 1px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes blinky {
|
|
||||||
0% {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background: rgba(170, 170, 170, 0.9);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes blinky {
|
|
||||||
0% {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background: rgba(170, 170, 170, 0.9);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#terminal_input {
|
|
||||||
width: 100%;
|
|
||||||
background: #000;
|
|
||||||
border-radius: 0 0 5px 5px;
|
|
||||||
padding: 5px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal_input--input {
|
|
||||||
height: 0;
|
|
||||||
width: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: -20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal_input--text, .terminal_input--prompt {
|
|
||||||
line-height: 14px;
|
|
||||||
width: 100%;
|
|
||||||
vertical-align: middle;
|
|
||||||
font-size: 12px;
|
|
||||||
font-family: monospace;
|
|
||||||
margin-bottom: 0;
|
|
||||||
background: transparent;
|
|
||||||
color: #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal_input--text:before, .terminal_input--text:after {
|
|
||||||
content: "";
|
|
||||||
display: inline-block;
|
|
||||||
width: 7px;
|
|
||||||
height: 14px;
|
|
||||||
margin: 0 0 -12px -6px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal_input--text:after {
|
|
||||||
position: relative;
|
|
||||||
bottom: 8px;
|
|
||||||
left: 8px;
|
|
||||||
background: #ff00;
|
|
||||||
animation: blinky 0.6s linear infinite alternate;
|
|
||||||
-webkit-animation: blinky 0.6s linear infinite alternate;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal_input--input {
|
|
||||||
color: transparent;
|
|
||||||
background-color: transparent;
|
|
||||||
border: 0;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
148
public/themes/pterodactyl/css/terminal.css
Normal file
148
public/themes/pterodactyl/css/terminal.css
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
/*Design for Terminal*/
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Source+Code+Pro');
|
||||||
|
|
||||||
|
#terminal-body {
|
||||||
|
background: rgb(26, 26, 26);
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#terminal {
|
||||||
|
font-family: 'Source Code Pro', monospace;
|
||||||
|
color: rgb(223, 223, 223);
|
||||||
|
background: rgb(26, 26, 26);
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 14px;
|
||||||
|
padding: 10px 10px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 500px;
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
border-radius: 5px 5px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#terminal > .cmd {
|
||||||
|
padding: 1px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes cursorblink {
|
||||||
|
0% {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background: rgba(170, 170, 170, 0.9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes cursorblink {
|
||||||
|
0% {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background: rgba(170, 170, 170, 0.9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#terminal_input {
|
||||||
|
width: 100%;
|
||||||
|
background: rgb(26, 26, 26);
|
||||||
|
border-radius: 0 0 5px 5px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal_input--input {
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal_input--text, .terminal_input--prompt {
|
||||||
|
line-height: 14px;
|
||||||
|
width: 100%;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: 'Source Code Pro', monospace;
|
||||||
|
margin-bottom: 0;
|
||||||
|
background: transparent;
|
||||||
|
color: rgb(223, 223, 223);
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal_input--text:before, .terminal_input--text:after {
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
width: 7px;
|
||||||
|
height: 14px;
|
||||||
|
margin: 0 0 -12px -6px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal_input--text:after {
|
||||||
|
position: relative;
|
||||||
|
bottom: 8px;
|
||||||
|
left: 8px;
|
||||||
|
background: #ff00;
|
||||||
|
animation: cursorblink 0.6s linear infinite alternate;
|
||||||
|
-webkit-animation: cursorblink 0.6s linear infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal_input--input {
|
||||||
|
color: transparent;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 0;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal-notify {
|
||||||
|
position: absolute;
|
||||||
|
right: 30px;
|
||||||
|
bottom: 30px;
|
||||||
|
padding: 3.5px 7px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
opacity: .5;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal-notify:hover {
|
||||||
|
opacity: .9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ansi-black-fg { color: rgb(0, 0, 0); }
|
||||||
|
.ansi-red-fg { color: rgb(166, 0, 44); }
|
||||||
|
.ansi-green-fg { color: rgb(55, 106, 27); }
|
||||||
|
.ansi-yellow-fg { color: rgb(241, 133, 24); }
|
||||||
|
.ansi-blue-fg { color: rgb(17, 56, 163); }
|
||||||
|
.ansi-magenta-fg { color: rgb(67, 0, 117); }
|
||||||
|
.ansi-cyan-fg { color: rgb(18, 95, 105); }
|
||||||
|
.ansi-white-fg { color: rgb(255, 255, 255); }
|
||||||
|
.ansi-bright-black-fg { color: rgb(51, 51, 51); }
|
||||||
|
.ansi-bright-red-fg { color: rgb(223, 45, 39); }
|
||||||
|
.ansi-bright-green-fg { color: rgb(105, 175, 45); }
|
||||||
|
.ansi-bright-yellow-fg { color: rgb(254, 232, 57); }
|
||||||
|
.ansi-bright-blue-fg { color: rgb(68, 145, 240); }
|
||||||
|
.ansi-bright-magenta-fg { color: rgb(151, 50, 174); }
|
||||||
|
.ansi-bright-cyan-fg{ color: rgb(37, 173, 98); }
|
||||||
|
.ansi-bright-white-fg { color: rgb(208, 208, 208); }
|
||||||
|
|
||||||
|
.ansi-black-bg { background: rgb(0, 0, 0); }
|
||||||
|
.ansi-red-bg { background: rgb(166, 0, 44); }
|
||||||
|
.ansi-green-bg { background: rgb(55, 106, 27); }
|
||||||
|
.ansi-yellow-bg { background: rgb(241, 133, 24); }
|
||||||
|
.ansi-blue-bg { background: rgb(17, 56, 163); }
|
||||||
|
.ansi-magenta-bg { background: rgb(67, 0, 117); }
|
||||||
|
.ansi-cyan-bg { background: rgb(18, 95, 105); }
|
||||||
|
.ansi-white-bg { background: rgb(255, 255, 255); }
|
||||||
|
.ansi-bright-black-bg { background: rgb(51, 51, 51); }
|
||||||
|
.ansi-bright-red-bg { background: rgb(223, 45, 39); }
|
||||||
|
.ansi-bright-green-bg { background: rgb(105, 175, 45); }
|
||||||
|
.ansi-bright-yellow-bg { background: rgb(254, 232, 57); }
|
||||||
|
.ansi-bright-blue-bg { background: rgb(68, 145, 240); }
|
||||||
|
.ansi-bright-magenta-bg { background: rgb(151, 50, 174); }
|
||||||
|
.ansi-bright-cyan-bg { background: rgb(37, 173, 98); }
|
||||||
|
.ansi-bright-white-bg { background: rgb(208, 208, 208); }
|
|
@ -17,12 +17,12 @@
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
// SOFTWARE.
|
// SOFTWARE.
|
||||||
var CONSOLE_PUSH_COUNT = Pterodactyl.config.console_count || 10;
|
var CONSOLE_PUSH_COUNT = Pterodactyl.config.console_count || 50;
|
||||||
var CONSOLE_PUSH_FREQ = Pterodactyl.config.console_freq || 200;
|
var CONSOLE_PUSH_FREQ = Pterodactyl.config.console_freq || 200;
|
||||||
var CONSOLE_OUTPUT_LIMIT = Pterodactyl.config.console_limit || 2000;
|
var CONSOLE_OUTPUT_LIMIT = Pterodactyl.config.console_limit || 2000;
|
||||||
|
|
||||||
var InitialLogSent = false;
|
|
||||||
var AnsiUp = new AnsiUp;
|
var AnsiUp = new AnsiUp;
|
||||||
|
AnsiUp.use_classes = true;
|
||||||
|
|
||||||
var $terminal = $('#terminal');
|
var $terminal = $('#terminal');
|
||||||
var $ghostInput = $('.terminal_input--input');
|
var $ghostInput = $('.terminal_input--input');
|
||||||
|
@ -61,6 +61,10 @@ window.scrollToBottom = function () {
|
||||||
$terminal.scrollTop($terminal[0].scrollHeight);
|
$terminal.scrollTop($terminal[0].scrollHeight);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function pushToTerminal(string) {
|
||||||
|
$terminal.append('<div class="cmd">' + AnsiUp.ansi_to_html(string + '\u001b[0m') + '</div>');
|
||||||
|
}
|
||||||
|
|
||||||
(function initConsole() {
|
(function initConsole() {
|
||||||
window.TerminalQueue = [];
|
window.TerminalQueue = [];
|
||||||
window.ConsoleServerStatus = 0;
|
window.ConsoleServerStatus = 0;
|
||||||
|
@ -79,9 +83,7 @@ window.scrollToBottom = function () {
|
||||||
|
|
||||||
if (TerminalQueue.length > 0) {
|
if (TerminalQueue.length > 0) {
|
||||||
for (var i = 0; i < CONSOLE_PUSH_COUNT && TerminalQueue.length > 0; i++) {
|
for (var i = 0; i < CONSOLE_PUSH_COUNT && TerminalQueue.length > 0; i++) {
|
||||||
$terminal.append(
|
pushToTerminal(TerminalQueue[0]);
|
||||||
'<div class="cmd">' + AnsiUp.ansi_to_html(TerminalQueue[0] + '\u001b[0m') + '</div>'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (! $scrollNotify.is(':visible')) {
|
if (! $scrollNotify.is(':visible')) {
|
||||||
window.scrollToBottom();
|
window.scrollToBottom();
|
||||||
|
@ -105,12 +107,10 @@ window.scrollToBottom = function () {
|
||||||
// Update Listings on Initial Status
|
// Update Listings on Initial Status
|
||||||
Socket.on('initial status', function (data) {
|
Socket.on('initial status', function (data) {
|
||||||
ConsoleServerStatus = data.status;
|
ConsoleServerStatus = data.status;
|
||||||
if (! InitialLogSent) {
|
updateServerPowerControls(data.status);
|
||||||
updateServerPowerControls(data.status);
|
|
||||||
|
|
||||||
if (data.status === 1 || data.status === 2) {
|
if (data.status === 1 || data.status === 2) {
|
||||||
Socket.emit('send server log');
|
Socket.emit('send server log');
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -120,14 +120,14 @@ window.scrollToBottom = function () {
|
||||||
updateServerPowerControls(data.status);
|
updateServerPowerControls(data.status);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Skips the queue so we don't wait
|
||||||
|
// 10 minutes to load the log...
|
||||||
Socket.on('server log', function (data) {
|
Socket.on('server log', function (data) {
|
||||||
if (! InitialLogSent) {
|
$('#terminal').html('');
|
||||||
$('#terminal').html('');
|
data.split(/\n/g).forEach(function (item) {
|
||||||
data.split(/\n/g).forEach(function (item) {
|
pushToTerminal(item);
|
||||||
TerminalQueue.push(item);
|
window.scrollToBottom();
|
||||||
});
|
});
|
||||||
InitialLogSent = true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Socket.on('console', function (data) {
|
Socket.on('console', function (data) {
|
||||||
|
|
|
@ -23,10 +23,10 @@
|
||||||
<title>{{ Settings::get('company', 'Pterodactyl') }} - Console → {{ $server->name }}</title>
|
<title>{{ Settings::get('company', 'Pterodactyl') }} - Console → {{ $server->name }}</title>
|
||||||
@include('layouts.scripts')
|
@include('layouts.scripts')
|
||||||
{!! Theme::css('vendor/bootstrap/bootstrap.min.css') !!}
|
{!! Theme::css('vendor/bootstrap/bootstrap.min.css') !!}
|
||||||
{!! Theme::css('css/pterodactyl.css') !!}
|
{!! Theme::css('css/terminal.css') !!}
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
</head>
|
</head>
|
||||||
<body style="margin:0;width:100%;height:100%;background:#000;overflow: hidden;">
|
<body id="terminal-body">
|
||||||
<div id="terminal" style="width:100%;max-height: none !important;"></div>
|
<div id="terminal" style="width:100%;max-height: none !important;"></div>
|
||||||
<div id="terminal_input">
|
<div id="terminal_input">
|
||||||
<span class="terminal_input--prompt">{{ $server->username }}:~$</span> <span class="terminal_input--text"></span>
|
<span class="terminal_input--prompt">{{ $server->username }}:~$</span> <span class="terminal_input--text"></span>
|
||||||
|
@ -47,11 +47,11 @@
|
||||||
{!! Theme::js('js/frontend/console.js') !!}
|
{!! Theme::js('js/frontend/console.js') !!}
|
||||||
<script>
|
<script>
|
||||||
$terminal.height($(window).innerHeight() - 40);
|
$terminal.height($(window).innerHeight() - 40);
|
||||||
$terminal.width($(window).innerWidth() - 40);
|
$terminal.width($(window).innerWidth());
|
||||||
$(window).on('resize', function () {
|
$(window).on('resize', function () {
|
||||||
window.scrollToBottom();
|
window.scrollToBottom();
|
||||||
$terminal.height($(window).innerHeight() - 40);
|
$terminal.height($(window).innerHeight() - 40);
|
||||||
$terminal.width($(window).innerWidth() - 40);
|
$terminal.width($(window).innerWidth());
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -23,6 +23,11 @@
|
||||||
{{ trans('server.index.title', [ 'name' => $server->name]) }}
|
{{ trans('server.index.title', [ 'name' => $server->name]) }}
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
@section('scripts')
|
||||||
|
@parent
|
||||||
|
{!! Theme::css('css/terminal.css') !!}
|
||||||
|
@endsection
|
||||||
|
|
||||||
@section('content-header')
|
@section('content-header')
|
||||||
<h1>@lang('server.index.header')<small>@lang('server.index.header_sub')</small></h1>
|
<h1>@lang('server.index.header')<small>@lang('server.index.header_sub')</small></h1>
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
|
|
Loading…
Reference in a new issue