Adding Dropdown menus for small screens

This commit is contained in:
Silversthorn 2022-03-26 23:37:08 +01:00
parent 6bf6b7675b
commit c7fab827d9
5 changed files with 709 additions and 641 deletions

View File

@ -0,0 +1,31 @@
<div class="col-sm-12 mt-4 mb-4">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-expanded="false">
Server Controls
</button>
<div class="dropdown-menu col-md-12" aria-labelledby="dropdownMenuButton">
{% if data['permissions']['Terminal'] in data['user_permissions'] %}
<a class="dropdown-item {% if data['active_link'] == 'term' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=term" role="tab" aria-selected="false"><i class="fas fa-file-signature"></i> {{ translate('serverDetails', 'terminal', data['lang']) }}</a>
{% end %}
<!--Bedrock servers don't have logs so we'll only show it if we know it's not a bedrock server.-->
{% if data['permissions']['Logs'] in data['user_permissions'] and data['server_data']['type'] != 'minecraft-bedrock'%}
<a class="dropdown-item {% if data['active_link'] == 'logs' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="false"><i class="fas fa-file-signature"></i> {{ translate('serverDetails', 'logs', data['lang']) }}</a>
{% end %}
{% if data['permissions']['Schedule'] in data['user_permissions'] %}
<a class="dropdown-item {% if data['active_link'] == 'schedules' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=schedules" role="tab" aria-selected="false"><i class="fas fa-clock"></i> {{ translate('serverDetails', 'schedule', data['lang']) }}</a>
{% end %}
{% if data['permissions']['Backup'] in data['user_permissions'] %}
<a class="dropdown-item {% if data['active_link'] == 'backup' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=backup" role="tab" aria-selected="false"><i class="fas fa-save"></i> {{ translate('serverDetails', 'backup', data['lang']) }}</a>
{% end %}
{% if data['permissions']['Files'] in data['user_permissions'] %}
<a class="dropdown-item {% if data['active_link'] == 'files' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=files" role="tab" aria-selected="false"><i class="fas fa-folder-tree"></i> {{ translate('serverDetails', 'files', data['lang']) }}</a>
{% end %}
{% if data['permissions']['Config'] in data['user_permissions'] %}
<a class="dropdown-item {% if data['active_link'] == 'config' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=config" role="tab" aria-selected="true"><i class="fas fa-cogs"></i> {{ translate('serverDetails', 'config', data['lang']) }}</a>
{% end %}
{% if data['permissions']['Players'] in data['user_permissions'] and data['server_data']['type'] != 'minecraft-bedrock' %}
<a class="dropdown-item {% if data['active_link'] == 'admin_controls' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=admin_controls" role="tab" aria-selected="true"><i class="fas fa-users"></i> {{ translate('serverDetails', 'playerControls', data['lang']) }}</a>
{% end %}
</div>
</div>
</div>

View File

@ -9,14 +9,14 @@
<div class="content-wrapper">
<!-- Page Title Header Starts-->
<!-- Page Title Header Starts-->
<div class="row page-title-header">
<div class="col-12">
<div class="page-header">
<h4 class="page-title">
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{ data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
</h4>
</div>
</div>
@ -24,71 +24,78 @@
</div>
<!-- Page Title Header Ends-->
{% include "parts/details_stats.html %}
{% include "parts/details_stats.html %}
<div class="row">
<div class="col-sm-12 grid-margin">
<div class="card">
<div class="card-body pt-0">
<span class="d-none d-sm-block">
{% include "parts/server_controls_list.html %}
</span>
<span class="d-block d-sm-none">
{% include "parts/m_server_controls_list.html %}
</span>
<div class="row">
<div class="col-md-6 col-sm-12">
<style>
.playerItem {
background: #1c1e2f;
padding: 1rem;
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: space-between;
margin: 1rem 0px 1rem 0px;
}
.playerItem h3 {
vertical-align: middle;
padding: 0px;
margin: 0px;
margin-right: 1.5rem;
}
.playerItem button {
vertical-align: middle;
margin: 0.25rem;
}
<div class="row">
<div class="col-md-6 col-sm-12">
<style>
.playerItem {
background: #1c1e2f;
padding: 1rem;
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: space-between;
margin: 1rem 0px 1rem 0px;
}
.playerUnban {
margin-bottom: 1rem;
}
.playerItem h3 {
vertical-align: middle;
padding: 0px;
margin: 0px;
margin-right: 1.5rem;
}
.banned span {
font-size: 1.1rem;
}
</style>
<h2>{{ translate('serverPlayerManagement', 'players', data['lang']) }}:</h2>
<ul style="list-style: none;padding: 0px;margin: 0px; margin-bottom: 1rem;gap: 1rem;">
{% for player in data['get_players']() %}
<li class="playerItem">
<h3>{{ player }}</h3>
<div class="buttons">
<button onclick="send_command_to_server('ban {{ player }}')" type="button" class="btn btn-danger">Ban</button>
<button onclick="send_command_to_server('kick {{ player }}')" type="button" class="btn btn-outline-danger">Kick</button>
<button onclick="send_command_to_server('op {{ player }}')" type="button" class="btn btn-warning">OP</button>
<button onclick="send_command_to_server('deop {{ player }}')" type="button" class="btn btn-outline-warning">De-OP</button>
</div>
</li>
{% end %}
</ul>
</div>
<div class="col-md-6 col-sm-12">
<h2>{{ translate('serverPlayerManagement', 'bannedPlayers', data['lang']) }}:</h2>
<ul id="bannedPlayers" style="list-style: none;padding: 0px;margin: 0px; margin-bottom: 1rem;gap: 1rem;">
<li class="playerItem banned">
<h3>{{ translate('serverPlayerManagement', 'loadingBannedPlayers', data['lang']) }}</h3>
</li>
.playerItem button {
vertical-align: middle;
margin: 0.25rem;
}
</ul>
</div>
.playerUnban {
margin-bottom: 1rem;
}
.banned span {
font-size: 1.1rem;
}
</style>
<h2>{{ translate('serverPlayerManagement', 'players', data['lang']) }}:</h2>
<ul style="list-style: none;padding: 0px;margin: 0px; margin-bottom: 1rem;gap: 1rem;">
{% for player in data['get_players']() %}
<li class="playerItem">
<h3>{{ player }}</h3>
<div class="buttons">
<button onclick="send_command_to_server('ban {{ player }}')" type="button" class="btn btn-danger">Ban</button>
<button onclick="send_command_to_server('kick {{ player }}')" type="button" class="btn btn-outline-danger">Kick</button>
<button onclick="send_command_to_server('op {{ player }}')" type="button" class="btn btn-warning">OP</button>
<button onclick="send_command_to_server('deop {{ player }}')" type="button" class="btn btn-outline-warning">De-OP</button>
</div>
</li>
{% end %}
</ul>
</div>
<div class="col-md-6 col-sm-12">
<h2>{{ translate('serverPlayerManagement', 'bannedPlayers', data['lang']) }}:</h2>
<ul id="bannedPlayers" style="list-style: none;padding: 0px;margin: 0px; margin-bottom: 1rem;gap: 1rem;">
<li class="playerItem banned">
<h3>{{ translate('serverPlayerManagement', 'loadingBannedPlayers', data['lang']) }}</h3>
</li>
</ul>
</div>
</div>
</div>
</div>
@ -106,46 +113,46 @@
<script>
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
function htmlDecode(input){
var e = document.createElement('textarea');
e.innerHTML = input;
// handle case of empty input
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}
function htmlDecode(input) {
var e = document.createElement('textarea');
e.innerHTML = input;
// handle case of empty input
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}
$( document ).ready(function() {
console.log( "ready!" );
$(document).ready(function () {
console.log("ready!");
var bannedPlayers = `{{ data['banned_players'] }}`;
var bannedPlayers = `{{ data['banned_players'] }}`;
var bannedPlayersDecoded = htmlDecode(bannedPlayers);
var bannedPlayersDecoded = htmlDecode(bannedPlayers);
$("#bannedPlayers").html(bannedPlayersDecoded)
$("#bannedPlayers").html(bannedPlayersDecoded)
});
function send_command_to_server(command) {
console.log(command)
var token = getCookie("_xsrf")
console.log('sending command: ' + command)
$.ajax({
type: "POST",
headers: { 'X-XSRFToken': token },
url: '/ajax/send_command?id=1',
data: { command },
success: function (data) {
console.log("got response:");
console.log(data);
},
});
function send_command_to_server (command) {
console.log(command)
var token = getCookie("_xsrf")
console.log('sending command: ' + command)
$.ajax({
type: "POST",
headers: {'X-XSRFToken': token},
url: '/ajax/send_command?id=1',
data: { command },
success: function(data){
console.log("got response:");
console.log(data);
},
});
}
}
</script>

View File

@ -9,14 +9,14 @@
<div class="content-wrapper">
<!-- Page Title Header Starts-->
<!-- Page Title Header Starts-->
<div class="row page-title-header">
<div class="col-12">
<div class="page-header">
<h4 class="page-title">
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{ data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
</h4>
</div>
</div>
@ -24,155 +24,161 @@
</div>
<!-- Page Title Header Ends-->
{% include "parts/details_stats.html %}
{% include "parts/details_stats.html %}
<div class="row">
<div class="col-sm-12 grid-margin">
<div class="card">
<div class="card-body pt-0">
<span class="d-none d-sm-block">
{% include "parts/server_controls_list.html %}
</span>
<span class="d-block d-sm-none">
{% include "parts/m_server_controls_list.html %}
</span>
<div class="row">
<div class="col-md-6 col-sm-12">
<br>
<br>
<form class="forms-sample" method="post" action="/panel/server_backup">
{% raw xsrf_form_html() %}
<input type="hidden" name="id" value="{{ data['server_stats']['server_id']['server_id'] }}">
<input type="hidden" name="subpage" value="backup">
<div class="row">
<div class="col-md-6 col-sm-12">
<br>
<br>
<form class="forms-sample" method="post" action="/panel/server_backup">
{% raw xsrf_form_html() %}
<input type="hidden" name="id" value="{{ data['server_stats']['server_id']['server_id'] }}">
<input type="hidden" name="subpage" value="backup">
{% if data['backing_up'] %}
<div class="progress" style="height: 15px;">
<div class="progress-bar progress-bar-striped progress-bar-animated" id="backup_progress_bar" role="progressbar" style="width:{{data['backup_stats']['percent']}}%;" aria-valuenow="{{data['backup_stats']['percent']}}" aria-valuemin="0" aria-valuemax="100">{{ data['backup_stats']['percent'] }}%</div>
</div>
<p>Backing up <span id="total_files">{{data['backup_stats']['total_files']}}</span> Files</p>
{% end %}
<br>
{% if not data['backing_up'] %}
<div id="backup_button" class="form-group">
<button class="btn btn-primary" id="backup_now_button">{{ translate('serverBackups', 'backupNow', data['lang']) }}</button>
</div>
{% end %}
<div class="form-group">
{% if data['super_user'] %}
<label for="server_name">{{ translate('serverBackups', 'storageLocation', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverBackups', 'storageLocationDesc', data['lang']) }}</small> </label>
<input type="text" class="form-control" name="backup_path" id="backup_path" value="{{ data['server_stats']['server_id']['backup_path'] }}" placeholder="{{ translate('serverBackups', 'storageLocation', data['lang']) }}" >
{% end %}
</div>
<div class="form-group">
<label for="server_path">{{ translate('serverBackups', 'maxBackups', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverBackups', 'maxBackupsDesc', data['lang']) }}</small> </label>
<input type="text" class="form-control" name="max_backups" id="max_backups" value="{{ data['backup_config']['max_backups'] }}" placeholder="{{ translate('serverBackups', 'maxBackups', data['lang']) }}" >
</div>
<div class="form-group">
<label for="compress" class="form-check-label ml-4 mb-4"></label>
{% if data['backup_config']['compress'] %}
<input type="checkbox" class="form-check-input" id="compress" name="compress"
checked="" value="True">{{ translate('serverBackups', 'compress', data['lang']) }}
{% else %}
<input type="checkbox" class="form-check-input" id="compress" name="compress"
value="True">{{ translate('serverBackups', 'compress', data['lang']) }}
{% end %}
</div>
<div class="form-group">
<label for="server">{{ translate('serverBackups', 'exclusionsTitle', data['lang']) }} <small> - {{ translate('serverBackups', 'excludedChoose', data['lang']) }}</small></label>
<br>
<button class="btn btn-primary mr-2" id="root_files_button" data-server_path="{{ data['server_stats']['server_id']['path']}}" type="button">{{ translate('serverBackups', 'clickExclude', data['lang']) }}</button>
</div>
<input type="number" class="form-control" name="changed" id="changed" value="0" style="visibility: hidden;"></input>
<div class="modal fade" id="dir_select" tabindex="-1" role="dialog" aria-labelledby="dir_select" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">{{ translate('serverBackups', 'excludedChoose', data['lang']) }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="tree-ctx-item" id="main-tree-div" data-path="" style="overflow: scroll; max-height:75%;">
<input type="checkbox" id="main-tree-input" name="root_path" value="" disabled>
<span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path="">
<i class="far fa-folder"></i>
<i class="far fa-folder-open"></i>
{{ translate('serverFiles', 'files', data['lang']) }}
</span>
</input>
</div>
</div>
<div class="modal-footer">
<button type="button" id="modal-cancel" class="btn btn-secondary" data-dismiss="modal">{{ translate('serverBackups', 'cancel', data['lang']) }}</button>
<button type="button" id="modal-okay" data-dismiss="modal" class="btn btn-primary">{{ translate('serverWizard', 'save', data['lang']) }}</button>
</div>
</div>
</div>
</div>
<button type="submit" class="btn btn-success mr-2">{{ translate('serverBackups', 'save', data['lang']) }}</button>
<button type="reset" class="btn btn-light">{{ translate('serverBackups', 'cancel', data['lang']) }}</button>
</form>
{% if data['backing_up'] %}
<div class="progress" style="height: 15px;">
<div class="progress-bar progress-bar-striped progress-bar-animated" id="backup_progress_bar" role="progressbar" style="width:{{data['backup_stats']['percent']}}%;" aria-valuenow="{{data['backup_stats']['percent']}}" aria-valuemin="0" aria-valuemax="100">{{ data['backup_stats']['percent'] }}%</div>
</div>
<div class="col-md-6 col-sm-12">
<div class="text-center">
<table class="table table-responsive dataTable" id="backup_table">
<h4 class="card-title">{{ translate('serverBackups', 'currentBackups', data['lang']) }}</h4>
<thead>
<tr>
<th width="10%">{{ translate('serverBackups', 'options', data['lang']) }}</th>
<th>{{ translate('serverBackups', 'path', data['lang']) }}</th>
<th width="20%">{{ translate('serverBackups', 'size', data['lang']) }}</th>
</tr>
</thead>
<tbody>
{% for backup in data['backup_list'] %}
<tr>
<td>
<a href="/panel/download_backup?file={{ backup['path'] }}&id={{ data['server_stats']['server_id']['server_id'] }}" class="btn btn-primary">
<i class="fas fa-download" aria-hidden="true"></i>
{{ translate('serverBackups', 'download', data['lang']) }}
</a>
<br>
<br>
<button data-file="{{ backup['path'] }}" data-backup_path="{{ data['backup_path'] }}" class="btn btn-danger del_button">
<i class="fas fa-trash" aria-hidden="true"></i>
{{ translate('serverBackups', 'delete', data['lang']) }}
</button>
<button data-file="{{ backup['path'] }}" class="btn btn-warning restore_button">
<i class="fas fa-undo-alt" aria-hidden="true"></i>
{{ translate('serverBackups', 'restore', data['lang']) }}
</button>
</td>
<td>{{ backup['path'] }}</td>
<td>{{ backup['size'] }}</td>
</tr>
{% end %}
</tbody>
</table>
</div>
</div>
</div>
<div class="col-md-12 col-sm-12">
<br>
<br>
<div class="card-header header-sm d-flex justify-content-between align-items-center">
<h4 class="card-title"><i class="fas fa-server"></i> {{ translate('serverBackups', 'excludedBackups', data['lang']) }} <small class="text-muted ml-1"></small> </h4>
</div>
<br>
<ul>
{% for item in data['exclusions'] %}
<li>{{item}}</li>
<br>
<p>Backing up <span id="total_files">{{data['backup_stats']['total_files']}}</span> Files</p>
{% end %}
</ul>
<br>
{% if not data['backing_up'] %}
<div id="backup_button" class="form-group">
<button class="btn btn-primary" id="backup_now_button">{{ translate('serverBackups', 'backupNow', data['lang']) }}</button>
</div>
{% end %}
<div class="form-group">
{% if data['super_user'] %}
<label for="server_name">{{ translate('serverBackups', 'storageLocation', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverBackups', 'storageLocationDesc', data['lang']) }}</small> </label>
<input type="text" class="form-control" name="backup_path" id="backup_path" value="{{ data['server_stats']['server_id']['backup_path'] }}" placeholder="{{ translate('serverBackups', 'storageLocation', data['lang']) }}">
{% end %}
</div>
<div class="form-group">
<label for="server_path">{{ translate('serverBackups', 'maxBackups', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverBackups', 'maxBackupsDesc', data['lang']) }}</small> </label>
<input type="text" class="form-control" name="max_backups" id="max_backups" value="{{ data['backup_config']['max_backups'] }}" placeholder="{{ translate('serverBackups', 'maxBackups', data['lang']) }}">
</div>
<div class="form-group">
<label for="compress" class="form-check-label ml-4 mb-4"></label>
{% if data['backup_config']['compress'] %}
<input type="checkbox" class="form-check-input" id="compress" name="compress"
checked="" value="True">{{ translate('serverBackups', 'compress', data['lang']) }}
{% else %}
<input type="checkbox" class="form-check-input" id="compress" name="compress"
value="True">{{ translate('serverBackups', 'compress', data['lang']) }}
{% end %}
</div>
<div class="form-group">
<label for="server">{{ translate('serverBackups', 'exclusionsTitle', data['lang']) }} <small> - {{ translate('serverBackups', 'excludedChoose', data['lang']) }}</small></label>
<br>
<button class="btn btn-primary mr-2" id="root_files_button" data-server_path="{{ data['server_stats']['server_id']['path']}}" type="button">{{ translate('serverBackups', 'clickExclude', data['lang']) }}</button>
</div>
<input type="number" class="form-control" name="changed" id="changed" value="0" style="visibility: hidden;"></input>
<div class="modal fade" id="dir_select" tabindex="-1" role="dialog" aria-labelledby="dir_select" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">{{ translate('serverBackups', 'excludedChoose', data['lang']) }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="tree-ctx-item" id="main-tree-div" data-path="" style="overflow: scroll; max-height:75%;">
<input type="checkbox" id="main-tree-input" name="root_path" value="" disabled>
<span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path="">
<i class="far fa-folder"></i>
<i class="far fa-folder-open"></i>
{{ translate('serverFiles', 'files', data['lang']) }}
</span>
</input>
</div>
</div>
<div class="modal-footer">
<button type="button" id="modal-cancel" class="btn btn-secondary" data-dismiss="modal">{{ translate('serverBackups', 'cancel', data['lang']) }}</button>
<button type="button" id="modal-okay" data-dismiss="modal" class="btn btn-primary">{{ translate('serverWizard', 'save', data['lang']) }}</button>
</div>
</div>
</div>
</div>
<button type="submit" class="btn btn-success mr-2">{{ translate('serverBackups', 'save', data['lang']) }}</button>
<button type="reset" class="btn btn-light">{{ translate('serverBackups', 'cancel', data['lang']) }}</button>
</form>
</div>
<div class="col-md-6 col-sm-12">
<div class="text-center">
<table class="table table-responsive dataTable" id="backup_table">
<h4 class="card-title">{{ translate('serverBackups', 'currentBackups', data['lang']) }}</h4>
<thead>
<tr>
<th width="10%">{{ translate('serverBackups', 'options', data['lang']) }}</th>
<th>{{ translate('serverBackups', 'path', data['lang']) }}</th>
<th width="20%">{{ translate('serverBackups', 'size', data['lang']) }}</th>
</tr>
</thead>
<tbody>
{% for backup in data['backup_list'] %}
<tr>
<td>
<a href="/panel/download_backup?file={{ backup['path'] }}&id={{ data['server_stats']['server_id']['server_id'] }}" class="btn btn-primary">
<i class="fas fa-download" aria-hidden="true"></i>
{{ translate('serverBackups', 'download', data['lang']) }}
</a>
<br>
<br>
<button data-file="{{ backup['path'] }}" data-backup_path="{{ data['backup_path'] }}" class="btn btn-danger del_button">
<i class="fas fa-trash" aria-hidden="true"></i>
{{ translate('serverBackups', 'delete', data['lang']) }}
</button>
<button data-file="{{ backup['path'] }}" class="btn btn-warning restore_button">
<i class="fas fa-undo-alt" aria-hidden="true"></i>
{{ translate('serverBackups', 'restore', data['lang']) }}
</button>
</td>
<td>{{ backup['path'] }}</td>
<td>{{ backup['size'] }}</td>
</tr>
{% end %}
</tbody>
</table>
</div>
</div>
</div>
<div class="col-md-12 col-sm-12">
<br>
<br>
<div class="card-header header-sm d-flex justify-content-between align-items-center">
<h4 class="card-title"><i class="fas fa-server"></i> {{ translate('serverBackups', 'excludedBackups', data['lang']) }} <small class="text-muted ml-1"></small> </h4>
</div>
<br>
<ul>
{% for item in data['exclusions'] %}
<li>{{item}}</li>
<br>
{% end %}
</ul>
</div>
</div>
</div>
</div>
@ -183,41 +189,44 @@
</div>
<style>
/* Remove default bullets */
.tree-view,
.tree-nested {
list-style-type: none;
margin: 0;
padding: 0;
margin-left: 10px;
}
.tree-view,
.tree-nested {
list-style-type: none;
margin: 0;
padding: 0;
margin-left: 10px;
}
/* Style the items */
.tree-item,
.files-tree-title {
cursor: pointer;
user-select: none; /* Prevent text selection */
}
/* Style the items */
.tree-item,
.files-tree-title {
cursor: pointer;
user-select: none;
/* Prevent text selection */
}
/* Create the caret/arrow with a unicode, and style it */
.tree-caret .fa-folder {
display: inline-block;
}
.tree-caret .fa-folder-open {
display: none;
}
/* Create the caret/arrow with a unicode, and style it */
.tree-caret .fa-folder {
display: inline-block;
}
/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
.tree-caret-down .fa-folder {
display: none;
}
.tree-caret-down .fa-folder-open {
display: inline-block;
}
.tree-caret .fa-folder-open {
display: none;
}
/* Hide the nested list */
.tree-nested {
display: none;
}
/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
.tree-caret-down .fa-folder {
display: none;
}
.tree-caret-down .fa-folder-open {
display: inline-block;
}
/* Hide the nested list */
.tree-nested {
display: none;
}
</style>
<!-- content-wrapper ends -->
@ -226,7 +235,7 @@
{% block js %}
<script>
const server_id = new URLSearchParams(document.location.search).get('id')
const server_id = new URLSearchParams(document.location.search).get('id')
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
@ -241,63 +250,63 @@ const server_id = new URLSearchParams(document.location.search).get('id')
var dialog = bootbox.dialog({
message: "{{ translate('serverBackups', 'backupTask', data['lang']) }}",
closeButton: false
});
$.ajax({
type: "POST",
headers: {'X-XSRFToken': token},
url: '/ajax/backup_now?id='+server_id,
success: function(data) {
},
});
}
});
$.ajax({
type: "POST",
headers: { 'X-XSRFToken': token },
url: '/ajax/backup_now?id=' + server_id,
success: function (data) {
},
});
}
function del_backup(filename, id){
function del_backup(filename, id) {
var token = getCookie("_xsrf")
data_to_send = { file_name :filename}
data_to_send = { file_name: filename }
console.log('Sending Command to delete backup: ' + filename)
$.ajax({
type: "DELETE",
headers: {'X-XSRFToken': token},
url: '/ajax/del_backup?server_id='+id,
headers: { 'X-XSRFToken': token },
url: '/ajax/del_backup?server_id=' + id,
data: {
file_path: filename,
id: id
file_path: filename,
id: id
},
success: function(data) {
success: function (data) {
location.reload();
},
});
}
function restore_backup(filename, id){
function restore_backup(filename, id) {
var token = getCookie("_xsrf")
var dialog = bootbox.dialog({
message: '<i class="fa fa-spin fa-spinner"></i> {{ translate('serverBackups', 'restoring', data['lang']) }}',
closeButton: false
});
message: '<i class="fa fa-spin fa-spinner"></i> {{ translate('serverBackups', 'restoring', data['lang']) }}',
closeButton: false
});
console.log('Sending Command to restore backup: ' + filename)
$.ajax({
type: "POST",
headers: {'X-XSRFToken': token},
url: '/ajax/restore_backup?server_id='+id,
headers: { 'X-XSRFToken': token },
url: '/ajax/restore_backup?server_id=' + id,
data: {
zip_file: filename,
id: id
zip_file: filename,
id: id
},
success: function(data) {
setTimeout(function(){
location.href=('/panel/dashboard');
}, 15000);
success: function (data) {
setTimeout(function () {
location.href = ('/panel/dashboard');
}, 15000);
},
});
}
$( document ).ready(function() {
console.log( "ready!" );
$(document).ready(function () {
console.log("ready!");
$("#backup_config_box").hide();
$("#backup_save_note").hide();
@ -309,8 +318,8 @@ const server_id = new URLSearchParams(document.location.search).get('id')
});
$('#backup_table').DataTable({
"order": [[ 1, "desc" ]],
"paging":true,
"order": [[1, "desc"]],
"paging": true,
"lengthChange": false,
"searching": true,
"ordering": true,
@ -319,7 +328,7 @@ const server_id = new URLSearchParams(document.location.search).get('id')
"responsive": true,
});
$( ".del_button" ).click(function() {
$(".del_button").click(function () {
var file_to_del = $(this).data("file");
var backup_path = $(this).data('backup_path');
@ -346,12 +355,12 @@ const server_id = new URLSearchParams(document.location.search).get('id')
});
});
$( ".restore_button" ).click(function() {
$(".restore_button").click(function () {
var file_to_restore = $(this).data("file");
bootbox.confirm({
title: "{{ translate('serverBackups', 'restore', data['lang']) }} "+file_to_restore,
title: "{{ translate('serverBackups', 'restore', data['lang']) }} " + file_to_restore,
message: "{{ translate('serverBackups', 'confirmRestore', data['lang']) }}",
buttons: {
cancel: {
@ -359,7 +368,7 @@ const server_id = new URLSearchParams(document.location.search).get('id')
},
confirm: {
label: '<i class="fas fa-check"></i> {{ translate("serverBackups", "restore", data['lang']) }}',
className: 'btn-outline-danger'
className: 'btn-outline-danger'
}
},
callback: function (result) {
@ -370,46 +379,46 @@ const server_id = new URLSearchParams(document.location.search).get('id')
}
});
});
$( "#backup_now_button" ).click(function() {
$("#backup_now_button").click(function () {
backup_started();
});
});
document.getElementById("modal-cancel").addEventListener("click", function(){
document.getElementById("root_files_button").classList.remove('clicked');
document.getElementById("main-tree-div").innerHTML = '<input type="checkbox" id="main-tree-input" name="root_path" value="" disabled><span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path=""><i class="far fa-folder"></i><i class="far fa-folder-open"></i>{{ translate("serverFiles", "files", data["lang"]) }}</span></input>'
})
document.getElementById("modal-cancel").addEventListener("click", function () {
document.getElementById("root_files_button").classList.remove('clicked');
document.getElementById("main-tree-div").innerHTML = '<input type="checkbox" id="main-tree-input" name="root_path" value="" disabled><span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path=""><i class="far fa-folder"></i><i class="far fa-folder-open"></i>{{ translate("serverFiles", "files", data["lang"]) }}</span></input>'
})
document.getElementById("root_files_button").addEventListener("click", function(){
if($("#root_files_button").data('server_path') != ""){
if(document.getElementById('root_files_button').classList.contains('clicked')){
document.getElementById("root_files_button").addEventListener("click", function () {
if ($("#root_files_button").data('server_path') != "") {
if (document.getElementById('root_files_button').classList.contains('clicked')) {
show_file_tree();
return;
}else{
} else {
document.getElementById('root_files_button').classList.add('clicked');
document.getElementById("changed").value = 1;
}
path = $("#root_files_button").data('server_path')
console.log($("#root_files_button").data('server_path'))
var token = getCookie("_xsrf");
var dialog = bootbox.dialog({
message: '<p class="text-center mb-0"><i class="fa fa-spin fa-cog"></i> Please wait while we gather your files...</p>',
closeButton: false
});
path = $("#root_files_button").data('server_path')
console.log($("#root_files_button").data('server_path'))
var token = getCookie("_xsrf");
var dialog = bootbox.dialog({
message: '<p class="text-center mb-0"><i class="fa fa-spin fa-cog"></i> Please wait while we gather your files...</p>',
closeButton: false
});
$.ajax({
type: "POST",
headers: {'X-XSRFToken': token},
url: '/ajax/backup_select?id='+server_id+'&path='+path,
});
}else{
bootbox.alert("You must input a path before selecting this button");
}
$.ajax({
type: "POST",
headers: { 'X-XSRFToken': token },
url: '/ajax/backup_select?id=' + server_id + '&path=' + path,
});
} else {
bootbox.alert("You must input a path before selecting this button");
}
});
if (webSocket) {
webSocket.on('send_temp_path', function (data) {
setTimeout(function(){
setTimeout(function () {
var x = document.querySelector('.bootbox');
if (x) {
x.remove()
@ -422,19 +431,19 @@ document.getElementById("modal-cancel").addEventListener("click", function(){
getTreeView(data.path);
show_file_tree();
}, 5000);
}, 5000);
});
}
if (webSocket) {
webSocket.on('backup_status', function (backup) {
if(backup.percent >= 100){
if (backup.percent >= 100) {
document.getElementById('backup_progress_bar').innerHTML = '100%';
document.getElementById('backup_progress_bar').style.width = '100%';
setTimeout(function(){
setTimeout(function () {
window.location.reload(1);
}, 5000);
}else{
document.getElementById('backup_progress_bar').innerHTML = backup.percent +'%';
}, 5000);
} else {
document.getElementById('backup_progress_bar').innerHTML = backup.percent + '%';
document.getElementById('backup_progress_bar').style.width = backup.percent + '%';
document.getElementById('total_files').innerHTML = backup.total_files;
}
@ -451,9 +460,9 @@ document.getElementById("modal-cancel").addEventListener("click", function(){
$.ajax({
type: "GET",
url: '/ajax/get_backup_tree?id='+server_id+'&path='+path,
url: '/ajax/get_backup_tree?id=' + server_id + '&path=' + path,
dataType: 'text',
success: function(data){
success: function (data) {
console.log("got response:");
console.log(data);
@ -461,13 +470,13 @@ document.getElementById("modal-cancel").addEventListener("click", function(){
serverDir = dataArr.shift(); // Remove & return first element (server directory)
text = dataArr.join('\n');
try{
try {
document.getElementById('main-tree-div').innerHTML += text;
document.getElementById('main-tree').parentElement.classList.add("clicked");
}catch{
} catch {
document.getElementById('files-tree').innerHTML = text;
}
document.getElementsByClassName('files-tree-title')[0].setAttribute('data-path', serverDir);
document.getElementsByClassName('files-tree-title')[0].setAttribute('data-name', 'Files');
@ -477,57 +486,57 @@ document.getElementById("modal-cancel").addEventListener("click", function(){
}
function getToggleMain(event) {
path = event.target.parentElement.getAttribute('data-path');
document.getElementById("files-tree").classList.toggle("d-block");
document.getElementById(path+"span").classList.toggle("tree-caret-down");
document.getElementById(path+"span").classList.toggle("tree-caret");
}
document.getElementById("files-tree").classList.toggle("d-block");
document.getElementById(path + "span").classList.toggle("tree-caret-down");
document.getElementById(path + "span").classList.toggle("tree-caret");
}
function getDirView(event) {
path = event.target.parentElement.getAttribute('data-path');
path = event.target.parentElement.getAttribute('data-path');
if (document.getElementById(path).classList.contains('clicked')){
if (document.getElementById(path).classList.contains('clicked')) {
var toggler = document.getElementById(path+"span");
var toggler = document.getElementById(path + "span");
if (toggler.classList.contains('files-tree-title')){
document.getElementById(path+"ul").classList.toggle("d-block");
document.getElementById(path+"span").classList.toggle("tree-caret-down");
if (toggler.classList.contains('files-tree-title')) {
document.getElementById(path + "ul").classList.toggle("d-block");
document.getElementById(path + "span").classList.toggle("tree-caret-down");
}
return;
}else{
$.ajax({
type: "GET",
url: '/ajax/get_backup_dir?id='+server_id+'&path='+path,
dataType: 'text',
success: function(data){
console.log("got response:");
} else {
$.ajax({
type: "GET",
url: '/ajax/get_backup_dir?id=' + server_id + '&path=' + path,
dataType: 'text',
success: function (data) {
console.log("got response:");
dataArr = data.split('\n');
serverDir = dataArr.shift(); // Remove & return first element (server directory)
text = dataArr.join('\n');
dataArr = data.split('\n');
serverDir = dataArr.shift(); // Remove & return first element (server directory)
text = dataArr.join('\n');
try{
document.getElementById(path+"span").classList.add('tree-caret-down');
document.getElementById(path).innerHTML += text;
document.getElementById(path).classList.add("clicked");
}catch{
console.log("Bad")
}
try {
document.getElementById(path + "span").classList.add('tree-caret-down');
document.getElementById(path).innerHTML += text;
document.getElementById(path).classList.add("clicked");
} catch {
console.log("Bad")
}
var toggler = document.getElementById(path);
var toggler = document.getElementById(path);
if (toggler.classList.contains('files-tree-title')){
document.getElementById(path+"span").addEventListener("click", function caretListener() {
document.getElementById(path+"ul").classList.toggle("d-block");
document.getElementById(path+"span").classList.toggle("tree-caret-down");
});
}
},
});
if (toggler.classList.contains('files-tree-title')) {
document.getElementById(path + "span").addEventListener("click", function caretListener() {
document.getElementById(path + "ul").classList.toggle("d-block");
document.getElementById(path + "span").classList.toggle("tree-caret-down");
});
}
},
});
}
}
}
function show_file_tree(){
function show_file_tree() {
$("#dir_select").modal();
}

View File

@ -9,14 +9,14 @@
<div class="content-wrapper">
<!-- Page Title Header Starts-->
<!-- Page Title Header Starts-->
<div class="row page-title-header">
<div class="col-12">
<div class="page-header">
<h4 class="page-title">
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{ data['server_stats']['server_id']['server_name'] }}
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
<br />
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
</h4>
</div>
</div>
@ -24,208 +24,223 @@
</div>
<!-- Page Title Header Ends-->
{% include "parts/details_stats.html %}
{% include "parts/details_stats.html %}
<div class="row">
<div class="col-sm-12 grid-margin">
<div class="card">
<div class="card-body pt-0">
{% include "parts/server_controls_list.html %}
<div class="row">
<div class="col-md-12 col-sm-12" style="overflow-x:auto;">
<div class="card">
<div class="card-header header-sm d-flex justify-content-between align-items-center">
<h4 class="card-title"><i class="fas fa-calendar"></i> Scheduled Tasks</h4>
<span class="too_small" title="{{ translate('serverSchedules', 'cannotSee', data['lang']) }}", data-content="{{ translate('serverSchedules', 'cannotSeeOnMobile', data['lang']) }}", data-placement="bottom"></span>
<div><button onclick="location.href=`/panel/add_schedule?id={{ data['server_stats']['server_id']['server_id'] }}`" class="btn btn-info">Create New Schedule <i class="fas fa-pencil-alt"></i></button></div>
</div>
<div class="card-body">
<table class="table table-hover d-none d-lg-block responsive-table" id="schedule_table" width="100%" style="table-layout:fixed;">
<thead>
<tr class="rounded">
<th style="width: 2%; min-width: 10px;">ID</th>
<th style="width: 23%; min-width: 50px;">Action</th>
<th style="width: 40%; min-width: 50px;">Command</th>
<th style="width: 10%; min-width: 50px;">Interval</th>
<th style="width: 10%; min-width: 50px;">Start Time</th>
<th style="width: 10%; min-width: 50px;">Enabled</th>
<th style="width: 10%; min-width: 50px;">Edit</th>
</tr>
</thead>
<tbody>
{% for schedule in data['schedules'] %}
<tr>
<td id="{{schedule.schedule_id}}" class="id">
<p>{{schedule.schedule_id}}</p>
</td>
<td id="{{schedule.action}}" class="action">
<p>{{schedule.action}}</p>
</td>
<td id="{{schedule.command}}" class="action" style="overflow: scroll; max-width: 30px;">
<p>{{schedule.command}}</p>
</td>
<td id="{{schedule.interval}}" class="action">
{% if schedule.interval != '' %}
<p>Every</p>
<p>{{schedule.interval}} {{schedule.interval_type}}</p>
{% elif schedule.interval_type == 'reaction' %}
<p>{{schedule.interval_type}}<br><br>child of ID: {{ schedule.parent }}</p>
{% else %}
<p>Cron String:</p>
<p>{{schedule.cron_string}}</p>
{% end %}
</td>
<td id="{{schedule.start_time}}" class="action">
<p>{{schedule.start_time}}</p>
</td>
<td id="{{schedule.enabled}}" class="action">
<span class="d-none d-sm-block">
{% include "parts/server_controls_list.html %}
</span>
<span class="d-block d-sm-none">
{% include "parts/m_server_controls_list.html %}
</span>
<div class="row">
<div class="col-md-12 col-sm-12" style="overflow-x:auto;">
<div class="card">
<div class="card-header header-sm d-flex justify-content-between align-items-center">
<h4 class="card-title"><i class="fas fa-calendar"></i> Scheduled Tasks</h4>
<span class="too_small" title="{{ translate('serverSchedules', 'cannotSee', data['lang']) }}" , data-content="{{ translate('serverSchedules', 'cannotSeeOnMobile', data['lang']) }}" , data-placement="bottom"></span>
<div><button onclick="location.href=`/panel/add_schedule?id={{ data['server_stats']['server_id']['server_id'] }}`" class="btn btn-info">Create New Schedule <i class="fas fa-pencil-alt"></i></button></div>
</div>
<div class="card-body">
<table class="table table-hover d-none d-lg-block responsive-table" id="schedule_table" width="100%" style="table-layout:fixed;">
<thead>
<tr class="rounded">
<th style="width: 2%; min-width: 10px;">ID</th>
<th style="width: 23%; min-width: 50px;">Action</th>
<th style="width: 40%; min-width: 50px;">Command</th>
<th style="width: 10%; min-width: 50px;">Interval</th>
<th style="width: 10%; min-width: 50px;">Start Time</th>
<th style="width: 10%; min-width: 50px;">Enabled</th>
<th style="width: 10%; min-width: 50px;">Edit</th>
</tr>
</thead>
<tbody>
{% for schedule in data['schedules'] %}
<tr>
<td id="{{schedule.schedule_id}}" class="id">
<p>{{schedule.schedule_id}}</p>
</td>
<td id="{{schedule.action}}" class="action">
<p>{{schedule.action}}</p>
</td>
<td id="{{schedule.command}}" class="action" style="overflow: scroll; max-width: 30px;">
<p>{{schedule.command}}</p>
</td>
<td id="{{schedule.interval}}" class="action">
{% if schedule.interval != '' %}
<p>Every</p>
<p>{{schedule.interval}} {{schedule.interval_type}}</p>
{% elif schedule.interval_type == 'reaction' %}
<p>{{schedule.interval_type}}<br><br>child of ID: {{ schedule.parent }}</p>
{% else %}
<p>Cron String:</p>
<p>{{schedule.cron_string}}</p>
{% end %}
</td>
<td id="{{schedule.start_time}}" class="action">
<p>{{schedule.start_time}}</p>
</td>
<td id="{{schedule.enabled}}" class="action">
{% if schedule.enabled %}
<span class="text-success">
<i class="fas fa-check-square"></i> Yes
</span>
{% else %}
<span class="text-danger">
<i class="far fa-times-square"></i> No
<i class="far fa-times-square"></i> No
</span>
{% end %}
</td>
<td id="{{schedule.action}}" class="action">
<button onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'" class="btn btn-info">
<i class="fas fa-pencil-alt"></i>
</button>
</td>
<td id="{{schedule.action}}" class="action">
<button onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'" class="btn btn-info">
<i class="fas fa-pencil-alt"></i>
</button>
<br>
<br>
<button data-sch={{ schedule.schedule_id }} class="btn btn-danger del_button">
<i class="fas fa-trash" aria-hidden="true"></i>
</button>
</td>
</tr>
</button>
</td>
</tr>
{% end %}
</tbody>
</table>
<hr />
<table class="table table-hover d-block d-lg-none" id="mini_schedule_table" width="100%" style="table-layout:fixed;">
<thead>
<tr class="rounded">
<th style="width: 25%; min-width: 50px;">Action</th>
<th style="max-width: 40%; min-width: 50px;">Command</th>
<th style="width: 10%; min-width: 50px;">Enabled</th>
</tr>
</thead>
<tbody>
{% for schedule in data['schedules'] %}
<tr data-toggle="modal" data-target="#task_details_{{schedule.schedule_id}}">
<td id="{{schedule.action}}" class="action">
<p>{{schedule.action}}</p>
</td>
<td id="{{schedule.command}}" class="action" style="overflow: scroll; max-width: 30px;">
<p>{{schedule.command}}</p>
</td>
<td id="{{schedule.enabled}}" class="action">
{% if schedule.enabled %}
<span class="text-success">
<i class="fas fa-check-square"></i> Yes
</span>
{% else %}
<span class="text-danger">
<i class="far fa-times-square"></i> No
</span>
{% end %}
</tbody>
</table>
<hr />
<table class="table table-hover d-block d-lg-none" id="mini_schedule_table" width="100%" style="table-layout:fixed;">
<thead>
<tr class="rounded">
<th style="width: 25%; min-width: 50px;">Action</th>
<th style="max-width: 40%; min-width: 50px;">Command</th>
<th style="width: 10%; min-width: 50px;">Enabled</th>
</tr>
</thead>
<tbody>
{% for schedule in data['schedules'] %}
<tr data-toggle="modal" data-target="#task_details_{{schedule.schedule_id}}">
<td id="{{schedule.action}}" class="action">
<p>{{schedule.action}}</p>
</td>
<td id="{{schedule.command}}" class="action" style="overflow: scroll; max-width: 30px;">
<p>{{schedule.command}}</p>
</td>
<td id="{{schedule.enabled}}" class="action">
{% if schedule.enabled %}
<span class="text-success">
<i class="fas fa-check-square"></i> Yes
</span>
{% else %}
<span class="text-danger">
<i class="far fa-times-square"></i> No
</span>
{% end %}
</td>
</tr>
<!-- Modal -->
<div class="modal fade" id="task_details_{{schedule.schedule_id}}" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Task Details</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<ul style="list-style: none;">
<li id="{{schedule.schedule_id}}" class="id" style="border-top: .1em solid gray;">
<h4>ID</h4><p>{{schedule.schedule_id}}</p>
</li>
<li id="{{schedule.action}}" class="action" style="border-top: .1em solid gray;">
<h4>Action</h4><p>{{schedule.action}}</p>
</li>
<li id="{{schedule.command}}" class="action" style="border-top: .1em solid gray;">
<h4>Command</h4><p>{{schedule.command}}</p>
</li>
<li id="{{schedule.interval}}" class="action" style="border-top: .1em solid gray;">
{% if schedule.interval != '' %}
<h4>Interval</h4> <p>Every {{schedule.interval}} {{schedule.interval_type}}</p>
{% elif schedule.interval_type == 'reaction' %}
<h4>Interval</h4> <p>{{schedule.interval_type}}<br><br>child of ID: {{ schedule.parent }}</p>
{% else %}
<h4>Interval</h4> <p>Cron String: {{schedule.cron_string}}</p>
{% end %}
</li>
<li id="{{schedule.start_time}}" class="action" style="border-top: .1em solid gray;">
<h4>Start Time</h4> <p>{{schedule.start_time}}</p>
</li>
<li id="{{schedule.enabled}}" class="action" style="border-top: .1em solid gray; border-bottom: .1em solid gray">
{% if schedule.enabled %}
<h4>Enabled</h4> <span class="text-success">
<i class="fas fa-check-square"></i> Yes
</span>
{% else %}
<h4>Enabled</h4> <span class="text-danger">
<i class="far fa-times-square"></i> No
</span>
{% end %}
</li>
</ul>
</div>
<div class="modal-footer">
<button onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'" class="btn btn-info">
<i class="fas fa-pencil-alt"></i> Edit
</button>
<button data-sch={{ schedule.schedule_id }} class="btn btn-danger del_button">
<i class="fas fa-trash" aria-hidden="true"></i> Delete
</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</td>
</tr>
<!-- Modal -->
<div class="modal fade" id="task_details_{{schedule.schedule_id}}" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Task Details</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<ul style="list-style: none;">
<li id="{{schedule.schedule_id}}" class="id" style="border-top: .1em solid gray;">
<h4>ID</h4>
<p>{{schedule.schedule_id}}</p>
</li>
<li id="{{schedule.action}}" class="action" style="border-top: .1em solid gray;">
<h4>Action</h4>
<p>{{schedule.action}}</p>
</li>
<li id="{{schedule.command}}" class="action" style="border-top: .1em solid gray;">
<h4>Command</h4>
<p>{{schedule.command}}</p>
</li>
<li id="{{schedule.interval}}" class="action" style="border-top: .1em solid gray;">
{% if schedule.interval != '' %}
<h4>Interval</h4>
<p>Every {{schedule.interval}} {{schedule.interval_type}}</p>
{% elif schedule.interval_type == 'reaction' %}
<h4>Interval</h4>
<p>{{schedule.interval_type}}<br><br>child of ID: {{ schedule.parent }}</p>
{% else %}
<h4>Interval</h4>
<p>Cron String: {{schedule.cron_string}}</p>
{% end %}
</li>
<li id="{{schedule.start_time}}" class="action" style="border-top: .1em solid gray;">
<h4>Start Time</h4>
<p>{{schedule.start_time}}</p>
</li>
<li id="{{schedule.enabled}}" class="action" style="border-top: .1em solid gray; border-bottom: .1em solid gray">
{% if schedule.enabled %}
<h4>Enabled</h4> <span class="text-success">
<i class="fas fa-check-square"></i> Yes
</span>
{% else %}
<h4>Enabled</h4> <span class="text-danger">
<i class="far fa-times-square"></i> No
</span>
{% end %}
</li>
</ul>
</div>
<div class="modal-footer">
<button onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'" class="btn btn-info">
<i class="fas fa-pencil-alt"></i> Edit
</button>
<button data-sch={{ schedule.schedule_id }} class="btn btn-danger del_button">
<i class="fas fa-trash" aria-hidden="true"></i> Delete
</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
{% end %}
</tbody>
</table>
</div>
</div>
</div>
{% end %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
.popover-body{
color: white !important;;
}
.popover-body {
color: white !important;
;
}
</style>
</div>
<style>
/* Hide scrollbar for Chrome, Safari and Opera */
td::-webkit-scrollbar {
display: none;
}
td::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
td {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
/* Hide scrollbar for IE, Edge and Firefox */
td {
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}
</style>
<!-- content-wrapper ends -->
@ -235,140 +250,140 @@ td {
<script>
const serverId = new URLSearchParams(document.location.search).get('id')
$( document ).ready(function() {
$(document).ready(function () {
console.log('ready for JS!')
$('#schedule_table').DataTable({
'order': [4, 'desc']
}
);
});
$( document ).ready(function() {
console.log('ready for JS!')
$('#mini_schedule_table').DataTable({
'order': [2, 'desc']
}
);
document.getElementById('mini_schedule_table_wrapper').hidden = true;
});
$(document).ready(function(){
});
$(document).ready(function () {
console.log('ready for JS!')
$('#mini_schedule_table').DataTable({
'order': [2, 'desc']
}
);
document.getElementById('mini_schedule_table_wrapper').hidden = true;
});
$(document).ready(function () {
$('[data-toggle="popover"]').popover();
if($(window).width() < 1000){
if ($(window).width() < 1000) {
$('.too_small').popover("show");
document.getElementById('schedule_table_wrapper').hidden = true;
document.getElementById('mini_schedule_table_wrapper').hidden = false;
}
});
$(window).ready(function(){
$('body').click(function(){
$('.too_small').popover("hide");
});
$(window).ready(function () {
$('body').click(function () {
$('.too_small').popover("hide");
});
});
$(window).resize(function() {
$(window).resize(function () {
// This will execute whenever the window is resized
if($(window).width() < 1000){
if ($(window).width() < 1000) {
$('.too_small').popover("show");
document.getElementById('schedule_table_wrapper').hidden = true;
document.getElementById('mini_schedule_table_wrapper').hidden = false;
}
else{
else {
$('.too_small').popover("hide");
document.getElementById('schedule_table_wrapper').hidden = false;
document.getElementById('mini_schedule_table_wrapper').hidden = true;
} // New width
});
</script>
</script>
<script>
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
$(document).ready(function () {
console.log("ready!");
});
function yesnoCheck(that) {
if (that.value == "command") {
document.getElementById("ifYes").style.display = "block";
document.getElementById("command").required = true;
} else {
document.getElementById("ifYes").style.display = "none";
document.getElementById("command").required = false;
}
$( document ).ready(function() {
console.log( "ready!" );
});
function yesnoCheck(that) {
if (that.value == "command") {
document.getElementById("ifYes").style.display = "block";
document.getElementById("command").required = true;
} else {
document.getElementById("ifYes").style.display = "none";
document.getElementById("command").required = false;
}
}
function basicAdvanced(that) {
if (that.value == "advanced") {
document.getElementById("ifAdvanced").style.display = "block";
document.getElementById("ifBasic").style.display = "none";
document.getElementById("interval").required = false;
document.getElementById("time").required = false;
document.getElementById("ifAdvanced").style.display = "block";
document.getElementById("ifBasic").style.display = "none";
document.getElementById("interval").required = false;
document.getElementById("time").required = false;
} else {
document.getElementById("ifAdvanced").style.display = "none";
document.getElementById("ifBasic").style.display = "block";
document.getElementById("interval").required = true;
document.getElementById("time").required = true;
document.getElementById("ifAdvanced").style.display = "none";
document.getElementById("ifBasic").style.display = "block";
document.getElementById("interval").required = true;
document.getElementById("time").required = true;
}
}
function ifDays(that) {
if (that.value == "days") {
}
function ifDays(that) {
if (that.value == "days") {
document.getElementById("ifDays").style.display = "block";
document.getElementById("time").required = true;
} else {
} else {
document.getElementById("ifDays").style.display = "none";
document.getElementById("time").required = false;
}
}
}
$( ".del_button" ).click(function() {
var sch_id = $(this).data('sch');
$(".del_button").click(function () {
var sch_id = $(this).data('sch');
console.log(sch_id)
console.log(sch_id)
bootbox.confirm({
bootbox.confirm({
title: "{{ translate('serverSchedules', 'areYouSure', data['lang']) }}",
message: "{{ translate('serverSchedules', 'confirmDelete', data['lang']) }}",
buttons: {
cancel: {
label: '<i class="fas fa-times"></i> {{ translate("serverSchedules", "cancel", data['lang']) }}'
cancel: {
label: '<i class="fas fa-times"></i> {{ translate("serverSchedules", "cancel", data['lang']) }}'
},
confirm: {
className: 'btn-outline-danger',
label: '<i class="fas fa-check"></i> {{ translate("serverSchedules", "confirm", data['lang']) }}'
confirm: {
className: 'btn-outline-danger',
label: '<i class="fas fa-check"></i> {{ translate("serverSchedules", "confirm", data['lang']) }}'
}
},
callback: function (result) {
console.log(result);
if (result == true) {
del_task(sch_id, serverId);
}
console.log(result);
if (result == true) {
del_task(sch_id, serverId);
}
}
});
});
});
function del_task(sch_id, id){
var token = getCookie("_xsrf")
function del_task(sch_id, id) {
var token = getCookie("_xsrf")
$.ajax({
type: "DELETE",
headers: {'X-XSRFToken': token},
url: '/ajax/del_task?server_id='+id+'&schedule_id='+sch_id,
data: {
schedule_id: sch_id,
id: id
},
success: function(data) {
location.reload();
},
});
}
$.ajax({
type: "DELETE",
headers: { 'X-XSRFToken': token },
url: '/ajax/del_task?server_id=' + id + '&schedule_id=' + sch_id,
data: {
schedule_id: sch_id,
id: id
},
success: function (data) {
location.reload();
},
});
}
</script>
{% end %}
{% end %}

View File

@ -31,7 +31,13 @@
<div class="col-sm-12 grid-margin">
<div class="card">
<div class="card-body pt-0">
{% include "parts/server_controls_list.html %}
<span class="d-none d-sm-block">
{% include "parts/server_controls_list.html %}
</span>
<span class="d-block d-sm-none">
{% include "parts/m_server_controls_list.html %}
</span>
<div class="col-md-12">
<div class="input-group">
@ -60,12 +66,12 @@
<button onclick="" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1 disabled">{{ translate('serverTerm', 'stop', data['lang']) }}</button>
</div>
{% elif data['downloading'] %}
<div id="control_buttons" class="mt-4 flex-wrap d-flex justify-content-between justify-content-md-center align-items-center px-5 px-md-0" style="visibility: visible">
<button onclick="" id="start-btn" style="max-width: 12rem; white-space: nowrap;" class="btn btn-secondary m-1 flex-grow-1 disabled"><i class="fa fa-spinner fa-spin"></i> {{ translate('serverTerm', 'downloading',
data['lang']) }}</button>
<button onclick="" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1 disabled">{% raw translate('serverTerm', 'restart', data['lang']) %}</button>
<button onclick="" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1 disabled">{{ translate('serverTerm', 'stop', data['lang']) }}</button>
</div>
<div id="control_buttons" class="mt-4 flex-wrap d-flex justify-content-between justify-content-md-center align-items-center px-5 px-md-0" style="visibility: visible">
<button onclick="" id="start-btn" style="max-width: 12rem; white-space: nowrap;" class="btn btn-secondary m-1 flex-grow-1 disabled"><i class="fa fa-spinner fa-spin"></i> {{ translate('serverTerm', 'downloading',
data['lang']) }}</button>
<button onclick="" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1 disabled">{% raw translate('serverTerm', 'restart', data['lang']) %}</button>
<button onclick="" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1 disabled">{{ translate('serverTerm', 'stop', data['lang']) }}</button>
</div>
{% else %}
<div id="control_buttons" class="mt-4 flex-wrap d-flex justify-content-between justify-content-md-center align-items-center px-5 px-md-0" style="visibility: visible">
<button onclick="send_command(serverId, 'start_server');" id="start-btn" style="max-width: 7rem;" class="btn btn-primary m-1 flex-grow-1">{{ translate('serverTerm', 'start', data['lang']) }}</button>
@ -130,16 +136,16 @@
webSocket.on('update_button_status', function (updateButton) {
if (updateButton.isUpdating) {
if (updateButton.server_id == serverId) {
console.log(updateButton.isUpdating)
document.getElementById('control_buttons').innerHTML = '<button onclick="" id="start-btn" style="max-width: 7rem;" class="btn btn-primary m-1 flex-grow-1">{{ translate("serverTerm", "updating", data["lang"]) }}</button><button onclick="" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1">{% raw translate("serverTerm", "restart", data["lang"]) %}</button><button onclick="" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1 disabled">{{ translate("serverTerm", "stop", data["lang"]) }}</button>';
}
}
else {
if (updateButton.server_id == serverId) {
window.location.reload()
document.getElementById('update_control_buttons').innerHTML = '<button onclick="send_command(serverId, "start_server");" id="start-btn" style="max-width: 7rem;" class="btn btn-primary m-1 flex-grow-1">{{ translate("serverTerm", "start", data["lang"]) }}</button><button onclick="send_command(serverId, "restart_server");" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1">{% raw translate("serverTerm", "restart", data["lang"]) %}</button><button onclick="" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1 disabled">{{ translate("serverTerm", "stop", data["lang"]) }}</button>';
}
}
console.log(updateButton.isUpdating)
document.getElementById('control_buttons').innerHTML = '<button onclick="" id="start-btn" style="max-width: 7rem;" class="btn btn-primary m-1 flex-grow-1">{{ translate("serverTerm", "updating", data["lang"]) }}</button><button onclick="" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1">{% raw translate("serverTerm", "restart", data["lang"]) %}</button><button onclick="" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1 disabled">{{ translate("serverTerm", "stop", data["lang"]) }}</button>';
}
}
else {
if (updateButton.server_id == serverId) {
window.location.reload()
document.getElementById('update_control_buttons').innerHTML = '<button onclick="send_command(serverId, "start_server");" id="start-btn" style="max-width: 7rem;" class="btn btn-primary m-1 flex-grow-1">{{ translate("serverTerm", "start", data["lang"]) }}</button><button onclick="send_command(serverId, "restart_server");" id="restart-btn" style="max-width: 7rem;" class="btn btn-outline-primary m-1 flex-grow-1">{% raw translate("serverTerm", "restart", data["lang"]) %}</button><button onclick="" id="stop-btn" style="max-width: 7rem;" class="btn btn-danger m-1 flex-grow-1 disabled">{{ translate("serverTerm", "stop", data["lang"]) }}</button>';
}
}
});
}
// Convert running to lower case (example: 'True' converts to 'true') and
@ -162,10 +168,10 @@
}
if (webSocket) {
webSocket.on('send_start_reload', function () {
location.reload()
});
}
webSocket.on('send_start_reload', function () {
location.reload()
});
}
//{% end %}
function get_server_log() {
@ -255,7 +261,7 @@
},
body: formdata,
});
let responseData = await res.text();
console.log("got response:");
console.log(responseData);
@ -288,4 +294,4 @@
}
</script>
{% end %}
{% end %}