mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'dev' into tweak/front-end-translation-fa
This commit is contained in:
commit
e39e87824d
13
CHANGELOG.md
13
CHANGELOG.md
@ -1,13 +1,18 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
## --- [4.0.21] - 2023/TBD
|
## --- [4.0.21] - 2023/TBD
|
||||||
### New features
|
### New features
|
||||||
TBD
|
- Add better feedback for uploads with a progress bar ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/546))
|
||||||
|
- Add ignored exit codes for crash detection ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/553))
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
TBD
|
- Fix exception related to page data on server start ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/544))
|
||||||
|
- Fix logical issue with uploading dynamic files ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/555))
|
||||||
|
- Fix backups failing by correctly using tz objects ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/556))
|
||||||
### Tweaks
|
### Tweaks
|
||||||
TBD
|
- Cleanup authentication helpers ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/545))
|
||||||
|
- Optimize file upload progress WS ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/546))
|
||||||
|
- Truncate sidebar servers to a max of 10 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/552))
|
||||||
### Lang
|
### Lang
|
||||||
TBD
|
- Add additional translations to backups page strings ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/543))
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
## --- [4.0.20] - 2023/01/29
|
## --- [4.0.20] - 2023/01/29
|
||||||
|
@ -40,6 +40,7 @@ class Servers(BaseModel):
|
|||||||
show_status = BooleanField(default=1)
|
show_status = BooleanField(default=1)
|
||||||
created_by = IntegerField(default=-100)
|
created_by = IntegerField(default=-100)
|
||||||
shutdown_timeout = IntegerField(default=60)
|
shutdown_timeout = IntegerField(default=60)
|
||||||
|
ignored_exits = CharField(default="0")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
table_name = "servers"
|
table_name = "servers"
|
||||||
|
@ -13,7 +13,6 @@ logger = logging.getLogger(__name__)
|
|||||||
class Authentication:
|
class Authentication:
|
||||||
def __init__(self, helper):
|
def __init__(self, helper):
|
||||||
self.helper = helper
|
self.helper = helper
|
||||||
self.secret = "my secret"
|
|
||||||
try:
|
try:
|
||||||
self.secret = ManagementController.get_crafty_api_key()
|
self.secret = ManagementController.get_crafty_api_key()
|
||||||
if self.secret == "":
|
if self.secret == "":
|
||||||
|
@ -1013,7 +1013,7 @@ class Helpers:
|
|||||||
for item in file_list:
|
for item in file_list:
|
||||||
if os.path.isdir(os.path.join(folder, item)):
|
if os.path.isdir(os.path.join(folder, item)):
|
||||||
dir_list.append(item)
|
dir_list.append(item)
|
||||||
elif str(item) != "crafty.sqlite":
|
elif str(item) != self.ignored_names:
|
||||||
unsorted_files.append(item)
|
unsorted_files.append(item)
|
||||||
file_list = sorted(dir_list, key=str.casefold) + sorted(
|
file_list = sorted(dir_list, key=str.casefold) + sorted(
|
||||||
unsorted_files, key=str.casefold
|
unsorted_files, key=str.casefold
|
||||||
@ -1054,7 +1054,7 @@ class Helpers:
|
|||||||
for item in file_list:
|
for item in file_list:
|
||||||
if os.path.isdir(os.path.join(folder, item)):
|
if os.path.isdir(os.path.join(folder, item)):
|
||||||
dir_list.append(item)
|
dir_list.append(item)
|
||||||
elif str(item) != "crafty.sqlite":
|
elif str(item) != self.ignored_names:
|
||||||
unsorted_files.append(item)
|
unsorted_files.append(item)
|
||||||
file_list = sorted(dir_list, key=str.casefold) + sorted(
|
file_list = sorted(dir_list, key=str.casefold) + sorted(
|
||||||
unsorted_files, key=str.casefold
|
unsorted_files, key=str.casefold
|
||||||
|
@ -12,6 +12,8 @@ import html
|
|||||||
import urllib.request
|
import urllib.request
|
||||||
import glob
|
import glob
|
||||||
|
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
# TZLocal is set as a hidden import on win pipeline
|
# TZLocal is set as a hidden import on win pipeline
|
||||||
from tzlocal import get_localzone
|
from tzlocal import get_localzone
|
||||||
from tzlocal.utils import ZoneInfoNotFoundError
|
from tzlocal.utils import ZoneInfoNotFoundError
|
||||||
@ -136,7 +138,7 @@ class ServerInstance:
|
|||||||
logger.error(
|
logger.error(
|
||||||
"Could not capture time zone from system. Falling back to Europe/London"
|
"Could not capture time zone from system. Falling back to Europe/London"
|
||||||
)
|
)
|
||||||
self.tz = "Europe/London"
|
self.tz = ZoneInfo("Europe/London")
|
||||||
self.server_scheduler = BackgroundScheduler(timezone=str(self.tz))
|
self.server_scheduler = BackgroundScheduler(timezone=str(self.tz))
|
||||||
self.server_scheduler.start()
|
self.server_scheduler.start()
|
||||||
self.backup_thread = threading.Thread(
|
self.backup_thread = threading.Thread(
|
||||||
@ -730,26 +732,26 @@ class ServerInstance:
|
|||||||
self.server_thread.join()
|
self.server_thread.join()
|
||||||
|
|
||||||
def stop_server(self):
|
def stop_server(self):
|
||||||
if self.settings["stop_command"]:
|
|
||||||
self.send_command(self.settings["stop_command"])
|
|
||||||
if self.settings["crash_detection"]:
|
|
||||||
# remove crash detection watcher
|
|
||||||
logger.info(f"Removing crash watcher for server {self.name}")
|
|
||||||
try:
|
|
||||||
self.server_scheduler.remove_job("c_" + str(self.server_id))
|
|
||||||
except:
|
|
||||||
logger.error(
|
|
||||||
f"Removing crash watcher for server {self.name} failed. "
|
|
||||||
f"Assuming it was never started."
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# windows will need to be handled separately for Ctrl+C
|
|
||||||
self.process.terminate()
|
|
||||||
running = self.check_running()
|
running = self.check_running()
|
||||||
if not running:
|
if not running:
|
||||||
logger.info(f"Can't stop server {self.name} if it's not running")
|
logger.info(f"Can't stop server {self.name} if it's not running")
|
||||||
Console.info(f"Can't stop server {self.name} if it's not running")
|
Console.info(f"Can't stop server {self.name} if it's not running")
|
||||||
return
|
return
|
||||||
|
if self.settings["crash_detection"]:
|
||||||
|
# remove crash detection watcher
|
||||||
|
logger.info(f"Removing crash watcher for server {self.name}")
|
||||||
|
try:
|
||||||
|
self.server_scheduler.remove_job("c_" + str(self.server_id))
|
||||||
|
except:
|
||||||
|
logger.error(
|
||||||
|
f"Removing crash watcher for server {self.name} failed. "
|
||||||
|
f"Assuming it was never started."
|
||||||
|
)
|
||||||
|
if self.settings["stop_command"]:
|
||||||
|
self.send_command(self.settings["stop_command"])
|
||||||
|
else:
|
||||||
|
# windows will need to be handled separately for Ctrl+C
|
||||||
|
self.process.terminate()
|
||||||
i = 0
|
i = 0
|
||||||
|
|
||||||
# caching the name and pid number
|
# caching the name and pid number
|
||||||
@ -919,7 +921,7 @@ class ServerInstance:
|
|||||||
if running:
|
if running:
|
||||||
return
|
return
|
||||||
# check the exit code -- This could be a fix for /stop
|
# check the exit code -- This could be a fix for /stop
|
||||||
if self.process.returncode == 0:
|
if str(self.process.returncode) in self.settings["ignored_exits"].split(","):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"Process {self.process.pid} exited with code "
|
f"Process {self.process.pid} exited with code "
|
||||||
f"{self.process.returncode}. This is considered a clean exit"
|
f"{self.process.returncode}. This is considered a clean exit"
|
||||||
|
@ -1585,6 +1585,8 @@ class PanelHandler(BaseHandler):
|
|||||||
crash_detection = int(float(self.get_argument("crash_detection", "0")))
|
crash_detection = int(float(self.get_argument("crash_detection", "0")))
|
||||||
logs_delete_after = int(float(self.get_argument("logs_delete_after", "0")))
|
logs_delete_after = int(float(self.get_argument("logs_delete_after", "0")))
|
||||||
java_selection = self.get_argument("java_selection", None)
|
java_selection = self.get_argument("java_selection", None)
|
||||||
|
# make sure there is no whitespace
|
||||||
|
ignored_exits = self.get_argument("ignored_exits", "").replace(" ", "")
|
||||||
# subpage = self.get_argument('subpage', None)
|
# subpage = self.get_argument('subpage', None)
|
||||||
|
|
||||||
server_id = self.check_server_id()
|
server_id = self.check_server_id()
|
||||||
@ -1669,6 +1671,7 @@ class PanelHandler(BaseHandler):
|
|||||||
server_obj.auto_start = auto_start
|
server_obj.auto_start = auto_start
|
||||||
server_obj.crash_detection = crash_detection
|
server_obj.crash_detection = crash_detection
|
||||||
server_obj.logs_delete_after = logs_delete_after
|
server_obj.logs_delete_after = logs_delete_after
|
||||||
|
server_obj.ignored_exits = ignored_exits
|
||||||
failed = False
|
failed = False
|
||||||
for servers in self.controller.servers.failed_servers:
|
for servers in self.controller.servers.failed_servers:
|
||||||
if servers["server_id"] == int(server_id):
|
if servers["server_id"] == int(server_id):
|
||||||
|
@ -183,6 +183,7 @@ class ServerHandler(BaseHandler):
|
|||||||
"version_data": "version_data_here", # TODO
|
"version_data": "version_data_here", # TODO
|
||||||
"user_data": exec_user,
|
"user_data": exec_user,
|
||||||
"show_contribute": self.helper.get_setting("show_contribute_link", True),
|
"show_contribute": self.helper.get_setting("show_contribute_link", True),
|
||||||
|
"background": self.controller.cached_login,
|
||||||
"lang": self.controller.users.get_user_lang_by_id(exec_user["user_id"]),
|
"lang": self.controller.users.get_user_lang_by_id(exec_user["user_id"]),
|
||||||
"lang_page": Helpers.get_lang_page(
|
"lang_page": Helpers.get_lang_page(
|
||||||
self.controller.users.get_user_lang_by_id(exec_user["user_id"])
|
self.controller.users.get_user_lang_by_id(exec_user["user_id"])
|
||||||
|
@ -7,12 +7,12 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class StatusHandler(BaseHandler):
|
class StatusHandler(BaseHandler):
|
||||||
def get(self):
|
def get(self):
|
||||||
page_data = {"background": self.controller.cached_login}
|
page_data = {
|
||||||
page_data["lang"] = self.helper.get_setting("language")
|
"background": self.controller.cached_login,
|
||||||
page_data["lang_page"] = self.helper.get_lang_page(
|
"lang": self.helper.get_setting("language"),
|
||||||
self.helper.get_setting("language")
|
"lang_page": self.helper.get_lang_page(self.helper.get_setting("language")),
|
||||||
)
|
"servers": self.controller.servers.get_all_servers_stats(),
|
||||||
page_data["servers"] = self.controller.servers.get_all_servers_stats()
|
}
|
||||||
running = 0
|
running = 0
|
||||||
for srv in page_data["servers"]:
|
for srv in page_data["servers"]:
|
||||||
if srv["stats"]["running"]:
|
if srv["stats"]["running"]:
|
||||||
|
@ -52,18 +52,19 @@ class UploadHandler(BaseHandler):
|
|||||||
f"User with ID {user_id} attempted to upload a file that"
|
f"User with ID {user_id} attempted to upload a file that"
|
||||||
f" exceeded the max body size."
|
f" exceeded the max body size."
|
||||||
)
|
)
|
||||||
self.helper.websocket_helper.broadcast_user(
|
|
||||||
user_id,
|
return self.finish_json(
|
||||||
"send_start_error",
|
413,
|
||||||
{
|
{
|
||||||
"error": self.helper.translation.translate(
|
"status": "error",
|
||||||
|
"error": "TOO LARGE",
|
||||||
|
"info": self.helper.translation.translate(
|
||||||
"error",
|
"error",
|
||||||
"fileTooLarge",
|
"fileTooLarge",
|
||||||
self.controller.users.get_user_lang_by_id(user_id),
|
self.controller.users.get_user_lang_by_id(user_id),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return
|
|
||||||
self.do_upload = True
|
self.do_upload = True
|
||||||
|
|
||||||
if superuser:
|
if superuser:
|
||||||
@ -141,48 +142,50 @@ class UploadHandler(BaseHandler):
|
|||||||
f"User with ID {user_id} attempted to upload a file that"
|
f"User with ID {user_id} attempted to upload a file that"
|
||||||
f" exceeded the max body size."
|
f" exceeded the max body size."
|
||||||
)
|
)
|
||||||
self.helper.websocket_helper.broadcast_user(
|
|
||||||
user_id,
|
return self.finish_json(
|
||||||
"send_start_error",
|
413,
|
||||||
{
|
{
|
||||||
"error": self.helper.translation.translate(
|
"status": "error",
|
||||||
|
"error": "TOO LARGE",
|
||||||
|
"info": self.helper.translation.translate(
|
||||||
"error",
|
"error",
|
||||||
"fileTooLarge",
|
"fileTooLarge",
|
||||||
self.controller.users.get_user_lang_by_id(user_id),
|
self.controller.users.get_user_lang_by_id(user_id),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return
|
|
||||||
self.do_upload = True
|
self.do_upload = True
|
||||||
|
|
||||||
if not superuser:
|
if not superuser:
|
||||||
self.helper.websocket_helper.broadcast_user(
|
return self.finish_json(
|
||||||
user_id,
|
401,
|
||||||
"send_start_error",
|
|
||||||
{
|
{
|
||||||
"error": self.helper.translation.translate(
|
"status": "error",
|
||||||
|
"error": "UNAUTHORIZED ACCESS",
|
||||||
|
"info": self.helper.translation.translate(
|
||||||
"error",
|
"error",
|
||||||
"superError",
|
"superError",
|
||||||
self.controller.users.get_user_lang_by_id(user_id),
|
self.controller.users.get_user_lang_by_id(user_id),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return
|
|
||||||
if not self.request.headers.get("X-Content-Type", None).startswith(
|
if not self.request.headers.get("X-Content-Type", None).startswith(
|
||||||
"image/"
|
"image/"
|
||||||
):
|
):
|
||||||
self.helper.websocket_helper.broadcast_user(
|
|
||||||
user_id,
|
return self.finish_json(
|
||||||
"send_start_error",
|
415,
|
||||||
{
|
{
|
||||||
"error": self.helper.translation.translate(
|
"status": "error",
|
||||||
|
"error": "TYPE ERROR",
|
||||||
|
"info": self.helper.translation.translate(
|
||||||
"error",
|
"error",
|
||||||
"fileError",
|
"fileError",
|
||||||
self.controller.users.get_user_lang_by_id(user_id),
|
self.controller.users.get_user_lang_by_id(user_id),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return
|
|
||||||
if user_id is None:
|
if user_id is None:
|
||||||
logger.warning("User ID not found in upload handler call")
|
logger.warning("User ID not found in upload handler call")
|
||||||
Console.warning("User ID not found in upload handler call")
|
Console.warning("User ID not found in upload handler call")
|
||||||
@ -219,18 +222,19 @@ class UploadHandler(BaseHandler):
|
|||||||
f"User with ID {user_id} attempted to upload a file that"
|
f"User with ID {user_id} attempted to upload a file that"
|
||||||
f" exceeded the max body size."
|
f" exceeded the max body size."
|
||||||
)
|
)
|
||||||
self.helper.websocket_helper.broadcast_user(
|
|
||||||
user_id,
|
return self.finish_json(
|
||||||
"send_start_error",
|
413,
|
||||||
{
|
{
|
||||||
"error": self.helper.translation.translate(
|
"status": "error",
|
||||||
|
"error": "TOO LARGE",
|
||||||
|
"info": self.helper.translation.translate(
|
||||||
"error",
|
"error",
|
||||||
"fileTooLarge",
|
"fileTooLarge",
|
||||||
self.controller.users.get_user_lang_by_id(user_id),
|
self.controller.users.get_user_lang_by_id(user_id),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return
|
|
||||||
self.do_upload = True
|
self.do_upload = True
|
||||||
|
|
||||||
if superuser:
|
if superuser:
|
||||||
|
@ -81,7 +81,7 @@
|
|||||||
<i class="menu-arrow"></i>
|
<i class="menu-arrow"></i>
|
||||||
</a>
|
</a>
|
||||||
<div class="collapse" id="page-layouts">
|
<div class="collapse" id="page-layouts">
|
||||||
<ul class="nav flex-column sub-menu">
|
<ul class="nav flex-column sub-menu" id="sidebar-servers">
|
||||||
{% if data['crafty_permissions']['Server_Creation'] in data['user_crafty_permissions'] %}
|
{% if data['crafty_permissions']['Server_Creation'] in data['user_crafty_permissions'] %}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/server/step1"><i class="fas fa-plus-circle"></i> {{ translate('sidebar',
|
<a class="nav-link" href="/server/step1"><i class="fas fa-plus-circle"></i> {{ translate('sidebar',
|
||||||
@ -138,4 +138,9 @@
|
|||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
$('#sidebar-servers li:gt(10)').remove();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
<!-- partial -->
|
<!-- partial -->
|
@ -6,7 +6,8 @@
|
|||||||
{% block title %}Crafty Controller - {{ translate('panelConfig', 'pageTitle', data['lang']) }}{% end %}
|
{% block title %}Crafty Controller - {{ translate('panelConfig', 'pageTitle', data['lang']) }}{% end %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.10/css/bootstrap-select.min.css">
|
<link rel="stylesheet"
|
||||||
|
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.10/css/bootstrap-select.min.css">
|
||||||
|
|
||||||
|
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
@ -50,62 +51,68 @@
|
|||||||
{% for item in data['config-json'].items() %}
|
{% for item in data['config-json'].items() %}
|
||||||
{% if item[0] == "reset_secrets_on_next_boot" %}
|
{% if item[0] == "reset_secrets_on_next_boot" %}
|
||||||
<div class="form-group" style="background: rgba(243, 21, 6, 0.3); outline: 1px solid red; padding: 10px;">
|
<div class="form-group" style="background: rgba(243, 21, 6, 0.3); outline: 1px solid red; padding: 10px;">
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
{% end %}
|
|
||||||
<label class="form" for="{{item[0]}}">{{item[0]}}
|
|
||||||
<small class="text-muted ml-1">
|
|
||||||
</small> </label><br />
|
|
||||||
{% if item[0] == 'language' %}
|
|
||||||
<select name="{{item[0]}}" class="form-control">
|
|
||||||
{% for lang in data['availables_languages'] %}
|
|
||||||
{% if lang == item[1] %}
|
|
||||||
<option selected>{{lang}}</option>
|
|
||||||
{% else %}
|
|
||||||
<option>{{lang}}</option>
|
|
||||||
{% end %}
|
{% end %}
|
||||||
{% end %}
|
<label class="form" for="{{item[0]}}">{{item[0]}}
|
||||||
</select>
|
<small class="text-muted ml-1">
|
||||||
{% elif item[0] == 'disabled_language_files' %}
|
</small> </label><br />
|
||||||
<div class="input-group">
|
{% if item[0] == 'language' %}
|
||||||
<button type="button" class="btn btn-outline-default custom-picker" onclick="$('option', $('#lang_select')).each(function(element) {
|
<select name="{{item[0]}}" class="form-control">
|
||||||
$(this).removeAttr('selected').prop('selected', false); $('.selectpicker').selectpicker('refresh')
|
{% for lang in data['availables_languages'] %}
|
||||||
});">Enable all Languages</button>
|
{% if lang == item[1] %}
|
||||||
<select id="lang_select" class="form-control selectpicker show-tick" data-icon-base="fas" data-tick-icon="fa-check" multiple data-style="custom-picker">
|
|
||||||
{% for lang in data['all_languages'] %}
|
|
||||||
{% if lang in item[1] %}
|
|
||||||
<option selected>{{lang}}</option>
|
<option selected>{{lang}}</option>
|
||||||
{% else %}
|
{% else %}
|
||||||
<option>{{lang}}</option>
|
<option>{{lang}}</option>
|
||||||
{% end %}
|
{% end %}
|
||||||
{% end %}
|
{% end %}
|
||||||
</select>
|
</select>
|
||||||
<textarea id="disabled_lang" name="{{item[0]}}" class="form-control list hidden" rows="{{ len(data['all_languages']) }}" value="{{','.join(item[1])}}" hidden>{{','.join(item[1])}}</textarea>
|
{% elif item[0] == 'disabled_language_files' %}
|
||||||
|
<div class="input-group">
|
||||||
|
<button type="button" class="btn btn-outline-default custom-picker" onclick="$('option', $('#lang_select')).each(function(element) {
|
||||||
|
$(this).removeAttr('selected').prop('selected', false); $('.selectpicker').selectpicker('refresh')
|
||||||
|
});">Enable all Languages</button>
|
||||||
|
<select id="lang_select" class="form-control selectpicker show-tick" data-icon-base="fas"
|
||||||
|
data-tick-icon="fa-check" multiple data-style="custom-picker">
|
||||||
|
{% for lang in data['all_languages'] %}
|
||||||
|
{% if lang in item[1] %}
|
||||||
|
<option selected>{{lang}}</option>
|
||||||
|
{% else %}
|
||||||
|
<option>{{lang}}</option>
|
||||||
|
{% end %}
|
||||||
|
{% end %}
|
||||||
|
</select>
|
||||||
|
<textarea id="disabled_lang" name="{{item[0]}}" class="form-control list hidden"
|
||||||
|
rows="{{ len(data['all_languages']) }}" value="{{','.join(item[1])}}"
|
||||||
|
hidden>{{','.join(item[1])}}</textarea>
|
||||||
|
</div>
|
||||||
|
{% elif isinstance(item[1], list) %}
|
||||||
|
<textarea value="{{','.join(item[1])}}" type="text" name="{{item[0]}}"
|
||||||
|
class="form-control list">{{','.join(item[1])}}</textarea>
|
||||||
|
{% elif isinstance(item[1], bool) %}
|
||||||
|
<div style="margin-left: 30px;">
|
||||||
|
{% if item[1] == True %}
|
||||||
|
<input type="radio" class="form-check-input" name="{{item[0]}}" id="True" value="True" checked>
|
||||||
|
<label for="True">True</label><br>
|
||||||
|
<input type="radio" class="form-check-input" name="{{item[0]}}" id="False" value="False">
|
||||||
|
<label for="False">False</label>
|
||||||
|
{% else %}
|
||||||
|
<input type="radio" class="form-check-input" name="{{item[0]}}" id="True" value="True">
|
||||||
|
<label for="True">True</label><br>
|
||||||
|
<input type="radio" class="form-check-input" name="{{item[0]}}" id="False" value="False" checked>
|
||||||
|
<label for="False">False</label>
|
||||||
|
{% end %}
|
||||||
|
</div>
|
||||||
|
{% elif isinstance(item[1], int) %}
|
||||||
|
<input type="number" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}"
|
||||||
|
step="1" min="0" required>
|
||||||
|
{% else %}
|
||||||
|
<input type="text" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}"
|
||||||
|
step="2" min="0" required>
|
||||||
|
{% end %}
|
||||||
</div>
|
</div>
|
||||||
{% elif isinstance(item[1], list) %}
|
|
||||||
<textarea value="{{','.join(item[1])}}" type="text" name="{{item[0]}}" class="form-control list">{{','.join(item[1])}}</textarea>
|
|
||||||
{% elif isinstance(item[1], bool) %}
|
|
||||||
<div style="margin-left: 30px;">
|
|
||||||
{% if item[1] == True %}
|
|
||||||
<input type="radio" class="form-check-input" name="{{item[0]}}" id="True" value="True" checked>
|
|
||||||
<label for="True">True</label><br>
|
|
||||||
<input type="radio" class="form-check-input" name="{{item[0]}}" id="False" value="False">
|
|
||||||
<label for="False">False</label>
|
|
||||||
{% else %}
|
|
||||||
<input type="radio" class="form-check-input" name="{{item[0]}}" id="True" value="True">
|
|
||||||
<label for="True">True</label><br>
|
|
||||||
<input type="radio" class="form-check-input" name="{{item[0]}}" id="False" value="False" checked>
|
|
||||||
<label for="False">False</label>
|
|
||||||
{% end %}
|
{% end %}
|
||||||
</div>
|
<button class="btn btn-success" type="submit">Submit</button> <span id="submit-status"></span>
|
||||||
{% elif isinstance(item[1], int) %}
|
|
||||||
<input type="number" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}" step="1" min="0" required>
|
|
||||||
{% else %}
|
|
||||||
<input type="text" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}" step="2" min="0" required>
|
|
||||||
{% end %}
|
|
||||||
</div>
|
|
||||||
{% end %}
|
|
||||||
<button class="btn btn-success" type="submit">Submit</button> <span id="submit-status"></span>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -276,44 +283,6 @@
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
var file;
|
|
||||||
function sendFile() {
|
|
||||||
file = $("#file")[0].files[0]
|
|
||||||
document.getElementById("upload_input").innerHTML = '<div class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>'
|
|
||||||
let xmlHttpRequest = new XMLHttpRequest();
|
|
||||||
let token = getCookie("_xsrf")
|
|
||||||
let fileName = file.name
|
|
||||||
let target = '/upload'
|
|
||||||
let mimeType = file.type
|
|
||||||
let size = file.size
|
|
||||||
let type = 'background'
|
|
||||||
|
|
||||||
xmlHttpRequest.open('POST', target, true);
|
|
||||||
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
|
|
||||||
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
|
|
||||||
xmlHttpRequest.setRequestHeader('X-Content-Length', size);
|
|
||||||
xmlHttpRequest.setRequestHeader('X-Content-Disposition', 'attachment; filename="' + fileName + '"');
|
|
||||||
xmlHttpRequest.setRequestHeader('X-Content-Upload-Type', type);
|
|
||||||
xmlHttpRequest.setRequestHeader('X-FileName', fileName);
|
|
||||||
xmlHttpRequest.addEventListener('load', (event) => {
|
|
||||||
if (event.target.responseText == 'success') {
|
|
||||||
console.log('Upload for file', file.name, 'was successful!')
|
|
||||||
document.getElementById("upload_input").innerHTML = '<div class="card-header header-sm d-flex justify-content-between align-items-center"><span id="file-uploaded" style="color: gray;">' + fileName + '</span> 🔒</div>';
|
|
||||||
setTimeout(function () {
|
|
||||||
window.location.reload();
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
alert('Upload failed with response: ' + event.target.responseText);
|
|
||||||
doUpload = false;
|
|
||||||
}
|
|
||||||
}, false);
|
|
||||||
xmlHttpRequest.addEventListener('error', (e) => {
|
|
||||||
console.error('Error while uploading file', file.name + '.', 'Event:', e)
|
|
||||||
}, false);
|
|
||||||
xmlHttpRequest.send(file);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.10/js/bootstrap-select.min.js">
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.10/js/bootstrap-select.min.js">
|
||||||
</script>
|
</script>
|
||||||
|
@ -56,11 +56,11 @@
|
|||||||
<input type="hidden" value="import_zip" name="create_type">
|
<input type="hidden" value="import_zip" name="create_type">
|
||||||
<div class="col form-group">
|
<div class="col form-group">
|
||||||
<span id="upload_input"><input type="file" class="form-control-file" id="file" name="file"
|
<span id="upload_input"><input type="file" class="form-control-file" id="file" name="file"
|
||||||
multiple="false" required></span>
|
multiple="false" required></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col form-group">
|
<div class="col form-group">
|
||||||
<button type="button" class="btn btn-info" id="upload-button" onclick="sendFile()"
|
<button type="button" class="btn btn-info" id="upload-button" onclick="sendFile()"
|
||||||
disabled>UPLOAD</button>
|
disabled>UPLOAD</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<hr>
|
<hr>
|
||||||
@ -74,7 +74,7 @@
|
|||||||
<label for="photo" class="col-sm-6 col-form-label">Selected Background Image</label>
|
<label for="photo" class="col-sm-6 col-form-label">Selected Background Image</label>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<select class="form-select form-control form-control-lg select-css form-control-plaintext"
|
<select class="form-select form-control form-control-lg select-css form-control-plaintext"
|
||||||
id="photo" name="photo" form="photo_form" onchange="updateBackgroundPreview()">
|
id="photo" name="photo" form="photo_form" onchange="updateBackgroundPreview()">
|
||||||
{% for image in data["backgrounds"] %}
|
{% for image in data["backgrounds"] %}
|
||||||
<option value="{{image}}">{{image}}</option>
|
<option value="{{image}}">{{image}}</option>
|
||||||
{% end %}
|
{% end %}
|
||||||
@ -84,8 +84,8 @@
|
|||||||
<div id="photo_loading" class="form-group" hidden>
|
<div id="photo_loading" class="form-group" hidden>
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
|
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
|
||||||
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i
|
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i
|
||||||
class="fa-solid fa-spinner"></i></div>
|
class="fa-solid fa-spinner"></i></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
@ -94,12 +94,12 @@
|
|||||||
<label class="col-sm-1" id="opacityValue">{{ data['login_opacity'] }}%</label>
|
<label class="col-sm-1" id="opacityValue">{{ data['login_opacity'] }}%</label>
|
||||||
<div class="range col-sm-8">
|
<div class="range col-sm-8">
|
||||||
<input type="range" class="form-control-range" id="modal_opacity" name="modal_opacity"
|
<input type="range" class="form-control-range" id="modal_opacity" name="modal_opacity"
|
||||||
onchange="previewOpacity()" min="0" max="100" value="{{ data['login_opacity'] }}">
|
onchange="previewOpacity()" min="0" max="100" value="{{ data['login_opacity'] }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="login_preview" style="position: relative;">
|
<div id="login_preview" style="position: relative;">
|
||||||
<img id="bg-preview" src="../../static/assets/images/auth/{{ data['background'] }}"
|
<img id="bg-preview" src="../../static/assets/images/auth/{{ data['background'] }}"
|
||||||
class="img-fluid" alt="Responsive image">
|
class="img-fluid" alt="Responsive image">
|
||||||
<div id="login-form-preview">
|
<div id="login-form-preview">
|
||||||
<div id="login-form-background" class="auto-form-wrapper login-modal">
|
<div id="login-form-background" class="auto-form-wrapper login-modal">
|
||||||
<div class="text-center auto-form-logo">
|
<div class="text-center auto-form-logo">
|
||||||
@ -164,19 +164,19 @@
|
|||||||
|
|
||||||
<div id="login_form_data">
|
<div id="login_form_data">
|
||||||
<input type="hidden" name="_xsrf"
|
<input type="hidden" name="_xsrf"
|
||||||
value="2|1d603267|809fb6bd82f677d440e484dde7c3a310|1671726040" disabled>
|
value="2|1d603267|809fb6bd82f677d440e484dde7c3a310|1671726040" disabled>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="label">Username</label>
|
<label class="label">Username</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" class="form-control login-text-input login-input"
|
<input type="text" class="form-control login-text-input login-input"
|
||||||
placeholder="Username" name="username" id="username" required="true" disabled>
|
placeholder="Username" name="username" id="username" required="true" disabled>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="label">Password</label>
|
<label class="label">Password</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="password" class="form-control login-text-input login-input"
|
<input type="password" class="form-control login-text-input login-input"
|
||||||
placeholder="Password" name="password" id="password" required="true" disabled>
|
placeholder="Password" name="password" id="password" required="true" disabled>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -196,7 +196,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="text-block text-center my-3">
|
<div class="text-block text-center my-3">
|
||||||
<span class="text-small font-weight-semibold"><a
|
<span class="text-small font-weight-semibold"><a
|
||||||
href="https://craftycontrol.com/">Crafty Control
|
href="https://craftycontrol.com/">Crafty Control
|
||||||
4.0.20</a> </span>
|
4.0.20</a> </span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -352,7 +352,7 @@
|
|||||||
var file;
|
var file;
|
||||||
function sendFile() {
|
function sendFile() {
|
||||||
file = $("#file")[0].files[0]
|
file = $("#file")[0].files[0]
|
||||||
document.getElementById("upload_input").innerHTML = '<div class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>';
|
document.getElementById("upload_input").innerHTML = '<div class="progress"><div id="upload-progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>';
|
||||||
let xmlHttpRequest = new XMLHttpRequest();
|
let xmlHttpRequest = new XMLHttpRequest();
|
||||||
let token = getCookie("_xsrf")
|
let token = getCookie("_xsrf")
|
||||||
let fileName = file.name
|
let fileName = file.name
|
||||||
@ -361,6 +361,15 @@
|
|||||||
let size = file.size
|
let size = file.size
|
||||||
let type = 'background'
|
let type = 'background'
|
||||||
|
|
||||||
|
xmlHttpRequest.upload.addEventListener('progress', function (e) {
|
||||||
|
|
||||||
|
if (e.loaded <= size) {
|
||||||
|
var percent = Math.round(e.loaded / size * 100);
|
||||||
|
$(`#upload-progress-bar`).css('width', percent + '%');
|
||||||
|
$(`#upload-progress-bar`).html(percent + '%');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
xmlHttpRequest.open('POST', target, true);
|
xmlHttpRequest.open('POST', target, true);
|
||||||
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
|
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
|
||||||
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
|
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
|
||||||
@ -377,7 +386,15 @@
|
|||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
alert('Upload failed with response: ' + event.target.responseText);
|
let response_text = JSON.parse(event.target.responseText);
|
||||||
|
var x = document.querySelector('.bootbox');
|
||||||
|
console.log(JSON.parse(event.target.responseText).info)
|
||||||
|
bootbox.alert({
|
||||||
|
message: JSON.parse(event.target.responseText).info,
|
||||||
|
callback: function () {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
doUpload = false;
|
doUpload = false;
|
||||||
}
|
}
|
||||||
}, false);
|
}, false);
|
||||||
|
@ -110,15 +110,15 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="command-check" class="form-check-label ml-4 mb-4"></label>
|
<label for="command-check" class="form-check-label ml-4 mb-4"></label>
|
||||||
{% if data['backup_config']['before'] %}
|
{% if data['backup_config']['before'] %}
|
||||||
<input type="checkbox" class="form-check-input" id="before-check" name="before-check" checked>Run
|
<input type="checkbox" class="form-check-input" id="before-check" name="before-check" checked>{{
|
||||||
Command Before Backup
|
translate('serverBackups', 'before', data['lang']) }}
|
||||||
<br>
|
<br>
|
||||||
<input type="text" class="form-control" name="backup_before" id="backup_before"
|
<input type="text" class="form-control" name="backup_before" id="backup_before"
|
||||||
value="{{ data['backup_config']['before'] }}" placeholder="We enter the / for you"
|
value="{{ data['backup_config']['before'] }}" placeholder="We enter the / for you"
|
||||||
style="display: inline-block;">
|
style="display: inline-block;">
|
||||||
{% else %}
|
{% else %}
|
||||||
<input type="checkbox" class="form-check-input" id="before-check" name="before-check">Run Command
|
<input type="checkbox" class="form-check-input" id="before-check" name="before-check">{{
|
||||||
Before Backup
|
translate('serverBackups', 'before', data['lang']) }}
|
||||||
<br>
|
<br>
|
||||||
<input type="text" class="form-control" name="backup_before" id="backup_before" value=""
|
<input type="text" class="form-control" name="backup_before" id="backup_before" value=""
|
||||||
placeholder="We enter the / for you." style="display: none;">
|
placeholder="We enter the / for you." style="display: none;">
|
||||||
@ -127,15 +127,15 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="command-check" class="form-check-label ml-4 mb-4"></label>
|
<label for="command-check" class="form-check-label ml-4 mb-4"></label>
|
||||||
{% if data['backup_config']['after'] %}
|
{% if data['backup_config']['after'] %}
|
||||||
<input type="checkbox" class="form-check-input" id="after-check" name="after-check" checked>Run
|
<input type="checkbox" class="form-check-input" id="after-check" name="after-check" checked>{{
|
||||||
Command After Backup
|
translate('serverBackups', 'after', data['lang']) }}
|
||||||
<br>
|
<br>
|
||||||
<input type="text" class="form-control" name="backup_after" id="backup_after"
|
<input type="text" class="form-control" name="backup_after" id="backup_after"
|
||||||
value="{{ data['backup_config']['after'] }}" placeholder="We enter the / for you"
|
value="{{ data['backup_config']['after'] }}" placeholder="We enter the / for you"
|
||||||
style="display: inline-block;">
|
style="display: inline-block;">
|
||||||
{% else %}
|
{% else %}
|
||||||
<input type="checkbox" class="form-check-input" id="after-check" name="after-check">Run Command
|
<input type="checkbox" class="form-check-input" id="after-check" name="after-check">{{
|
||||||
Before Backup
|
translate('serverBackups', 'after', data['lang']) }}
|
||||||
<br>
|
<br>
|
||||||
<input type="text" class="form-control" name="backup_after" id="backup_after" value=""
|
<input type="text" class="form-control" name="backup_after" id="backup_after" value=""
|
||||||
placeholder="We enter the / for you." style="display: none;">
|
placeholder="We enter the / for you." style="display: none;">
|
||||||
|
@ -184,6 +184,15 @@
|
|||||||
value="{{ data['server_stats']['server_id']['shutdown_timeout'] }}" step="2" max="300" min="60"
|
value="{{ data['server_stats']['server_id']['shutdown_timeout'] }}" step="2" max="300" min="60"
|
||||||
required>
|
required>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ignored_exits">{{ translate('serverConfig', 'ignoredExits', data['lang']) }}
|
||||||
|
<small class="text-muted ml-1"> - {{ translate('serverConfig', 'ignoredExitsExplain',
|
||||||
|
data['lang'])
|
||||||
|
}}
|
||||||
|
</small> </label>
|
||||||
|
<input type="text" class="form-control" name="ignored_exits" id="ignored_exits"
|
||||||
|
value="{{ data['server_stats']['server_id']['ignored_exits'] }}">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="logs_delete_after">{{ translate('serverConfig', 'removeOldLogsAfter', data['lang']) }}
|
<label for="logs_delete_after">{{ translate('serverConfig', 'removeOldLogsAfter', data['lang']) }}
|
||||||
|
@ -705,6 +705,15 @@
|
|||||||
let mimeType = file.type
|
let mimeType = file.type
|
||||||
let size = file.size
|
let size = file.size
|
||||||
|
|
||||||
|
xmlHttpRequest.upload.addEventListener('progress', function (e) {
|
||||||
|
|
||||||
|
if (e.loaded <= size) {
|
||||||
|
var percent = Math.round(e.loaded / size * 100);
|
||||||
|
$(`#upload-progress-bar-${i + 1}`).css('width', percent + '%');
|
||||||
|
$(`#upload-progress-bar-${i + 1}`).html(percent + '%');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
xmlHttpRequest.open('POST', target, true);
|
xmlHttpRequest.open('POST', target, true);
|
||||||
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
|
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
|
||||||
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
|
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
|
||||||
@ -721,10 +730,19 @@
|
|||||||
if (event.target.responseText == 'success') {
|
if (event.target.responseText == 'success') {
|
||||||
console.log('Upload for file', file.name, 'was successful!');
|
console.log('Upload for file', file.name, 'was successful!');
|
||||||
let caught = false;
|
let caught = false;
|
||||||
|
try {
|
||||||
|
if (document.getElementById(path).classList.contains("clicked")) {
|
||||||
|
var expanded = true;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
var expanded = false;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var par_el = document.getElementById(path + "ul");
|
var par_el = document.getElementById(path + "ul");
|
||||||
var items = par_el.children;
|
var items = par_el.children;
|
||||||
} catch {
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
caught = true;
|
caught = true;
|
||||||
var par_el = document.getElementById("files-tree");
|
var par_el = document.getElementById("files-tree");
|
||||||
var items = par_el.children;
|
var items = par_el.children;
|
||||||
@ -739,9 +757,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!flag) {
|
if (!flag) {
|
||||||
if (caught) {
|
if (caught && expanded == false) {
|
||||||
$(par_el).append('<li id=' + '"' + full_path.toString() + 'li' + '"' + 'class="d-block tree-ctx-item tree-file tree-item" data-path=' + '"' + full_path.toString() + '"' + ' data-name=' + '"' + name.toString() + '"' + ' onclick="clickOnFile(event)" ><span style="margin-right: 6px;"><i class="far fa-file"></i></span>' + name + '</li>');
|
$(par_el).append('<li id=' + '"' + full_path.toString() + 'li' + '"' + 'class="d-block tree-ctx-item tree-file tree-item" data-path=' + '"' + full_path.toString() + '"' + ' data-name=' + '"' + name.toString() + '"' + ' onclick="clickOnFile(event)" ><span style="margin-right: 6px;"><i class="far fa-file"></i></span>' + name + '</li>');
|
||||||
} else {
|
} else if (expanded == true) {
|
||||||
$(par_el).append('<li id=' + '"' + full_path.toString() + 'li' + '"' + 'class="tree-ctx-item tree-file tree-item" data-path=' + '"' + full_path.toString() + '"' + ' data-name=' + '"' + name.toString() + '"' + ' onclick="clickOnFile(event)" ><span style="margin-right: 6px;"><i class="far fa-file"></i></span>' + name + '</li>');
|
$(par_el).append('<li id=' + '"' + full_path.toString() + 'li' + '"' + 'class="tree-ctx-item tree-file tree-item" data-path=' + '"' + full_path.toString() + '"' + ' data-name=' + '"' + name.toString() + '"' + ' onclick="clickOnFile(event)" ><span style="margin-right: 6px;"><i class="far fa-file"></i></span>' + name + '</li>');
|
||||||
}
|
}
|
||||||
setTreeViewContext();
|
setTreeViewContext();
|
||||||
@ -751,7 +769,22 @@
|
|||||||
$(`#upload-progress-bar-${i + 1}`).html('<i style="color: black;" class="fas fa-box-check"></i>')
|
$(`#upload-progress-bar-${i + 1}`).html('<i style="color: black;" class="fas fa-box-check"></i>')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
alert('Upload failed with response: ' + event.target.responseText);
|
let response_text = JSON.parse(event.target.responseText);
|
||||||
|
var x = document.querySelector('.bootbox');
|
||||||
|
if (x) {
|
||||||
|
x.remove()
|
||||||
|
}
|
||||||
|
var x = document.querySelector('.modal-content');
|
||||||
|
if (x) {
|
||||||
|
x.remove()
|
||||||
|
}
|
||||||
|
console.log(JSON.parse(event.target.responseText).info)
|
||||||
|
bootbox.alert({
|
||||||
|
message: JSON.parse(event.target.responseText).info,
|
||||||
|
callback: function () {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
doUpload = false;
|
doUpload = false;
|
||||||
}
|
}
|
||||||
}, false);
|
}, false);
|
||||||
@ -788,7 +821,7 @@
|
|||||||
var height = files.files.length * 50;
|
var height = files.files.length * 50;
|
||||||
|
|
||||||
var waitMessage = '<p class="text-center mb-0">' +
|
var waitMessage = '<p class="text-center mb-0">' +
|
||||||
'<i class="fa fa-spin fa-cog"></i>' +
|
'<i class="fa fa-spin fa-cog"></i> ' +
|
||||||
"{{ translate('serverFiles', 'waitUpload', data['lang']) }}" + '<br>' +
|
"{{ translate('serverFiles', 'waitUpload', data['lang']) }}" + '<br>' +
|
||||||
'<strong>' + "{{ translate('serverFiles', 'stayHere', data['lang']) }}" + '</strong>' +
|
'<strong>' + "{{ translate('serverFiles', 'stayHere', data['lang']) }}" + '</strong>' +
|
||||||
'</p>' +
|
'</p>' +
|
||||||
@ -826,7 +859,7 @@
|
|||||||
|
|
||||||
await sendFile(files.files[i], path, serverId, nFiles - i - 1, i, (progress) => {
|
await sendFile(files.files[i], path, serverId, nFiles - i - 1, i, (progress) => {
|
||||||
$(`#upload-progress-bar-${i + 1}`).attr('aria-valuenow', progress)
|
$(`#upload-progress-bar-${i + 1}`).attr('aria-valuenow', progress)
|
||||||
$(`#upload-progress-bar-${i + 1}`).css('width', progress + '%')
|
$(`#upload-progress-bar-${i + 1}`).css('width', progress + '%');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
hideUploadBox();
|
hideUploadBox();
|
||||||
|
@ -563,7 +563,7 @@
|
|||||||
var file;
|
var file;
|
||||||
function sendFile() {
|
function sendFile() {
|
||||||
file = $("#file")[0].files[0]
|
file = $("#file")[0].files[0]
|
||||||
document.getElementById("upload_input").innerHTML = '<div class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>'
|
document.getElementById("upload_input").innerHTML = '<div class="progress"><div id="upload-progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>'
|
||||||
let xmlHttpRequest = new XMLHttpRequest();
|
let xmlHttpRequest = new XMLHttpRequest();
|
||||||
let token = getCookie("_xsrf")
|
let token = getCookie("_xsrf")
|
||||||
let fileName = encodeURIComponent(file.name)
|
let fileName = encodeURIComponent(file.name)
|
||||||
@ -572,6 +572,15 @@
|
|||||||
let size = file.size
|
let size = file.size
|
||||||
let type = 'server_import'
|
let type = 'server_import'
|
||||||
|
|
||||||
|
xmlHttpRequest.upload.addEventListener('progress', function (e) {
|
||||||
|
|
||||||
|
if (e.loaded <= size) {
|
||||||
|
var percent = Math.round(e.loaded / size * 100);
|
||||||
|
$(`#upload-progress-bar`).css('width', percent + '%');
|
||||||
|
$(`#upload-progress-bar`).html(percent + '%');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
xmlHttpRequest.open('POST', target, true);
|
xmlHttpRequest.open('POST', target, true);
|
||||||
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
|
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
|
||||||
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
|
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
|
||||||
@ -586,7 +595,15 @@
|
|||||||
document.getElementById("lower_half").style.visibility = "visible";
|
document.getElementById("lower_half").style.visibility = "visible";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
alert('Upload failed with response: ' + event.target.responseText);
|
let response_text = JSON.parse(event.target.responseText);
|
||||||
|
var x = document.querySelector('.bootbox');
|
||||||
|
console.log(JSON.parse(event.target.responseText).info)
|
||||||
|
bootbox.alert({
|
||||||
|
message: JSON.parse(event.target.responseText).info,
|
||||||
|
callback: function () {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
doUpload = false;
|
doUpload = false;
|
||||||
}
|
}
|
||||||
}, false);
|
}, false);
|
||||||
|
@ -805,7 +805,7 @@
|
|||||||
var file;
|
var file;
|
||||||
function sendFile() {
|
function sendFile() {
|
||||||
file = $("#file")[0].files[0]
|
file = $("#file")[0].files[0]
|
||||||
document.getElementById("upload_input").innerHTML = '<div class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>'
|
document.getElementById("upload_input").innerHTML = '<div class="progress"><div id="upload-progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>'
|
||||||
let xmlHttpRequest = new XMLHttpRequest();
|
let xmlHttpRequest = new XMLHttpRequest();
|
||||||
let token = getCookie("_xsrf")
|
let token = getCookie("_xsrf")
|
||||||
let fileName = file.name
|
let fileName = file.name
|
||||||
@ -814,6 +814,15 @@
|
|||||||
let size = file.size
|
let size = file.size
|
||||||
let type = 'server_import'
|
let type = 'server_import'
|
||||||
|
|
||||||
|
xmlHttpRequest.upload.addEventListener('progress', function (e) {
|
||||||
|
|
||||||
|
if (e.loaded <= size) {
|
||||||
|
var percent = Math.round(e.loaded / size * 100);
|
||||||
|
$(`#upload-progress-bar`).css('width', percent + '%');
|
||||||
|
$(`#upload-progress-bar`).html(percent + '%');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
xmlHttpRequest.open('POST', target, true);
|
xmlHttpRequest.open('POST', target, true);
|
||||||
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
|
xmlHttpRequest.setRequestHeader('X-Content-Type', mimeType);
|
||||||
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
|
xmlHttpRequest.setRequestHeader('X-XSRFToken', token);
|
||||||
@ -828,7 +837,15 @@
|
|||||||
document.getElementById("lower_half").style.visibility = "visible";
|
document.getElementById("lower_half").style.visibility = "visible";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
alert('Upload failed with response: ' + event.target.responseText);
|
let response_text = JSON.parse(event.target.responseText);
|
||||||
|
var x = document.querySelector('.bootbox');
|
||||||
|
console.log(JSON.parse(event.target.responseText).info)
|
||||||
|
bootbox.alert({
|
||||||
|
message: JSON.parse(event.target.responseText).info,
|
||||||
|
callback: function () {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
doUpload = false;
|
doUpload = false;
|
||||||
}
|
}
|
||||||
}, false);
|
}, false);
|
||||||
|
16
app/migrations/20220223_ignored_exits.py
Normal file
16
app/migrations/20220223_ignored_exits.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Generated by database migrator
|
||||||
|
import peewee
|
||||||
|
|
||||||
|
|
||||||
|
def migrate(migrator, database, **kwargs):
|
||||||
|
migrator.add_columns("servers", ignored_exits=peewee.CharField(default="0"))
|
||||||
|
"""
|
||||||
|
Write your migrations here.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def rollback(migrator, database, **kwargs):
|
||||||
|
migrator.drop_columns("servers", ["ignored_exits"])
|
||||||
|
"""
|
||||||
|
Write your rollback migrations here.
|
||||||
|
"""
|
@ -299,7 +299,9 @@
|
|||||||
"shutdown": "Shutdown server for duration of backup",
|
"shutdown": "Shutdown server for duration of backup",
|
||||||
"size": "Size",
|
"size": "Size",
|
||||||
"storageLocation": "Storage Location",
|
"storageLocation": "Storage Location",
|
||||||
"storageLocationDesc": "Where do you want to store backups?"
|
"storageLocationDesc": "Where do you want to store backups?",
|
||||||
|
"before": "Run command before backup",
|
||||||
|
"after": "Run command after backup"
|
||||||
},
|
},
|
||||||
"serverConfig": {
|
"serverConfig": {
|
||||||
"bePatientDelete": "Please be patient while we remove your server from the Crafty panel. This screen will close in a few moments.",
|
"bePatientDelete": "Please be patient while we remove your server from the Crafty panel. This screen will close in a few moments.",
|
||||||
@ -354,7 +356,9 @@
|
|||||||
"timeoutExplain1": "How long Crafty will wait for your server to shutdown after executing the",
|
"timeoutExplain1": "How long Crafty will wait for your server to shutdown after executing the",
|
||||||
"timeoutExplain2": "command before it forces the process down.",
|
"timeoutExplain2": "command before it forces the process down.",
|
||||||
"statsHint1": "The port your server is running on should go here. This is just how Crafty opens a connection to your server for stats.",
|
"statsHint1": "The port your server is running on should go here. This is just how Crafty opens a connection to your server for stats.",
|
||||||
"statsHint2": "This does not change the port of your server. You must still change the port in your server config file."
|
"statsHint2": "This does not change the port of your server. You must still change the port in your server config file.",
|
||||||
|
"ignoredExits": "Ignored Crash Exit Codes",
|
||||||
|
"ignoredExitsExplain": "Exit codes Crafty's Crash detection should ignore as a normal 'stop' (separated by commas)"
|
||||||
},
|
},
|
||||||
"serverConfigHelp": {
|
"serverConfigHelp": {
|
||||||
"desc": "Here is where you can change the configuration of your server",
|
"desc": "Here is where you can change the configuration of your server",
|
||||||
|
Loading…
Reference in New Issue
Block a user