Merge branch 'dev' into 'master'

v4.2.1

See merge request crafty-controller/crafty-4!663
This commit is contained in:
Iain Powrie 2023-11-01 02:48:02 +00:00
commit 46043520ba
26 changed files with 1098 additions and 377 deletions

View File

@ -44,7 +44,7 @@ black:
# Code Climate/Quality Checking [https://pylint.pycqa.org/en/latest/] # Code Climate/Quality Checking [https://pylint.pycqa.org/en/latest/]
pylint: pylint:
stage: lint stage: lint
image: registry.gitlab.com/pipeline-components/pylint:latest image: registry.gitlab.com/pipeline-components/pylint:0.21.1
tags: tags:
- docker - docker
rules: rules:

View File

@ -1,4 +1,23 @@
# Changelog # Changelog
## --- [4.2.1] - 2023/11/01
### Bug fixes
- Fix logic issue with `get_files` API permissions check ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/654))
- Fix notifications not showing up/being reset #298 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/660))
- Fix users not being able to be deleted since the prompt fails to display ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/661))
- Fix duplicate function naming on dashboard ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/662))
### Tweaks
- Auto refresh Crafty Announcements on 30m interval ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/653))
- Improve Crafty toggle buttons and Webhooks page ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/656))
### Lang
- Update `zh_CN` lang file ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/652))
- Update `es_ES` lang file ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/655))
- Clean up wording in `pl_PL` lang file ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/656))
- Add `de_DE`, `es_ES` `fr_FR`, `lol_EN`, `lv_LV`, `nl_BE` `pl_PL` & `zh_CN` translations for !656 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/656))
### Docs
- [(New) Server Webhook Documentation](https://docs.craftycontrol.com/pages/user-guide/webhooks/)
- [(Edit) Image Context in Windows Service - Install steps, with slight wording improvement](https://docs.craftycontrol.com/pages/getting-started/installation/windows/#install-steps)
<br><br>
## --- [4.2.0] - 2023/10/18 ## --- [4.2.0] - 2023/10/18
### New features ### New features
- Finish and Activate Arcadia notification backend ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/621) | [Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/626) | [Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/632)) - Finish and Activate Arcadia notification backend ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/621) | [Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/626) | [Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/632))

View File

@ -1,5 +1,5 @@
[![Crafty Logo](app/frontend/static/assets/images/logo_long.svg)](https://craftycontrol.com) [![Crafty Logo](app/frontend/static/assets/images/logo_long.svg)](https://craftycontrol.com)
# Crafty Controller 4.2.0 # Crafty Controller 4.2.1
> Python based Control Panel for your Minecraft Server > Python based Control Panel for your Minecraft Server
## What is Crafty Controller? ## What is Crafty Controller?

View File

@ -578,16 +578,19 @@ class Helpers:
return version_data return version_data
def get_announcements(self): def get_announcements(self):
data = []
try: try:
data = []
response = requests.get("https://craftycontrol.com/notify", timeout=2) response = requests.get("https://craftycontrol.com/notify", timeout=2)
data = json.loads(response.content) data = json.loads(response.content)
if self.update_available:
data.append(self.update_available)
return data
except Exception as e: except Exception as e:
logger.error(f"Failed to fetch notifications with error: {e}") logger.error(f"Failed to fetch notifications with error: {e}")
if self.update_available:
if self.update_available: data = [self.update_available]
data.append(self.update_available) else:
return data return False
def get_version_string(self): def get_version_string(self):
version_data = self.get_version() version_data = self.get_version()

View File

@ -29,6 +29,14 @@ class ApiAnnounceIndexHandler(BaseApiHandler):
) = auth_data ) = auth_data
data = self.helper.get_announcements() data = self.helper.get_announcements()
if not data:
return self.finish_json(
424,
{
"status": "error",
"data": "Failed to get announcements",
},
)
cleared = str( cleared = str(
self.controller.users.get_user_by_id(auth_data[4]["user_id"])[ self.controller.users.get_user_by_id(auth_data[4]["user_id"])[
"cleared_notifs" "cleared_notifs"
@ -84,6 +92,14 @@ class ApiAnnounceIndexHandler(BaseApiHandler):
}, },
) )
announcements = self.helper.get_announcements() announcements = self.helper.get_announcements()
if not announcements:
return self.finish_json(
424,
{
"status": "error",
"data": "Failed to get current announcements",
},
)
res = [d.get("id", None) for d in announcements] res = [d.get("id", None) for d in announcements]
cleared_notifs = str( cleared_notifs = str(
self.controller.users.get_user_by_id(auth_data[4]["user_id"])[ self.controller.users.get_user_by_id(auth_data[4]["user_id"])[

View File

@ -86,7 +86,7 @@ class ApiServersServerFilesIndexHandler(BaseApiHandler):
not in self.controller.server_perms.get_user_id_permissions_list( not in self.controller.server_perms.get_user_id_permissions_list(
auth_data[4]["user_id"], server_id auth_data[4]["user_id"], server_id
) )
or EnumPermissionsServer.BACKUP and EnumPermissionsServer.BACKUP
not in self.controller.server_perms.get_user_id_permissions_list( not in self.controller.server_perms.get_user_id_permissions_list(
auth_data[4]["user_id"], server_id auth_data[4]["user_id"], server_id
) )

View File

@ -21,7 +21,6 @@ class WebhookFactory:
"Mattermost": MattermostWebhook, "Mattermost": MattermostWebhook,
"Slack": SlackWebhook, "Slack": SlackWebhook,
"Teams": TeamsWebhook, "Teams": TeamsWebhook,
# "Custom",
} }
@classmethod @classmethod

View File

@ -1,5 +1,5 @@
{ {
"major": 4, "major": 4,
"minor": 2, "minor": 2,
"sub": 0 "sub": 1
} }

View File

@ -0,0 +1,447 @@
/**************************************************************/
/* CSS for Toggle Buttons */
/**************************************************************/
.btn-toggle {
margin: 0 4rem;
padding: 0;
position: relative;
border: none;
height: 1.5rem;
width: 3rem;
border-radius: 1.5rem;
color: #6b7381;
background: #bdc1c8;
}
.btn-toggle:focus,
.btn-toggle.focus,
.btn-toggle:focus.active,
.btn-toggle.focus.active {
outline: none;
}
.btn-toggle:before,
.btn-toggle:after {
line-height: 1.5rem;
width: 4rem;
text-align: center;
font-weight: 600;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 2px;
position: absolute;
bottom: 0;
transition: opacity 0.25s;
}
.btn-toggle:before {
content: 'Off';
left: -4rem;
}
.btn-toggle:after {
content: 'On';
right: -4rem;
opacity: 0.5;
}
.btn-toggle>.handle {
position: absolute;
top: 0.1875rem;
left: 0.1875rem;
width: 1.125rem;
height: 1.125rem;
border-radius: 1.125rem;
background: #fff;
transition: left 0.25s;
}
.btn-toggle.active {
transition: background-color 0.25s;
}
.btn-toggle.active>.handle {
left: 1.6875rem;
transition: left 0.25s;
}
.btn-toggle.active:before {
opacity: 0.5;
}
.btn-toggle.active:after {
opacity: 1;
}
.btn-toggle.btn-sm:before,
.btn-toggle.btn-sm:after {
line-height: -0.5rem;
color: #fff;
letter-spacing: 0.75px;
left: 0.4125rem;
width: 2.325rem;
}
.btn-toggle.btn-sm:before {
text-align: right;
}
.btn-toggle.btn-sm:after {
text-align: left;
opacity: 0;
}
.btn-toggle.btn-sm.active:before {
opacity: 0;
}
.btn-toggle.btn-sm.active:after {
opacity: 1;
}
.btn-toggle.btn-xs:before,
.btn-toggle.btn-xs:after {
display: none;
}
.btn-toggle:before,
.btn-toggle:after {
color: #6b7381;
}
.btn-toggle.active {
background-color: #29b5a8;
}
.btn-toggle.btn-lg {
margin: 0 5rem;
padding: 0;
position: relative;
border: none;
height: 2.5rem;
width: 5rem;
border-radius: 2.5rem;
}
.btn-toggle.btn-lg:focus,
.btn-toggle.btn-lg.focus,
.btn-toggle.btn-lg:focus.active,
.btn-toggle.btn-lg.focus.active {
outline: none;
}
.btn-toggle.btn-lg:before,
.btn-toggle.btn-lg:after {
line-height: 2.5rem;
width: 5rem;
text-align: center;
font-weight: 600;
font-size: 1rem;
text-transform: uppercase;
letter-spacing: 2px;
position: absolute;
bottom: 0;
transition: opacity 0.25s;
}
.btn-toggle.btn-lg:before {
content: 'Off';
left: -5rem;
}
.btn-toggle.btn-lg:after {
content: 'On';
right: -5rem;
opacity: 0.5;
}
.btn-toggle.btn-lg>.handle {
position: absolute;
top: 0.3125rem;
left: 0.3125rem;
width: 1.875rem;
height: 1.875rem;
border-radius: 1.875rem;
background: #fff;
transition: left 0.25s;
}
.btn-toggle.btn-lg.active {
transition: background-color 0.25s;
}
.btn-toggle.btn-lg.active>.handle {
left: 2.8125rem;
transition: left 0.25s;
}
.btn-toggle.btn-lg.active:before {
opacity: 0.5;
}
.btn-toggle.btn-lg.active:after {
opacity: 1;
}
.btn-toggle.btn-lg.btn-sm:before,
.btn-toggle.btn-lg.btn-sm:after {
line-height: 0.5rem;
color: #fff;
letter-spacing: 0.75px;
left: 0.6875rem;
width: 3.875rem;
}
.btn-toggle.btn-lg.btn-sm:before {
text-align: right;
}
.btn-toggle.btn-lg.btn-sm:after {
text-align: left;
opacity: 0;
}
.btn-toggle.btn-lg.btn-sm.active:before {
opacity: 0;
}
.btn-toggle.btn-lg.btn-sm.active:after {
opacity: 1;
}
.btn-toggle.btn-lg.btn-xs:before,
.btn-toggle.btn-lg.btn-xs:after {
display: none;
}
.btn-toggle.btn-sm {
margin: 0 0.5rem;
padding: 0;
position: relative;
border: none;
height: 1.5rem;
width: 3rem;
border-radius: 1.5rem;
}
.btn-toggle.btn-sm:focus,
.btn-toggle.btn-sm.focus,
.btn-toggle.btn-sm:focus.active,
.btn-toggle.btn-sm.focus.active {
outline: none;
}
.btn-toggle.btn-sm:before,
.btn-toggle.btn-sm:after {
line-height: 1.5rem;
width: 0.5rem;
text-align: center;
font-weight: 600;
font-size: 0.55rem;
text-transform: uppercase;
letter-spacing: 2px;
position: absolute;
bottom: 0;
transition: opacity 0.25s;
}
.btn-toggle.btn-sm:before {
content: 'Off';
left: -0.5rem;
}
.btn-toggle.btn-sm:after {
content: 'On';
right: -0.5rem;
opacity: 0.5;
}
.btn-toggle.btn-sm>.handle {
position: absolute;
top: 0.1875rem;
left: 0.1875rem;
width: 1.125rem;
height: 1.125rem;
border-radius: 1.125rem;
background: #fff;
transition: left 0.25s;
}
.btn-toggle.btn-sm.active {
transition: background-color 0.25s;
}
.btn-toggle.btn-sm.active>.handle {
left: 1.6875rem;
transition: left 0.25s;
}
.btn-toggle.btn-sm.active:before {
opacity: 0.5;
}
.btn-toggle.btn-sm.active:after {
opacity: 1;
}
.btn-toggle.btn-sm.btn-sm:before,
.btn-toggle.btn-sm.btn-sm:after {
line-height: -0.5rem;
color: #fff;
letter-spacing: 0.75px;
left: 0.4125rem;
width: 2.325rem;
}
.btn-toggle.btn-sm.btn-sm:before {
text-align: right;
}
.btn-toggle.btn-sm.btn-sm:after {
text-align: left;
opacity: 0;
}
.btn-toggle.btn-sm.btn-sm.active:before {
opacity: 0;
}
.btn-toggle.btn-sm.btn-sm.active:after {
opacity: 1;
}
.btn-toggle.btn-sm.btn-xs:before,
.btn-toggle.btn-sm.btn-xs:after {
display: none;
}
.btn-toggle.btn-xs {
margin: 0 0;
padding: 0;
position: relative;
border: none;
height: 1rem;
width: 2rem;
border-radius: 1rem;
}
.btn-toggle.btn-xs:focus,
.btn-toggle.btn-xs.focus,
.btn-toggle.btn-xs:focus.active,
.btn-toggle.btn-xs.focus.active {
outline: none;
}
.btn-toggle.btn-xs:before,
.btn-toggle.btn-xs:after {
line-height: 1rem;
width: 0;
text-align: center;
font-weight: 600;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 2px;
position: absolute;
bottom: 0;
transition: opacity 0.25s;
}
.btn-toggle.btn-xs:before {
content: 'Off';
left: 0;
}
.btn-toggle.btn-xs:after {
content: 'On';
right: 0;
opacity: 0.5;
}
.btn-toggle.btn-xs>.handle {
position: absolute;
top: 0.125rem;
left: 0.125rem;
width: 0.75rem;
height: 0.75rem;
border-radius: 0.75rem;
background: #fff;
transition: left 0.25s;
}
.btn-toggle.btn-xs.active {
transition: background-color 0.25s;
}
.btn-toggle.btn-xs.active>.handle {
left: 1.125rem;
transition: left 0.25s;
}
.btn-toggle.btn-xs.active:before {
opacity: 0.5;
}
.btn-toggle.btn-xs.active:after {
opacity: 1;
}
.btn-toggle.btn-xs.btn-sm:before,
.btn-toggle.btn-xs.btn-sm:after {
line-height: -1rem;
color: #fff;
letter-spacing: 0.75px;
left: 0.275rem;
width: 1.55rem;
}
.btn-toggle.btn-xs.btn-sm:before {
text-align: right;
}
.btn-toggle.btn-xs.btn-sm:after {
text-align: left;
opacity: 0;
}
.btn-toggle.btn-xs.btn-sm.active:before {
opacity: 0;
}
.btn-toggle.btn-xs.btn-sm.active:after {
opacity: 1;
}
.btn-toggle.btn-xs.btn-xs:before,
.btn-toggle.btn-xs.btn-xs:after {
display: none;
}
.btn-toggle.btn-info {
color: var(--white);
background: var(--gray);
}
.btn-toggle.btn-info:before,
.btn-toggle.btn-info:after {
color: #6b7381;
}
.btn-toggle.btn-info.active {
background-color: var(--info);
}
.btn-toggle.btn-secondary {
color: #6b7381;
background: #bdc1c8;
}
.btn-toggle.btn-secondary:before,
.btn-toggle.btn-secondary:after {
color: #6b7381;
}
.btn-toggle.btn-secondary.active {
background-color: #ff8300;
}
/**************************************************************/

View File

@ -182,11 +182,55 @@ div>.input-group>.form-control {
} }
.no-scroll { .no-scroll {
-ms-overflow-style: none; /* IE and Edge */ -ms-overflow-style: none;
scrollbar-width: none; /* Firefox */ /* IE and Edge */
scrollbar-width: none;
/* Firefox */
} }
.no-scroll::-webkit-scrollbar { .no-scroll::-webkit-scrollbar {
display: none; display: none;
} }
.custom-control-label::before,
.custom-control-label::after {
cursor: pointer;
}
.custom-control-input:checked~.custom-control-label::before {
color: black !important;
background-color: blueviolet !important;
border-color: var(--outline) !important;
}
.custom-control-label::before {
background-color: white !important;
top: calc(-0.2rem);
}
.custom-switch .custom-control-label::after {
top: calc(-0.125rem + 1px);
}
/**************************************************************/
/**************************************************************/
/* CSS for Tables Displays */
/**************************************************************/
td>ul {
margin: auto;
}
td p {
margin: auto;
}
td.action {
white-space: normal;
}
td.action .btn {
margin-bottom: 0.2rem;
}
/**************************************************************/ /**************************************************************/

View File

@ -17,6 +17,7 @@
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs4/dt-1.10.22/fh-3.1.7/r-2.2.6/sc-2.0.3/sp-1.2.2/datatables.min.css" /> <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs4/dt-1.10.22/fh-3.1.7/r-2.2.6/sc-2.0.3/sp-1.2.2/datatables.min.css" />
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css"> <link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
<link rel="stylesheet" href="/static/assets/css/crafty.css"> <link rel="stylesheet" href="/static/assets/css/crafty.css">
<link rel="stylesheet" href="/static/assets/css/crafty-toggle-btn.css">
<link rel="manifest" href="/static/assets/crafty.webmanifest"> <link rel="manifest" href="/static/assets/crafty.webmanifest">
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">

View File

@ -93,7 +93,7 @@
return true; return true;
} }
function updateAnnouncements(data) { function updateAnnouncements(data) {
console.log(data) console.log(data);
let text = ""; let text = "";
for (let value of data) { for (let value of data) {
text += `<li class="card-header header-sm justify-content-between align-items-center" id="${value.id}"><p style="float: right;"><i data-id="${value.id}"class="clear-button fa-regular fa-x"></i></p><a style="color: var(--purple);" href=${value.link} target="_blank"><h6>${value.title}</h6><small><p>${value.date}</p></small><p>${value.desc}</p></li></a>` text += `<li class="card-header header-sm justify-content-between align-items-center" id="${value.id}"><p style="float: right;"><i data-id="${value.id}"class="clear-button fa-regular fa-x"></i></p><a style="color: var(--purple);" href=${value.link} target="_blank"><h6>${value.title}</h6><small><p>${value.date}</p></small><p>${value.desc}</p></li></a>`
@ -136,10 +136,14 @@
}); });
let responseData = await res.json(); let responseData = await res.json();
console.log(responseData); console.log(responseData);
setTimeout(function() {
getAnnouncements();
}, 1800000); //Wait 30 minutes in miliseconds
console.log("Registered annoucement fetch event in 30 minutes.")
if (responseData.status === "ok") { if (responseData.status === "ok") {
updateAnnouncements(responseData.data) updateAnnouncements(responseData.data)
} else { } else {
updateAnnouncements("<li><p>Trouble Getting Annoucements</p></li>") updateAnnouncements([])
} }
} }
async function send_clear(uuid) { async function send_clear(uuid) {

View File

@ -615,7 +615,7 @@
} }
function warn(message, link = null, className = null) { function warnServer(message, link = null, className = null) {
var closeEl = document.createElement('span'); var closeEl = document.createElement('span');
var strongEL = document.createElement('strong'); var strongEL = document.createElement('strong');
var msgEl = document.createElement('div'); var msgEl = document.createElement('div');
@ -799,7 +799,7 @@
setTimeout(finishTimeout, 60000); setTimeout(finishTimeout, 60000);
}); });
function finishTimeout() { function finishTimeout() {
warn("It seems this is taking a while...it's possible you're using UBlock or a similar ad blocker and it's causing some of our connections to not make it to the server. Try disabling your ad blocker.", warnServer("It seems this is taking a while...it's possible you're using UBlock or a similar ad blocker and it's causing some of our connections to not make it to the server. Try disabling your ad blocker.",
null, 'wssError'); null, 'wssError');
} }
$(".stop_button").click(function () { $(".stop_button").click(function () {

View File

@ -363,6 +363,7 @@ data['lang']) }}{% end %}
{% block js %} {% block js %}
<script> <script>
const userId = new URLSearchParams(document.location.search).get('id');
function submit_user(event) { function submit_user(event) {
if (!validateForm()) { if (!validateForm()) {
event.preventDefault(); event.preventDefault();
@ -399,8 +400,6 @@ data['lang']) }}{% end %}
} }
} }
$("#user_form").on("submit", async function (e) { $("#user_form").on("submit", async function (e) {
const userId = new URLSearchParams(document.location.search).get('id');
console.log(userId)
e.preventDefault(); e.preventDefault();
let password = null; let password = null;
if(!userId){ if(!userId){

View File

@ -47,198 +47,184 @@
<h4 class="card-title"><i class="fas fa-calendar"></i> {{ translate('serverSchedules', <h4 class="card-title"><i class="fas fa-calendar"></i> {{ translate('serverSchedules',
'scheduledTasks', data['lang']) }} </h4> 'scheduledTasks', data['lang']) }} </h4>
{% if data['user_data']['hints'] %} {% if data['user_data']['hints'] %}
<span class="too_small" title="{{ translate('serverSchedules', 'cannotSee', data['lang']) }}" , <span class="too_small" title="{{ translate('serverSchedules', 'cannotSee', data['lang']) }}" , data-content="{{ translate('serverSchedules', 'cannotSeeOnMobile', data['lang']) }}" , data-placement="bottom"></span>
data-content="{{ translate('serverSchedules', 'cannotSeeOnMobile', data['lang']) }}" ,
data-placement="bottom"></span>
{% end %} {% end %}
<div> <div><a class="btn btn-info" href="/panel/add_schedule?id={{ data['server_stats']['server_id']['server_id'] }}"><i class="fas fa-plus-circle"></i> {{ translate('serverSchedules', 'create', data['lang']) }}</a></div>
<button
onclick="location.href=`/panel/add_schedule?id={{ data['server_stats']['server_id']['server_id'] }}`"
class="btn btn-info">{{ translate('serverSchedules', 'create', data['lang']) }}<i
class="fas fa-pencil-alt"></i></button>
</div>
</div> </div>
<div class="card-body"> <div class="card-body">
<table class="table table-hover d-none d-lg-block responsive-table" id="schedule_table" {% if len(data['schedules']) == 0 %}
style="table-layout:fixed;" aria-describedby="Schedule List"> <div style="text-align: center; color: grey;">
<thead> <h7>{{ translate('serverSchedules', 'no-schedule', data['lang']) }} <strong>{{ translate('serverSchedules', 'newSchedule',data['lang']) }}</strong>.</h7>
<tr class="rounded"> </div>
<th style="width: 2%; min-width: 10px;">{{ translate('serverSchedules', 'name', data['lang']) }} {% end %}
</th> {% if len(data['schedules']) > 0 %}
<th style="width: 23%; min-width: 50px;">{{ translate('serverSchedules', 'action', data['lang']) <div class="d-none d-lg-block">
}}</th> <table class="table table-hover table-responsive" id="schedule_table" style="table-layout:fixed;" aria-describedby="Schedule List">
<th style="width: 40%; min-width: 50px;">{{ translate('serverSchedules', 'command', <thead>
data['lang']) }}</th> <tr class="rounded">
<th style="width: 10%; min-width: 50px;">{{ translate('serverSchedules', 'interval', <th style="width: 5%; min-width: 64px;">{{ translate('serverSchedules', 'enabled',
data['lang']) }}</th> data['lang']) }}</th>
<th style="width: 10%; min-width: 50px;">{{ translate('serverSchedules', 'nextRun', <th style="width: 7%; min-width: 10px;">{{ translate('serverSchedules', 'name', data['lang']) }}
data['lang']) }}</th> </th>
<th style="width: 10%; min-width: 50px;">{{ translate('serverSchedules', 'enabled', <th style="width: 23%; min-width: 50px;">{{ translate('serverSchedules', 'action', data['lang'])
data['lang']) }}</th> }}</th>
<th style="width: 10%; min-width: 50px;">{{ translate('serverSchedules', 'edit', data['lang']) <th style="width: 40%; min-width: 50px;">{{ translate('serverSchedules', 'command',
}}</th> data['lang']) }}</th>
</tr> <th style="width: 10%; min-width: 50px;">{{ translate('serverSchedules', 'interval',
</thead> data['lang']) }}</th>
<tbody> <th style="width: 10%; min-width: 50px;">{{ translate('serverSchedules', 'nextRun',
{% for schedule in data['schedules'] %} data['lang']) }}</th>
<tr> <th style="width: 10%; min-width: 50px;">{{ translate('serverSchedules', 'edit', data['lang'])
<td id="{{schedule.schedule_id}}" class="id"> }}</th>
<p>{{schedule.name}}</p> </tr>
</td> </thead>
<td id="{{schedule.action}}" class="action"> <tbody>
<p>{{schedule.action}}</p> {% for schedule in data['schedules'] %}
</td> <tr>
<td id="{{schedule.command}}" class="action" style="overflow: scroll; max-width: 30px;"> <td id="{{schedule.enabled}}" class="enabled">
<p style="overflow: scroll;" class="no-scroll">{{schedule.command}}</p> <button type="button" class="btn btn-sm btn-info btn-toggle schedule-custom-toggle" id="schedule{{schedule.id}}" name="schedule{{schedule.id}}" data-schedule-id="{{schedule.schedule_id}}" data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}" data-toggle="button" aria-pressed="true" autocomplete="off">
</td> <div class="handle"></div>
<td id="{{schedule.interval}}" class="action"> </button>
{% if schedule.interval_type != '' and schedule.interval_type != 'reaction' %} </td>
<p>{{ translate('serverSchedules', 'every', data['lang']) }}</p> <td id="{{schedule.schedule_id}}" class="id">
<p>{{schedule.interval}} {{schedule.interval_type}}</p> <p>{{schedule.name}}</p>
{% elif schedule.interval_type == 'reaction' %} </td>
<p>{{schedule.interval_type}}<br><br>{{ translate('serverSchedules', 'child', data['lang'])}}: <td id="{{schedule.action}}">
{{ schedule.parent }}</p> <p>{{schedule.action}}</p>
{% else %} </td>
<p>Cron String:</p> <td id="{{schedule.command}}" style="overflow: scroll; max-width: 30px;">
<p>{{schedule.cron_string}}</p> <p style="overflow: scroll;" class="no-scroll">{{schedule.command}}</p>
{% end %} </td>
</td> <td id="{{schedule.interval}}">
<td id="{{schedule.start_time}}" class="action"> {% if schedule.interval_type != '' and schedule.interval_type != 'reaction' %}
<p>{{schedule.next_run}}</p> <p>{{ translate('serverSchedules', 'every', data['lang']) }}</p>
</td> <p>{{schedule.interval}} {{schedule.interval_type}}</p>
<td id="{{schedule.enabled}}" class="action"> {% elif schedule.interval_type == 'reaction' %}
<input style="width: 10px !important;" type="checkbox" class="schedule-enabled-toggle" <p>{{schedule.interval_type}}<br><br>{{ translate('serverSchedules', 'child', data['lang'])}}:
data-schedule-id="{{schedule.schedule_id}}" {{ schedule.parent }}</p>
data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}"> {% else %}
</td> <p>Cron String:</p>
<td id="{{schedule.action}}" class="action"> <p>{{schedule.cron_string}}</p>
<button {% end %}
onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'" </td>
class="btn btn-info"> <td id="{{schedule.start_time}}">
<i class="fas fa-pencil-alt"></i> <p>{{schedule.next_run}}</p>
</button> </td>
<br> <td id="{{schedule.action}}" class="action">
<br> <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">
<button data-sch={{ schedule.schedule_id }} class="btn btn-danger del_button"> <i class="fas fa-pencil-alt"></i>
<i class="fas fa-trash" aria-hidden="true"></i> </button>
</button> <button data-sch={{ schedule.schedule_id }} class="btn btn-danger del_button">
</td> <i class="fas fa-trash" aria-hidden="true"></i>
</tr> </button>
{% end %} </td>
</tbody> </tr>
</table> {% end %}
<hr /> </tbody>
<table class="table table-hover d-block d-lg-none" id="mini_schedule_table" </table>
style="table-layout:fixed;" aria-describedby="Schedule List Mobile"> <hr />
<thead> </div>
<tr class="rounded"> <div class=" d-block d-lg-none">
<th style="width: 25%; min-width: 50px;">{{ translate('serverSchedules', 'action', data['lang']) <table class="table table-hover" id="mini_schedule_table" style="table-layout:fixed;" aria-describedby="Schedule List Mobile">
}}</th> <thead>
<th style="max-width: 40%; min-width: 50px;">{{ translate('serverSchedules', 'command', <tr class="rounded">
data['lang']) }}</th> <th style="width: 25%; min-width: 50px;">{{ translate('serverSchedules', 'action', data['lang'])
<th style="width: 10%; min-width: 50px;">{{ translate('serverSchedules', 'enabled', }}</th>
data['lang']) }}</th> <th style="max-width: 40%; min-width: 50px;">{{ translate('serverSchedules', 'command',
</tr> data['lang']) }}</th>
</thead> <th style="width: 10%; min-width: 50px;">{{ translate('serverSchedules', 'enabled',
<tbody> data['lang']) }}</th>
{% for schedule in data['schedules'] %} </tr>
<tr data-toggle="modal" data-target="#task_details_{{schedule.schedule_id}}"> </thead>
<td id="{{schedule.action}}" class="action"> <tbody>
<p>{{schedule.action}}</p> {% for schedule in data['schedules'] %}
</td> <tr data-toggle="modal" data-target="#task_details_{{schedule.schedule_id}}">
<td id="{{schedule.command}}" class="action" style="overflow: scroll; max-width: 30px;"> <td id="{{schedule.action}}" class="action">
<p style="overflow: scroll;">{{schedule.command}}</p> <p>{{schedule.action}}</p>
</td> </td>
<td id="{{schedule.enabled}}" class="action"> <td id="{{schedule.command}}" class="action" style="overflow: scroll; max-width: 30px;">
{% if schedule.enabled %} <p style="overflow: scroll;">{{schedule.command}}</p>
<span class="text-success"> </td>
<i class="fas fa-check-square"></i> {{ translate('serverSchedules', 'yes', data['lang']) }} <td id="{{schedule.enabled}}" class="enabled">
</span> <button type="button" class="btn btn-sm btn-info btn-toggle schedule-custom-toggle" id="schedule{{schedule.id}}" name="schedule{{schedule.id}}" data-schedule-id="{{schedule.schedule_id}}" data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}" data-toggle="button" aria-pressed="true" autocomplete="off">
{% else %} <div class="handle"></div>
<span class="text-danger"> </button>
<i class="far fa-times-square"></i> {{ translate('serverSchedules', 'no', data['lang']) }} </td>
</span> </tr>
{% end %} <!-- Modal -->
</td> <div class="modal fade" id="task_details_{{schedule.schedule_id}}" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
</tr> <div class="modal-dialog" role="document">
<!-- Modal --> <div class="modal-content">
<div class="modal fade" id="task_details_{{schedule.schedule_id}}" tabindex="-1" role="dialog" <div class="modal-header">
aria-labelledby="exampleModalLabel" aria-hidden="true"> <h5 class="modal-title" id="exampleModalLabel">{{ translate('serverSchedules', 'details',
<div class="modal-dialog" role="document"> data['lang']) }}</h5>
<div class="modal-content"> <button type="button" class="close" data-dismiss="modal" aria-label="Close">
<div class="modal-header"> <span aria-hidden="true">&times;</span>
<h5 class="modal-title" id="exampleModalLabel">{{ translate('serverSchedules', 'details', </button>
data['lang']) }}</h5> </div>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <div class="modal-body">
<span aria-hidden="true">&times;</span> <ul style="list-style: none;">
</button> <li id="{{schedule.schedule_id}}" class="id" style="border-top: .1em solid gray;">
</div> <h4>{{ translate('serverSchedules', 'name', data['lang']) }}</h4>
<div class="modal-body"> <p>{{schedule.schedule_id}}</p>
<ul style="list-style: none;"> </li>
<li id="{{schedule.schedule_id}}" class="id" style="border-top: .1em solid gray;"> <li id="{{schedule.action}}" class="action" style="border-top: .1em solid gray;">
<h4>{{ translate('serverSchedules', 'name', data['lang']) }}</h4> <h4>{{ translate('serverSchedules', 'action', data['lang']) }}</h4>
<p>{{schedule.schedule_id}}</p> <p>{{schedule.action}}</p>
</li> </li>
<li id="{{schedule.action}}" class="action" style="border-top: .1em solid gray;"> <li id="{{schedule.command}}" class="action" style="border-top: .1em solid gray;">
<h4>{{ translate('serverSchedules', 'action', data['lang']) }}</h4> <h4>{{ translate('serverSchedules', 'command', data['lang']) }}</h4>
<p>{{schedule.action}}</p> <p>{{schedule.command}}</p>
</li> </li>
<li id="{{schedule.command}}" class="action" style="border-top: .1em solid gray;"> <li id="{{schedule.interval}}" class="action" style="border-top: .1em solid gray;">
<h4>{{ translate('serverSchedules', 'command', data['lang']) }}</h4> {% if schedule.interval != '' %}
<p>{{schedule.command}}</p> <h4>{{ translate('serverSchedules', 'interval', data['lang']) }}</h4>
</li> <p>{{ translate('serverSchedules', 'every', data['lang']) }} {{schedule.interval}}
<li id="{{schedule.interval}}" class="action" style="border-top: .1em solid gray;"> {{schedule.interval_type}}</p>
{% if schedule.interval != '' %} {% elif schedule.interval_type == 'reaction' %}
<h4>{{ translate('serverSchedules', 'interval', data['lang']) }}</h4> <h4>{{ translate('serverSchedules', 'interval', data['lang']) }}</h4>
<p>{{ translate('serverSchedules', 'every', data['lang']) }} {{schedule.interval}} <p>{{schedule.interval_type}}<br><br>{{ translate('serverSchedules', 'child',
{{schedule.interval_type}}</p> data['lang']) }}: {{ schedule.parent }}</p>
{% elif schedule.interval_type == 'reaction' %} {% else %}
<h4>{{ translate('serverSchedules', 'interval', data['lang']) }}</h4> <h4>{{ translate('serverSchedules', 'interval', data['lang']) }}</h4>
<p>{{schedule.interval_type}}<br><br>{{ translate('serverSchedules', 'child', <p>{{ translate('serverSchedules', 'cron', data['lang']) }}: {{schedule.cron_string}}
data['lang']) }}: {{ schedule.parent }}</p> </p>
{% else %} {% end %}
<h4>{{ translate('serverSchedules', 'interval', data['lang']) }}</h4> </li>
<p>{{ translate('serverSchedules', 'cron', data['lang']) }}: {{schedule.cron_string}} <li id="{{schedule.start_time}}" class="action" style="border-top: .1em solid gray;">
</p> <h4>{{ translate('serverSchedules', 'nextRun', data['lang']) }}</h4>
{% end %} {% if schedule.next_run %}
</li> <p>{{schedule.next_run}}</p>
<li id="{{schedule.start_time}}" class="action" style="border-top: .1em solid gray;"> {% else %}
<h4>{{ translate('serverSchedules', 'nextRun', data['lang']) }}</h4> <p>zzzzzzz</p>
{% if schedule.next_run %} {% end %}
<p>{{schedule.next_run}}</p> </li>
{% else %} <li id="{{schedule.enabled}}" class="action" style="border-top: .1em solid gray; border-bottom: .1em solid gray">
<p>zzzzzzz</p> <h4>{{ translate('serverSchedules', 'enabled', data['lang']) }}</h4>
{% end %} <input type="checkbox" class="schedule-enabled-toggle" data-schedule-id="{{schedule.schedule_id}}" data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}">
</li> </li>
<li id="{{schedule.enabled}}" class="action" </ul>
style="border-top: .1em solid gray; border-bottom: .1em solid gray"> </div>
<h4>{{ translate('serverSchedules', 'enabled', data['lang']) }}</h4> <div class="modal-footer">
<input type="checkbox" class="schedule-enabled-toggle" <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">
data-schedule-id="{{schedule.schedule_id}}" <i class="fas fa-pencil-alt"></i> {{ translate('serverSchedules', 'edit', data['lang'])
data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}"> }}
</li> </button>
</ul> <button data-sch={{ schedule.schedule_id }} class="btn btn-danger del_button">
</div> <i class="fas fa-trash" aria-hidden="true"></i> {{ translate('serverSchedules',
<div class="modal-footer"> 'delete', data['lang']) }}
<button </button>
onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'" <button type="button" class="btn btn-secondary" data-dismiss="modal">{{
class="btn btn-info"> translate('serverSchedules', 'close', data['lang']) }}</button>
<i class="fas fa-pencil-alt"></i> {{ translate('serverSchedules', 'edit', data['lang']) </div>
}}
</button>
<button data-sch={{ schedule.schedule_id }} class="btn btn-danger del_button">
<i class="fas fa-trash" aria-hidden="true"></i> {{ translate('serverSchedules',
'delete', data['lang']) }}
</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{
translate('serverSchedules', 'close', data['lang']) }}</button>
</div> </div>
</div> </div>
</div> </div>
</div> {% end %}
{% end %} </tbody>
</tbody> </table>
</table> </div>
{% end %}
</div> </div>
</div> </div>
</div> </div>
@ -265,6 +251,16 @@
.toggle { .toggle {
height: 0px !important; height: 0px !important;
} }
td.enabled {
vertical-align: middle;
border-collapse: collapse !important;
}
.enabled .toggle-group .btn {
vertical-align: middle;
cursor: pointer;
}
</style> </style>
@ -299,20 +295,21 @@
}; };
} }
$(() => { $(document).ready(function () {
$('.schedule-enabled-toggle').bootstrapToggle({ $('.schedule-custom-toggle').each(function () {
on: 'Yes',
off: 'No',
onstyle: 'success',
offstyle: 'danger',
})
$('.schedule-enabled-toggle').each(function () {
const enabled = JSON.parse(this.getAttribute('data-schedule-enabled')); const enabled = JSON.parse(this.getAttribute('data-schedule-enabled'));
$(this).bootstrapToggle(enabled ? 'on' : 'off') if (enabled) {
this.classList.add("active");
}
else {
this.classList.remove("active");
}
}) })
$('.schedule-enabled-toggle').change(function () { });
$(() => {
$('.schedule-custom-toggle').click(function () {
const id = this.getAttribute('data-schedule-id'); const id = this.getAttribute('data-schedule-id');
const enabled = this.checked; const enabled = !JSON.parse(this.getAttribute('data-schedule-enabled'));
fetch(`/api/v2/servers/{{data['server_id']}}/tasks/${id}`, { fetch(`/api/v2/servers/{{data['server_id']}}/tasks/${id}`, {
method: 'PATCH', method: 'PATCH',

View File

@ -46,104 +46,107 @@
<div class="card-header header-sm d-flex justify-content-between align-items-center"> <div class="card-header header-sm d-flex justify-content-between align-items-center">
<h4 class="card-title"><i class="fa-regular fa-bell"></i> {{ translate('webhooks', 'webhooks', data['lang']) }} </h4> <h4 class="card-title"><i class="fa-regular fa-bell"></i> {{ translate('webhooks', 'webhooks', data['lang']) }} </h4>
{% if data['user_data']['hints'] %} {% if data['user_data']['hints'] %}
<span class="too_small" title="{{ translate('serverSchedules', 'cannotSee', data['lang']) }}" , <span class="too_small" title="{{ translate('serverSchedules', 'cannotSee', data['lang']) }}" , data-content="{{ translate('serverSchedules', 'cannotSeeOnMobile', data['lang']) }}" , data-placement="bottom"></span>
data-content="{{ translate('serverSchedules', 'cannotSeeOnMobile', data['lang']) }}" ,
data-placement="bottom"></span>
{% end %} {% end %}
<div><button <div><a class="btn btn-info" href="/panel/add_webhook?id={{ data['server_stats']['server_id']['server_id'] }}"><i class="fas fa-plus-circle"></i> {{ translate('webhooks', 'new', data['lang']) }}</a></div>
onclick="location.href=`/panel/add_webhook?id={{ data['server_stats']['server_id']['server_id'] }}`"
class="btn btn-info">{{ translate('webhooks', 'new', data['lang']) }}<i
class="fas fa-pencil-alt"></i></button></div>
</div> </div>
<div class="card-body"> <div class="card-body">
<table class="table table-hover d-none d-lg-block responsive-table" aria-label="webhooks list" id="webhook_table" width="100%" style="table-layout:fixed;"> {% if len(data['webhooks']) == 0 %}
<thead> <div style="text-align: center; color: grey;">
<tr class="rounded"> <h7>{{ translate('webhooks', 'no-webhook', data['lang']) }} <strong>{{ translate('webhooks', 'newWebhook',data['lang']) }}</strong>.</h7>
<th style="width: 10%; min-width: 10px;">{{ translate('webhooks', 'name', data['lang']) }} </div>
</th> {% end %}
<th style="width: 20%; min-width: 50px;">{{ translate('webhooks', 'type', data['lang']) }}</th> {% if len(data['webhooks']) > 0 %}
<th style="width: 50%; min-width: 50px;">{{ translate('webhooks', 'trigger', data['lang']) }}</th> <div class="d-none d-lg-block">
<th style="width: 10%; min-width: 50px;">{{ translate('webhooks', 'enabled', <table class="table table-hover responsive-table" aria-label="webhooks list" id="webhook_table" width="100%" style="table-layout:fixed;">
data['lang']) }}</th> <thead>
<th style="width: 10%; min-width: 50px;">{{ translate('webhooks', 'edit', data['lang']) <tr class="rounded">
}}</th> <th scope="col" style="width: 5%; min-width: 64px;">{{ translate('webhooks', 'enabled', data['lang']) }}</th>
</tr> <th scope="col" style="width: 15%; min-width: 10px;">{{ translate('webhooks', 'name', data['lang']) }} </th>
</thead> <th scope="col" style="width: 20%; min-width: 50px;">{{ translate('webhooks', 'type', data['lang']) }}</th>
<tbody> <th scope="col" style="width: 50%; min-width: 50px;">{{ translate('webhooks', 'trigger', data['lang']) }}</th>
{% for webhook in data['webhooks'] %} <th scope="col" style="width: 10%; min-width: 50px;">{{ translate('webhooks', 'edit', data['lang']) }}</th>
<tr> </tr>
<td id="{{webhook.name}}" class="id"> </thead>
<p>{{webhook.name}}</p> <tbody>
</td> {% for webhook in data['webhooks'] %}
<td id="{{webhook.webhook_type}}" class="type"> <tr>
<p>{{webhook.webhook_type}}</p> <td id="{{webhook.enabled}}" class="enabled">
</td> <button type="button" class="btn btn-sm btn-info btn-toggle webhook-custom-toggle" id="webhook_{{webhook.id}}" name="webhook_{{webhook.id}}" data-webhook-id="{{webhook.id}}" data-webhook-enabled="{{ 'true' if webhook.enabled else 'false' }}" data-toggle="button" aria-pressed="true" autocomplete="off">
<td id="{{webhook.trigger}}" class="trigger" style="overflow: scroll; max-width: 30px;"> <div class="handle"></div>
<ul> </button>
{% for trigger in webhook.trigger.split(",") %} </td>
{% if trigger in data["triggers"] %} <td id="{{webhook.name}}" class="id">
<li>{{translate('webhooks', trigger , data['lang'])}}</li> <p>{{webhook.name}}</p>
{%end%} </td>
{%end%} <td id="{{webhook.webhook_type}}" class="type">
</ul> <p>{{webhook.webhook_type}}</p>
</td> </td>
<td id="{{webhook.enabled}}" class="enabled"> <td id="{{webhook.trigger}}" class="trigger" style="overflow: scroll; max-width: 30px;">
<input style="width: 10px !important;" type="checkbox" class="webhook-enabled-toggle" data-webhook-id="{{webhook.id}}" data-webhook-enabled="{{ 'true' if webhook.enabled else 'false' }}"> <ul>
</td> {% for trigger in webhook.trigger.split(",") %}
<td id="webhook_edit" class="action"> {% if trigger in data["triggers"] %}
<button onclick="window.location.href='/panel/webhook_edit?id={{ data['server_stats']['server_id']['server_id'] }}&webhook_id={{webhook.id}}'" class="btn btn-info"> <li>{{translate('webhooks', trigger , data['lang'])}}</li>
<i class="fas fa-pencil-alt"></i> {%end%}
</button> {%end%}
<br> </ul>
<br> </td>
<button data-webhook={{ webhook.id }} class="btn btn-danger del_button"> <td id="webhook_edit" class="action">
<i class="fas fa-trash" aria-hidden="true"></i> <button onclick="window.location.href=`/panel/webhook_edit?id={{ data['server_stats']['server_id']['server_id'] }}&webhook_id={{webhook.id}}`" class="btn btn-info">
</button> <i class="fas fa-pencil-alt"></i>
<button data-webhook={{ webhook.id }} data-toggle="tooltip" title="{{ translate('webhooks', 'run', data['lang']) }}" class="btn btn-outline-warning test-socket"> </button>
<i class="fa-solid fa-vial"></i> <button data-webhook={{ webhook.id }} class="btn btn-danger del_button">
</button> <i class="fas fa-trash" aria-hidden="true"></i>
</td> </button>
</tr> <button data-webhook={{ webhook.id }} data-toggle="tooltip" title="{{ translate('webhooks', 'run', data['lang']) }}" class="btn btn-outline-warning test-socket">
{% end %} <i class="fa-solid fa-vial"></i>
</tbody> </button>
</table> </td>
<table aria-label="webhooks list" class="table table-hover d-block d-lg-none responsive-table" id="webhook_table_mini" width="100%" style="table-layout:fixed;"> </tr>
<thead> {% end %}
<tr class="rounded"> </tbody>
<th style="width: 33.33%; min-width: 10px;">Name </table>
</th> </div>
<th style="width: 33.33%; min-width: 50px;">{{ translate('webhooks', 'enabled', <div class="d-block d-lg-none">
data['lang']) }}</th> <table aria-label="webhooks list" class="table table-hover responsive-table" id="webhook_table_mini" width="100%" style="table-layout:fixed;">
<th style="width: 33.33%; min-width: 50px;">{{ translate('webhooks', 'edit', data['lang']) <thead>
}}</th> <tr class="rounded">
</tr> <th style="width: 20%; min-width: 64px;">{{ translate('webhooks', 'enabled',
</thead> data['lang']) }}</th>
<tbody> <th style="width: 40%; min-width: 10px;">Name
{% for webhook in data['webhooks'] %} </th>
<tr> <th style="width: 40%; min-width: 50px;">{{ translate('webhooks', 'edit', data['lang'])
<td id="{{webhook.name}}" class="id"> }}</th>
<p>{{webhook.name}}</p> </tr>
</td> </thead>
<td id="{{webhook.enabled}}" class="enabled"> <tbody>
<input style="width: 10px !important;" type="checkbox" class="webhook-enabled-toggle" data-webhook-id="{{webhook.id}}" data-webhook-enabled="{{ 'true' if webhook.enabled else 'false' }}"> {% for webhook in data['webhooks'] %}
</td> <tr>
<td id="webhook_edit" class="action"> <td id="{{webhook.enabled}}" class="enabled">
<button onclick="window.location.href='/panel/webhook_edit?id={{ data['server_stats']['server_id']['server_id'] }}&webhook_id={{webhook.id}}'" class="btn btn-info"> <button type="button" class="btn btn-sm btn-info btn-toggle webhook-custom-toggle" id="webhook_{{webhook.id}}" name="webhook_{{webhook.id}}" data-webhook-id="{{webhook.id}}" data-webhook-enabled="{{ 'true' if webhook.enabled else 'false' }}" data-toggle="button" aria-pressed="true" autocomplete="off">
<i class="fas fa-pencil-alt"></i> <div class="handle"></div>
</button> </button>
<br> </td>
<br> <td id="{{webhook.name}}" class="id">
<button data-webhook={{ webhook.id }} class="btn btn-danger del_button"> <p>{{webhook.name}}</p>
<i class="fas fa-trash" aria-hidden="true"></i> </td>
</button> <td id="webhook_edit" class="action">
<button data-webhook={{ webhook.id }} data-toggle="tooltip" title="{{ translate('webhooks', 'run', data['lang']) }}" class="btn btn-outline-warning test-socket"> <button onclick="window.location.href=`/panel/webhook_edit?id={{ data['server_stats']['server_id']['server_id'] }}&webhook_id={{webhook.id}}`" class="btn btn-info">
<i class="fa-solid fa-vial"></i> <i class="fas fa-pencil-alt"></i>
</button> </button>
</td> <button data-webhook={{ webhook.id }} class="btn btn-danger del_button">
</tr> <i class="fas fa-trash" aria-hidden="true"></i>
{% end %} </button>
</tbody> <button data-webhook={{ webhook.id }} data-toggle="tooltip" title="{{ translate('webhooks', 'run', data['lang']) }}" class="btn btn-outline-warning test-socket">
</table> <i class="fa-solid fa-vial"></i>
</button>
</td>
</tr>
{% end %}
</tbody>
</table>
</div>
{% end %}
</div> </div>
</div> </div>
</div> </div>
@ -170,6 +173,16 @@
.toggle { .toggle {
height: 0px !important; height: 0px !important;
} }
td.enabled {
vertical-align: middle;
border-collapse: collapse !important;
}
.enabled .toggle-group .btn {
vertical-align: middle;
cursor: pointer;
}
</style> </style>
@ -195,16 +208,12 @@
{% block js %} {% block js %}
<script> <script>
$(document).ready(function () { $(document).ready(function () {
console.log('ready for JS!') console.log('ready for JS!')
$('#webhook_table').DataTable({ $('#webhook_table').DataTable({
'order': [4, 'asc'], 'order': [4, 'asc'],
} }
); );
});
$(document).ready(function () {
console.log('ready for JS!')
$('#webhook_table_mini').DataTable({ $('#webhook_table_mini').DataTable({
'order': [2, 'asc'] 'order': [2, 'asc']
} }
@ -247,20 +256,21 @@
}; };
} }
$(() => { $(document).ready(function () {
$('.webhook-enabled-toggle').bootstrapToggle({ $('.webhook-custom-toggle').each(function () {
on: 'Yes',
off: 'No',
onstyle: 'success',
offstyle: 'danger',
})
$('.webhook-enabled-toggle').each(function () {
const enabled = JSON.parse(this.getAttribute('data-webhook-enabled')); const enabled = JSON.parse(this.getAttribute('data-webhook-enabled'));
$(this).bootstrapToggle(enabled ? 'on' : 'off') if (enabled) {
this.classList.add("active");
}
else {
this.classList.remove("active");
}
}) })
$('.webhook-enabled-toggle').change(function () { });
$(() => {
$('.webhook-custom-toggle').click(function () {
const id = this.getAttribute('data-webhook-id'); const id = this.getAttribute('data-webhook-id');
const enabled = this.checked; const enabled = !JSON.parse(this.getAttribute('data-webhook-enabled'));
fetch(`/api/v2/servers/{{data['server_id']}}/webhook/${id}`, { fetch(`/api/v2/servers/{{data['server_id']}}/webhook/${id}`, {
method: 'PATCH', method: 'PATCH',
@ -296,12 +306,12 @@
message: "{{ translate('webhooks', 'areYouSureDel', data['lang']) }}", message: "{{ translate('webhooks', 'areYouSureDel', data['lang']) }}",
buttons: { buttons: {
cancel: { cancel: {
label: '<i class="fas fa-times"></i> {{ translate("serverSchedules", "cancel", data['lang']) }}' label: '<i class="fas fa-times"></i> {{ translate("serverSchedules", "cancel", data["lang"]) }}'
}, },
confirm: { confirm: {
className: 'btn-outline-danger', className: 'btn-outline-danger',
label: '<i class="fas fa-check"></i> {{ translate("serverSchedules", "confirm", data['lang']) }}' label: '<i class="fas fa-check"></i> {{ translate("serverSchedules", "confirm", data["lang"]) }}'
} }
}, },
callback: function (result) { callback: function (result) {
console.log(result); console.log(result);
@ -319,12 +329,12 @@
message: "{{ translate('webhooks', 'areYouSureRun', data['lang']) }}", message: "{{ translate('webhooks', 'areYouSureRun', data['lang']) }}",
buttons: { buttons: {
cancel: { cancel: {
label: '<i class="fas fa-times"></i> {{ translate("serverSchedules", "cancel", data['lang']) }}' label: '<i class="fas fa-times"></i> {{ translate("serverSchedules", "cancel", data["lang"]) }}'
}, },
confirm: { confirm: {
className: 'btn-outline-danger', className: 'btn-outline-danger',
label: '<i class="fas fa-check"></i> {{ translate("serverSchedules", "confirm", data['lang']) }}' label: '<i class="fas fa-check"></i> {{ translate("serverSchedules", "confirm", data["lang"]) }}'
} }
}, },
callback: function (result) { callback: function (result) {
console.log(result); console.log(result);
@ -346,12 +356,12 @@
let responseData = await res.json(); let responseData = await res.json();
if (responseData.status === "ok") { if (responseData.status === "ok") {
bootbox.alert("Webhook Sent!") bootbox.alert("Webhook Sent!")
}else{ } else {
console.log(responseData); console.log(responseData);
bootbox.alert({ bootbox.alert({
title: responseData.status, title: responseData.status,
message: responseData.error message: responseData.error
}); });
} }
} }
@ -367,11 +377,11 @@
let responseData = await res.json(); let responseData = await res.json();
if (responseData.status === "ok") { if (responseData.status === "ok") {
window.location.reload(); window.location.reload();
}else{ } else {
bootbox.alert({ bootbox.alert({
title: responseData.status, title: responseData.status,
message: responseData.error message: responseData.error
}); });
} }
} }

View File

@ -499,8 +499,10 @@
"every": "Jede", "every": "Jede",
"interval": "Intervall", "interval": "Intervall",
"name": "Name", "name": "Name",
"newSchedule": "Neuer Zeitplan",
"nextRun": "Nächster Durchlauf", "nextRun": "Nächster Durchlauf",
"no": "Nein", "no": "Nein",
"no-schedule": "Derzeit gibt es keine Zeitpläne für diesen Server. Hier kann einer angelegt werden",
"scheduledTasks": "Geplante Aufgaben", "scheduledTasks": "Geplante Aufgaben",
"yes": "Ja" "yes": "Ja"
}, },
@ -642,6 +644,8 @@
"kill": "Server Prozess abgebrochen", "kill": "Server Prozess abgebrochen",
"name": "Name", "name": "Name",
"new": "Neuer Webhook", "new": "Neuer Webhook",
"newWebhook": "Neuer Webhook",
"no-webhook": "Derzeit gibt es keine Webhooks für diesen Server. Hier kann einer angelegt werden",
"run": "Webhook-Test ausführen", "run": "Webhook-Test ausführen",
"send_command": "Befehl für den Server empfangen", "send_command": "Befehl für den Server empfangen",
"start_server": "Server gestartet", "start_server": "Server gestartet",

View File

@ -499,8 +499,10 @@
"every": "Every", "every": "Every",
"interval": "Interval", "interval": "Interval",
"name": "Name", "name": "Name",
"newSchedule": "New Schedule",
"nextRun": "Next Run", "nextRun": "Next Run",
"no": "No", "no": "No",
"no-schedule": "There are currently no schedules for this server. To get started, click",
"scheduledTasks": "Scheduled Tasks", "scheduledTasks": "Scheduled Tasks",
"yes": "Yes" "yes": "Yes"
}, },
@ -641,6 +643,8 @@
"kill": "Server Killed", "kill": "Server Killed",
"name": "Name", "name": "Name",
"new": "New Webhook", "new": "New Webhook",
"newWebhook": "New Webhook",
"no-webhook": "There are currently no webhooks for this server. To get started, click",
"run": "Test Run Webhook", "run": "Test Run Webhook",
"send_command": "Server Command Received", "send_command": "Server Command Received",
"start_server": "Server Started", "start_server": "Server Started",

View File

@ -90,8 +90,8 @@
"delay-explained": "El agente/servicio inicio recientemente y está retrasando el inicio de la instancia del servidor de Minecraft.", "delay-explained": "El agente/servicio inicio recientemente y está retrasando el inicio de la instancia del servidor de Minecraft.",
"host": "Host", "host": "Host",
"installing": "Instalando...", "installing": "Instalando...",
"kill": "Matar Proceso", "kill": "Detener Proceso",
"killing": "Cerrando el proceso...", "killing": "Deteniendo el proceso...",
"lastBackup": "Último:", "lastBackup": "Último:",
"max": "Máx", "max": "Máx",
"memUsage": "Uso de memoria", "memUsage": "Uso de memoria",
@ -217,7 +217,8 @@
"forgotPassword": "Olvidé mi contraseña", "forgotPassword": "Olvidé mi contraseña",
"login": "Iniciar Sesión", "login": "Iniciar Sesión",
"password": "Contraseña", "password": "Contraseña",
"username": "Usuario" "username": "Usuario",
"viewStatus": "View Public Status Page"
}, },
"notify": { "notify": {
"activityLog": "Registros de actividad", "activityLog": "Registros de actividad",
@ -240,12 +241,14 @@
"assignedRoles": "Grupos asignados", "assignedRoles": "Grupos asignados",
"cancel": "Cancelar", "cancel": "Cancelar",
"clearComms": "Limpiar comandos sin ejecutar.", "clearComms": "Limpiar comandos sin ejecutar.",
"custom": "Personalizar Crafty",
"delete": "Eliminar", "delete": "Eliminar",
"edit": "Editar", "edit": "Editar",
"enableLang": "Activar todos los Idiomas", "enableLang": "Activar todos los Idiomas",
"enabled": "Habilitado", "enabled": "Habilitado",
"globalExplain": "Donde Crafty almacena todos los archivos de tu servidor. (Juntaremos la ruta con /servers/[uuid de servidor])", "globalExplain": "Donde Crafty almacena todos los archivos de tu servidor. (Juntaremos la ruta con /servers/[uuid de servidor])",
"globalServer": "Directorio Global de Servidores", "globalServer": "Directorio Global de Servidores",
"json": "Config.json",
"match": "Las contraseñas deben coincidir", "match": "Las contraseñas deben coincidir",
"newRole": "Agregar nuevo Grupo", "newRole": "Agregar nuevo Grupo",
"newUser": "Agregar nuevo Usuario", "newUser": "Agregar nuevo Usuario",
@ -282,6 +285,7 @@
"roleTitle": "Configuración de Grupos", "roleTitle": "Configuración de Grupos",
"roleUserName": "Nombre de usuario", "roleUserName": "Nombre de usuario",
"roleUsers": "Usuarios del grupo: ", "roleUsers": "Usuarios del grupo: ",
"selectManager": "Seleccionar un administrador para este rol",
"serverAccess": "¿Acceso?", "serverAccess": "¿Acceso?",
"serverName": "Nombre del servidor", "serverName": "Nombre del servidor",
"serversDesc": "Servidores a los que este grupo puede acceder" "serversDesc": "Servidores a los que este grupo puede acceder"
@ -495,8 +499,10 @@
"every": "Cada", "every": "Cada",
"interval": "Intervalo", "interval": "Intervalo",
"name": "Nombre", "name": "Nombre",
"newSchedule": "Nueva Tarea programada",
"nextRun": "Siguiente ejecución", "nextRun": "Siguiente ejecución",
"no": "No", "no": "No",
"no-schedule": "Actualmente no hay programaciones para este servidor. Para comenzar, haz clic en",
"scheduledTasks": "Tareas programadas", "scheduledTasks": "Tareas programadas",
"yes": "Sí" "yes": "Sí"
}, },
@ -521,6 +527,7 @@
"commandInput": "Introducir tu comando", "commandInput": "Introducir tu comando",
"delay-explained": "El agente/servicio se inicio recientemente y está retrasando iniciar la instancia del servidor de Minecraft.", "delay-explained": "El agente/servicio se inicio recientemente y está retrasando iniciar la instancia del servidor de Minecraft.",
"downloading": "Descargando...", "downloading": "Descargando...",
"importing": "Importando...",
"installing": "Instalando...", "installing": "Instalando...",
"restart": "Reiniciar", "restart": "Reiniciar",
"sendCommand": "Enviar comando", "sendCommand": "Enviar comando",
@ -557,6 +564,7 @@
"save": "Guardar", "save": "Guardar",
"selectRole": "Seleccionar Grupo(s)", "selectRole": "Seleccionar Grupo(s)",
"selectRoot": "Seleccione el directorio raíz del archivo.", "selectRoot": "Seleccione el directorio raíz del archivo.",
"selectServer": "Seleccionar un servidor",
"selectType": "Tipo de servidor (Vanilla, Modificado, Mods, etc.)", "selectType": "Tipo de servidor (Vanilla, Modificado, Mods, etc.)",
"selectVersion": "Selecciona una versión", "selectVersion": "Selecciona una versión",
"selectZipDir": "Seleccione el directorio del archivo que quiere extraer el contenido.", "selectZipDir": "Seleccione el directorio del archivo que quiere extraer el contenido.",
@ -564,6 +572,7 @@
"serverName": "Nombre del servidor", "serverName": "Nombre del servidor",
"serverPath": "Ruta del servidor", "serverPath": "Ruta del servidor",
"serverPort": "Puerto del servidor", "serverPort": "Puerto del servidor",
"serverSelect": "Selección de servidor",
"serverType": "Tipo de servidor", "serverType": "Tipo de servidor",
"serverUpload": "Subir servidor comprimido", "serverUpload": "Subir servidor comprimido",
"serverVersion": "Versión del servidor", "serverVersion": "Versión del servidor",
@ -621,5 +630,30 @@
"userSettings": "Configuración de Usuario.", "userSettings": "Configuración de Usuario.",
"userTheme": "Tema de Interfaz", "userTheme": "Tema de Interfaz",
"uses": "Número de usos permitidos. (Sin límite: -1)" "uses": "Número de usos permitidos. (Sin límite: -1)"
},
"webhooks": {
"areYouSureDel": "¿Estás seguro de que quieres eliminar este webhook?",
"areYouSureRun": "¿Estás seguro de que quieres probar este webhook?",
"backup_server": "Copia de seguridad del servidor completada",
"bot_name": "Nombre del bot",
"color": "Seleccionar color de resaltado",
"crash_detected": "Server Crashed",
"edit": "Editar",
"enabled": "Habilitado",
"jar_update": "Ejecutable del Servidor actualizado",
"kill": "Servidor detenido",
"name": "Nombre",
"new": "Nuevo Webhook",
"newWebhook": "Nuevo Webhook",
"no-webhook": "Actualmente no hay webhooks para este servidor. Para comenzar, haz click en",
"run": "Ejecutar prueba de Webhook",
"send_command": "Comando de servidor recibido",
"start_server": "Servidor iniciado",
"stop_server": "Servidor detenido",
"trigger": "Trigger",
"type": "Tipo de Webhook",
"url": "URL de Webhook",
"webhook_body": "Cuerpo del Webhook",
"webhooks": "Webhooks"
} }
} }

View File

@ -499,8 +499,10 @@
"every": "Toutes", "every": "Toutes",
"interval": "Intervalle", "interval": "Intervalle",
"name": "Nom", "name": "Nom",
"newSchedule": "Nouvelle Tâche",
"nextRun": "Exécution suivante", "nextRun": "Exécution suivante",
"no": "Non", "no": "Non",
"no-schedule": "Il n'y a actuellement aucune tâche pour ce serveur. Pour commencer, clicke sur ",
"scheduledTasks": "Tâches Planifiées", "scheduledTasks": "Tâches Planifiées",
"yes": "Oui" "yes": "Oui"
}, },
@ -642,6 +644,8 @@
"kill": "Serveur Interrompu", "kill": "Serveur Interrompu",
"name": "Nom", "name": "Nom",
"new": "Nouveau Webhook", "new": "Nouveau Webhook",
"newWebhook": "Nouveau Webhook",
"no-webhook": "Il n'y a actuellement aucun webhook pour ce serveur. Pour commecner, clicke sur ",
"run": "Test l'exécution du Webhook", "run": "Test l'exécution du Webhook",
"send_command": "Commande du Serveur reçue", "send_command": "Commande du Serveur reçue",
"start_server": "Le serveur a démarré", "start_server": "Le serveur a démarré",

View File

@ -499,8 +499,10 @@
"every": "EVERYZ", "every": "EVERYZ",
"interval": "GAPZ", "interval": "GAPZ",
"name": "NAMZ", "name": "NAMZ",
"newSchedule": "NU SCHEDULE",
"nextRun": "NEXT RUNZ", "nextRun": "NEXT RUNZ",
"no": "NOPE", "no": "NOPE",
"no-schedule": "THER BE NO SCHEDULEZ FOR DIS SERVER RIGHT MEOW. 2 GET STARTD, BOOP",
"scheduledTasks": "SCHEDULED TASKZ", "scheduledTasks": "SCHEDULED TASKZ",
"yes": "YESH" "yes": "YESH"
}, },
@ -642,6 +644,8 @@
"kill": "SERVR GO BYE BYE", "kill": "SERVR GO BYE BYE",
"name": "NAMZ", "name": "NAMZ",
"new": "NU WEBHOOK", "new": "NU WEBHOOK",
"newWebhook": "NU WEBHOOK",
"no-webhook": "THER BE NO WEBHOOKZ FOR DIS SERVER RIGHT MEOW. 2 GET STARTD, BOOP",
"run": "TESTZ RUN WEBHOOK", "run": "TESTZ RUN WEBHOOK",
"send_command": "SERVR GOT COMMANDZ", "send_command": "SERVR GOT COMMANDZ",
"start_server": "SERVR WOKE UP", "start_server": "SERVR WOKE UP",

View File

@ -500,8 +500,10 @@
"every": "Katru", "every": "Katru",
"interval": "Intervāls", "interval": "Intervāls",
"name": "Nosaukums", "name": "Nosaukums",
"newSchedule": "Jauns Grafiks",
"nextRun": "Nākamā Izpilde", "nextRun": "Nākamā Izpilde",
"no": "Nē", "no": "Nē",
"no-schedule": "Pašlaik šim serverim nav grafiku. Lai sāktu, spied",
"scheduledTasks": "Ieplānotie Notikumi", "scheduledTasks": "Ieplānotie Notikumi",
"yes": "Jā" "yes": "Jā"
}, },
@ -643,6 +645,8 @@
"kill": "Serveris Izbeigts", "kill": "Serveris Izbeigts",
"name": "Nosaukums", "name": "Nosaukums",
"new": "Jauns Webhook", "new": "Jauns Webhook",
"newWebhook": "Jauns Webhooks",
"no-webhook": "Pašlaik šim serverim nav webhooki. Lai saktu, spied",
"run": "Testēt Webhook", "run": "Testēt Webhook",
"send_command": "Servera Komanda Saņemta", "send_command": "Servera Komanda Saņemta",
"start_server": "Serveris Startēts", "start_server": "Serveris Startēts",

View File

@ -499,8 +499,10 @@
"every": "Elke", "every": "Elke",
"interval": "Interval", "interval": "Interval",
"name": "Naam", "name": "Naam",
"newSchedule": "Nieuw schema",
"nextRun": "Volgende uitvoering", "nextRun": "Volgende uitvoering",
"no": "Nee", "no": "Nee",
"no-schedule": "Er zijn momenteel geen schema's voor deze server. Klik om te beginnen op",
"scheduledTasks": "Geplande taken", "scheduledTasks": "Geplande taken",
"yes": "Ja" "yes": "Ja"
}, },
@ -642,6 +644,8 @@
"kill": "Server gedood", "kill": "Server gedood",
"name": "Naam", "name": "Naam",
"new": "Nieuwe webhook", "new": "Nieuwe webhook",
"newWebhook": "Nieuwe webhook",
"no-webhook": "Er zijn momenteel geen webhooks voor deze server. Klik om te beginnen op",
"run": "Webhook testen", "run": "Webhook testen",
"send_command": "Serveropdracht ontvangen", "send_command": "Serveropdracht ontvangen",
"start_server": "Server gestart", "start_server": "Server gestart",

View File

@ -12,8 +12,8 @@
}, },
"apiKeys": { "apiKeys": {
"apiKeys": "Klucze API", "apiKeys": "Klucze API",
"auth": "Authorized? ", "auth": "Zezwól? ",
"buttons": "Przyciski", "buttons": "Akcje",
"config": "Config", "config": "Config",
"crafty": "Crafty: ", "crafty": "Crafty: ",
"createNew": "Stwórz nowy klucz API", "createNew": "Stwórz nowy klucz API",
@ -48,7 +48,7 @@
"subscriptionLevel": "Poziom", "subscriptionLevel": "Poziom",
"supportTeam": "Pomoc i Drużyna Dokumentacji", "supportTeam": "Pomoc i Drużyna Dokumentacji",
"thankYou": "DZIĘKUJEMY WAM", "thankYou": "DZIĘKUJEMY WAM",
"translationDesc": "dla naszej społeczności która tłumaczy!", "translationDesc": "dla naszej społeczności która tłumaczy! [ Aktywnie tłumaczy = 🟢 Tłumaczył = ⚪ ]",
"translationName": "Nazwa", "translationName": "Nazwa",
"translationTitle": "Język tłumaczenia", "translationTitle": "Język tłumaczenia",
"translator": "Tłumacze" "translator": "Tłumacze"
@ -143,11 +143,11 @@
}, },
"decimal": "", "decimal": "",
"emptyTable": "Brak danych w tej tabeli danych", "emptyTable": "Brak danych w tej tabeli danych",
"info": "Pokazywanie _START_ to _END_ of _TOTAL_ wejść", "info": "Pokazywanie od _START_ do _END_ z _TOTAL_ wszystkich wejść",
"infoEmpty": "Pokazywanie 0 do 0 z 0 wejść", "infoEmpty": "Pokazywanie 0 do 0 z 0 wejść",
"infoFiltered": "(filtered from _MAX_ total entries)", "infoFiltered": "(Pokazuje z _MAX_ wejść)",
"infoPostFix": "", "infoPostFix": "",
"lengthMenu": "Pokazuj _MENU_ entries", "lengthMenu": "Pokazuj _MENU_ wejść",
"loadingRecords": "Wczytywanie...", "loadingRecords": "Wczytywanie...",
"paginate": { "paginate": {
"first": "Pierwsze", "first": "Pierwsze",
@ -310,9 +310,9 @@
"excludedChoose": "Wybierz ścieżki do wykluczenia z backupu", "excludedChoose": "Wybierz ścieżki do wykluczenia z backupu",
"exclusionsTitle": "Wykluczenia backupu", "exclusionsTitle": "Wykluczenia backupu",
"maxBackups": "Maks. Backupów", "maxBackups": "Maks. Backupów",
"maxBackupsDesc": "Crafty nie będzie zbierał więcej niż N backupów, zacznie usuwać od nadstarszych (wpisz 0, aby zatrzymać nieskończoną ilość)", "maxBackupsDesc": "Crafty nie będzie zbierał więcej niż X backupów, zacznie usuwać od nadstarszych (wpisz 0, aby zatrzymać nieskończoną ilość)",
"options": "Opcje", "options": "Opcje",
"path": "Ścieżka", "path": "Nazwa pliku",
"restore": "Przywróć", "restore": "Przywróć",
"restoring": "Przywracanie backupu. To trochę zajmie. Bądź cierpliwy.", "restoring": "Przywracanie backupu. To trochę zajmie. Bądź cierpliwy.",
"save": "Zapisz", "save": "Zapisz",
@ -333,13 +333,13 @@
"deleteServer": "Usuń serwer", "deleteServer": "Usuń serwer",
"deleteServerQuestion": "Usunąć serwer?", "deleteServerQuestion": "Usunąć serwer?",
"deleteServerQuestionMessage": "Jesteś pewien że chcesz usunąć ten serwer? To jest nie odwracalne...", "deleteServerQuestionMessage": "Jesteś pewien że chcesz usunąć ten serwer? To jest nie odwracalne...",
"exeUpdateURL": "URL pliku egzekucyjnego serwera", "exeUpdateURL": "URL pliku startowego serwera",
"exeUpdateURLDesc": "Bezpośredni link dla aktualizacji.", "exeUpdateURLDesc": "Bezpośredni link dla aktualizacji.",
"ignoredExits": "Ignoruj kody błędu przy crashu", "ignoredExits": "Ignoruj kody błędu przy crashu",
"ignoredExitsExplain": "Kody błędu Crafty powinien rozumieć jako `stop` (odzielone przecinkiem)", "ignoredExitsExplain": "Kody błędu Crafty powinien rozumieć jako `stop` (odzielone przecinkiem)",
"javaNoChange": "Nie nadpisuj", "javaNoChange": "Nie nadpisuj",
"javaVersion": "Nadpisz wersję Javy", "javaVersion": "Nadpisz wersję Javy",
"javaVersionDesc": "Jeśli chcesz nadpisać wersję javy. Upewnij się że twoja wersja javy w 'komendzie egzekucyjnej' jest zawinięta w cytaty (podstatowa zmienna 'java' jest wykluczona )", "javaVersionDesc": "Jeśli chcesz nadpisać wersję javy. Upewnij się że twoja wersja javy w 'komendzie startowej' jest zawinięta w cytaty (podstatowa zmienna 'java' jest wykluczona )",
"noDelete": "Nie, wróć się", "noDelete": "Nie, wróć się",
"noDeleteFiles": "Nie, tylko usuń z panelu", "noDeleteFiles": "Nie, tylko usuń z panelu",
"removeOldLogsAfter": "Usuń stare logi po", "removeOldLogsAfter": "Usuń stare logi po",
@ -351,8 +351,8 @@
"serverAutostartDelay": "Opóźnienie auto-włączenia serwera", "serverAutostartDelay": "Opóźnienie auto-włączenia serwera",
"serverAutostartDelayDesc": "Opóźnienie auto-włączenia (Jeśli włączone poniżej)", "serverAutostartDelayDesc": "Opóźnienie auto-włączenia (Jeśli włączone poniżej)",
"serverCrashDetection": "Detekcja Crashu serwera", "serverCrashDetection": "Detekcja Crashu serwera",
"serverExecutable": "Plik egzekucyjny", "serverExecutable": "Plik startowy",
"serverExecutableDesc": "Plik egzekucyjnego serwera", "serverExecutableDesc": "Plik startowy serwera",
"serverExecutionCommand": "Komenda włączania serwera", "serverExecutionCommand": "Komenda włączania serwera",
"serverExecutionCommandDesc": "Co będzie odpalone w ukrytej konsoli", "serverExecutionCommandDesc": "Co będzie odpalone w ukrytej konsoli",
"serverIP": "IP serwera", "serverIP": "IP serwera",
@ -412,7 +412,7 @@
"serverFiles": { "serverFiles": {
"clickUpload": "Kliknij tutaj, aby wybrać twoje pliki", "clickUpload": "Kliknij tutaj, aby wybrać twoje pliki",
"close": "Zamknij", "close": "Zamknij",
"createDir": "Nowa ścieżka", "createDir": "Nowy folder",
"createDirQuestion": "Jak chcesz nazwać nową ścieżkę?", "createDirQuestion": "Jak chcesz nazwać nową ścieżkę?",
"createFile": "Nowy plik", "createFile": "Nowy plik",
"createFileQuestion": "Jak chcesz nazwać nowy plik?", "createFileQuestion": "Jak chcesz nazwać nowy plik?",
@ -435,8 +435,8 @@
"size": "Włącz zmienianie rozmiaru edytora", "size": "Włącz zmienianie rozmiaru edytora",
"stayHere": "NIE WYCHODŹ Z TEJ STRONY!", "stayHere": "NIE WYCHODŹ Z TEJ STRONY!",
"unsupportedLanguage": "Uwaga: To nie jest wspierany typ pliku", "unsupportedLanguage": "Uwaga: To nie jest wspierany typ pliku",
"unzip": "Unzip", "unzip": "Rozpakuj",
"upload": "Upload", "upload": "Wyślij plik",
"uploadTitle": "Wyślij pliki do: ", "uploadTitle": "Wyślij pliki do: ",
"waitUpload": "Poczekaj, aż wyślemy twoje pliki... To może chwilkę zająć.", "waitUpload": "Poczekaj, aż wyślemy twoje pliki... To może chwilkę zająć.",
"yesDelete": "Tak, zdaję sobie sprawę z konsekfencji" "yesDelete": "Tak, zdaję sobie sprawę z konsekfencji"
@ -460,10 +460,10 @@
"cron": "Cron", "cron": "Cron",
"cron-explain": "Tutaj wpisz cron string -- Uwaga: 0 = Poniedziałek jest ostatnią opcją.", "cron-explain": "Tutaj wpisz cron string -- Uwaga: 0 = Poniedziałek jest ostatnią opcją.",
"custom": "Własna komenda", "custom": "Własna komenda",
"days": "dni", "days": "Dni",
"enabled": "Włączony", "enabled": "Włączony",
"hours": "Godziny", "hours": "Godziny",
"interval": "Interwał", "interval": "Częstotliwość",
"interval-explain": "Jak często mamy to wykonywać?", "interval-explain": "Jak często mamy to wykonywać?",
"minutes": "Minuty", "minutes": "Minuty",
"offset": "Opóźnienie przesunięcia", "offset": "Opóźnienie przesunięcia",
@ -471,13 +471,13 @@
"one-time": "Usuń po wykonaniu", "one-time": "Usuń po wykonaniu",
"parent": "Wybierz harmonogram rodzica", "parent": "Wybierz harmonogram rodzica",
"parent-explain": "Który harmonogram powinien wykonywać ten?", "parent-explain": "Który harmonogram powinien wykonywać ten?",
"reaction": "Reakcja", "reaction": "Aktywuje sie na zadanie",
"restart": "Restart Serwera", "restart": "Restart Serwera",
"select": "Basic / Cron / Chain Zaznaczenie reakcji", "select": "Typ zadania: Podstawowa / Cron / Łańcuchowa",
"start": "Start Serwera", "start": "Start Serwera",
"stop": "Wyłącz Serwer", "stop": "Wyłącz Serwer",
"time": "Czas", "time": "Czas",
"time-explain": "O jakim czasie ma wykonać się ten harmonogram?" "time-explain": "O jakim czasie ma wykonać się to zadanie?"
}, },
"serverSchedules": { "serverSchedules": {
"action": "Akcja", "action": "Akcja",
@ -499,8 +499,10 @@
"every": "Co", "every": "Co",
"interval": "Regularność", "interval": "Regularność",
"name": "Nazwa", "name": "Nazwa",
"newSchedule": "Nowe zadanie",
"nextRun": "Następne uruchomienie", "nextRun": "Następne uruchomienie",
"no": "Nie", "no": "Nie",
"no-schedule": "Nie posiadasz aktualnie żadnych zadań dla tego serwera. Aby dodać zadanie kliknij na",
"scheduledTasks": "Zaplanowane zadania", "scheduledTasks": "Zaplanowane zadania",
"yes": "Tak" "yes": "Tak"
}, },
@ -565,7 +567,7 @@
"selectType": "Wybierz typ serwera", "selectType": "Wybierz typ serwera",
"selectVersion": "Wybiesz wersje", "selectVersion": "Wybiesz wersje",
"selectZipDir": "Wybierz ścieżkę w archiwóm którą chcesz abyśmy wypakowali", "selectZipDir": "Wybierz ścieżkę w archiwóm którą chcesz abyśmy wypakowali",
"serverJar": "Plik egzekucyjny serwera", "serverJar": "Plik startowy serwera",
"serverName": "Nazwa serwera", "serverName": "Nazwa serwera",
"serverPath": "Ścieżka serwera", "serverPath": "Ścieżka serwera",
"serverPort": "Port serwera", "serverPort": "Port serwera",
@ -579,7 +581,7 @@
"zipPath": "Server Path" "zipPath": "Server Path"
}, },
"sidebar": { "sidebar": {
"contribute": "Współpracuj", "contribute": "Wspomóż nas",
"credits": "Podziękowania", "credits": "Podziękowania",
"dashboard": "Panel", "dashboard": "Panel",
"documentation": "Dokumentacja", "documentation": "Dokumentacja",
@ -625,22 +627,24 @@
"userRoles": "Role użytkownika", "userRoles": "Role użytkownika",
"userRolesDesc": "Role, które ten użytkownik posiada.", "userRolesDesc": "Role, które ten użytkownik posiada.",
"userSettings": "Ustawienia użytkownika", "userSettings": "Ustawienia użytkownika",
"userTheme": "Wygląd UI", "userTheme": "Wygląd interfejsu",
"uses": "Ilość użyć (-1==Bez limitu)" "uses": "Ilość użyć (-1==Bez limitu)"
}, },
"webhooks": { "webhooks": {
"areYouSureDel": "Usunąć ten webhook?", "areYouSureDel": "Usunąć ten webhook?",
"areYouSureRun": "Przetestować webhook?", "areYouSureRun": "Przetestować ten webhook?",
"backup_server": "Kopia zapasowa serwera została wykonana", "backup_server": "Kopia zapasowa serwera została wykonana",
"bot_name": "Nazwa bota", "bot_name": "Nazwa bota",
"color": "Kolor akcentu", "color": "Akcent kolorystyczny",
"crash_detected": "Serwer uległ awarii!", "crash_detected": "Serwer scrashował!",
"edit": "Edytuj", "edit": "Edytuj",
"enabled": "Włączony", "enabled": "Włączony",
"jar_update": "Plik startowy zaktualizowany", "jar_update": "Plik startowy zaktualizowany",
"kill": "Serwer zatrzymany", "kill": "Serwer zatrzymany",
"name": "Nazwa", "name": "Nazwa",
"new": "Nowy Webhook", "new": "Nowy Webhook",
"newWebhook": "Nowy Webhook",
"no-webhook": "Nie posiadasz aktualnie żadnych Webhooków dla tego serwera. Aby dodać webhook kliknij na",
"run": "Włącz Webhook", "run": "Włącz Webhook",
"send_command": "Komenda serwera otrzymana!", "send_command": "Komenda serwera otrzymana!",
"start_server": "Serwer włączony", "start_server": "Serwer włączony",

View File

@ -53,6 +53,20 @@
"translationTitle": "语言翻译", "translationTitle": "语言翻译",
"translator": "译者" "translator": "译者"
}, },
"customLogin": {
"apply": "应用",
"backgroundUpload": "后台上传",
"customLoginPage": "自定义登录页面",
"delete": "删除",
"labelLoginImage": "选择您的登录页面背景",
"loginBackground": "登录页面背景图片",
"loginImage": "上传登录页面背景图片。",
"loginOpacity": "选择登录窗口透明度",
"pageTitle": "自定义登录页面",
"preview": "预览",
"select": "选择",
"selectImage": "选择一张图片"
},
"dashboard": { "dashboard": {
"actions": "操作", "actions": "操作",
"allServers": "所有服务器", "allServers": "所有服务器",
@ -75,6 +89,7 @@
"dashboard": "仪表板", "dashboard": "仪表板",
"delay-explained": "服务进程已经在刚才启动,并且正在延迟 Minecraft 服务器实例的启动", "delay-explained": "服务进程已经在刚才启动,并且正在延迟 Minecraft 服务器实例的启动",
"host": "主机", "host": "主机",
"installing": "安装中……",
"kill": "杀死进程", "kill": "杀死进程",
"killing": "正在杀死进程……", "killing": "正在杀死进程……",
"lastBackup": "上次:", "lastBackup": "上次:",
@ -164,20 +179,33 @@
} }
}, },
"error": { "error": {
"agree": "同意",
"bedrockError": "基岩版下载不可用。请检查",
"cancel": "取消",
"contact": "通过 Discord 联系 Crafty Control 支持", "contact": "通过 Discord 联系 Crafty Control 支持",
"craftyStatus": "Crafty 的状态页面",
"cronFormat": "检测到无效的定时Cron格式",
"embarassing": "哦,天哪,这太尴尬了。", "embarassing": "哦,天哪,这太尴尬了。",
"error": "错误!", "error": "错误!",
"eulaAgree": "你同意吗?", "eulaAgree": "你同意吗?",
"eulaMsg": "你必须同意最终用户许可协议EULA。一份 Minecraft EULA 副本的链接在此消息下方。", "eulaMsg": "你必须同意最终用户许可协议EULA。一份 Minecraft EULA 副本的链接在此消息下方。",
"eulaTitle": "同意最终用户许可协议EULA", "eulaTitle": "同意最终用户许可协议EULA",
"fileError": "文件类型必须是图片。",
"fileTooLarge": "上传失败。上传的文件过大。联系系统管理员以获取协助。", "fileTooLarge": "上传失败。上传的文件过大。联系系统管理员以获取协助。",
"hereIsTheError": "错误如下", "hereIsTheError": "错误如下",
"installerJava": "安装 {} 失败:安装 Forge 服务器需要 Java。我们检测到 Java 未安装。请先安装 java 然后再安装服务器。",
"internet": "我们检测到运行 Crafty 的设备没有网络连接。客户端到服务器的连接可能受限。", "internet": "我们检测到运行 Crafty 的设备没有网络连接。客户端到服务器的连接可能受限。",
"migration": "Crafty 的主服务器存储正在被迁移到新位置。期间的所有服务器启动已被暂停。请等待我们完成迁移",
"no-file": "我们似乎找不到请求的文件。请再次检查路径。Crafty 是否拥有了正确的权限?", "no-file": "我们似乎找不到请求的文件。请再次检查路径。Crafty 是否拥有了正确的权限?",
"noInternet": "Crafty 无法访问网络。服务器创建已被禁用。请检查您的网络连接并刷新此页面。",
"noJava": "服务器 {} 启动失败,并输出了如下错误码:我们检测到 Java 未安装。请先安装 java 然后再启动服务器。", "noJava": "服务器 {} 启动失败,并输出了如下错误码:我们检测到 Java 未安装。请先安装 java 然后再启动服务器。",
"not-downloaded": "我们似乎找不到您的可执行文件。它下载完成了吗?可执行文件的权限设置正确了吗?", "not-downloaded": "我们似乎找不到您的可执行文件。它下载完成了吗?可执行文件的权限设置正确了吗?",
"portReminder": "我们检测到这是你首次运行 {}。请确保从您的路由器/防火墙转发 {} 端口,以使程序可以从公网远程访问。", "portReminder": "我们检测到这是你首次运行 {}。请确保从您的路由器/防火墙转发 {} 端口,以使程序可以从公网远程访问。",
"privMsg": "以及",
"serverJars1": "无法访问服务器 JAR API。请检查",
"serverJars2": "以获取最新信息。",
"start-error": "服务器 {} 启动失败,错误代码为:{}", "start-error": "服务器 {} 启动失败,错误代码为:{}",
"superError": "您必须作为超级用户来完成此操作。",
"terribleFailure": "多糟糕的错误!" "terribleFailure": "多糟糕的错误!"
}, },
"footer": { "footer": {
@ -189,7 +217,8 @@
"forgotPassword": "忘记密码", "forgotPassword": "忘记密码",
"login": "登录", "login": "登录",
"password": "密码", "password": "密码",
"username": "用户名" "username": "用户名",
"viewStatus": "查看公开状态页面"
}, },
"notify": { "notify": {
"activityLog": "活动日志", "activityLog": "活动日志",
@ -201,24 +230,38 @@
"preparingLogs": " 请等待,我们正在准备您的日志……准备好时我们会发送一次提醒。这对于大型的部署来说可能需要一点时间。", "preparingLogs": " 请等待,我们正在准备您的日志……准备好时我们会发送一次提醒。这对于大型的部署来说可能需要一点时间。",
"supportLogs": "支持日志" "supportLogs": "支持日志"
}, },
"offline": {
"offline": "离线",
"pleaseConnect": "请连接至网络以使用 Crafty。"
},
"panelConfig": { "panelConfig": {
"adminControls": "管理员控制", "adminControls": "管理员控制",
"allowedServers": "允许的服务器", "allowedServers": "允许的服务器",
"apply": "应用",
"assignedRoles": "已分配的角色", "assignedRoles": "已分配的角色",
"cancel": "取消", "cancel": "取消",
"clearComms": "清除未执行的指令", "clearComms": "清除未执行的指令",
"custom": "自定义 Crafty",
"delete": "删除", "delete": "删除",
"edit": "编辑", "edit": "编辑",
"enableLang": "启用所有语言",
"enabled": "已启用", "enabled": "已启用",
"globalExplain": "Crafty 存储您的所有服务器文件的位置。(我们会在路径后添加 /servers/[服务器的 uuid]",
"globalServer": "全局服务器文件夹",
"json": "Config.json",
"match": "密码必须匹配",
"newRole": "添加新角色", "newRole": "添加新角色",
"newUser": "添加新用户", "newUser": "添加新用户",
"noMounts": "不在仪表板上显示挂载的驱动器",
"pageTitle": "面板配置", "pageTitle": "面板配置",
"role": "角色", "role": "角色",
"roleUsers": "被分配了该角色的用户", "roleUsers": "被分配了该角色的用户",
"roles": "角色", "roles": "角色",
"save": "保存", "save": "保存",
"select": "选择",
"superConfirm": "仅在你希望此用户能访问所有数据(所有用户账户、服务器、面板设置等)的情况下继续。它们甚至可以撤回您的超级用户权限。", "superConfirm": "仅在你希望此用户能访问所有数据(所有用户账户、服务器、面板设置等)的情况下继续。它们甚至可以撤回您的超级用户权限。",
"superConfirmTitle": "启用超级用户?您确定吗?", "superConfirmTitle": "启用超级用户?您确定吗?",
"title": "Crafty 配置",
"user": "用户", "user": "用户",
"users": "用户" "users": "用户"
}, },
@ -242,14 +285,17 @@
"roleTitle": "角色设置", "roleTitle": "角色设置",
"roleUserName": "用户名称", "roleUserName": "用户名称",
"roleUsers": "角色用户:", "roleUsers": "角色用户:",
"selectManager": "选择此角色的管理员",
"serverAccess": "访问?", "serverAccess": "访问?",
"serverName": "服务器名称", "serverName": "服务器名称",
"serversDesc": "此角色允许访问的服务器" "serversDesc": "此角色允许访问的服务器"
}, },
"serverBackups": { "serverBackups": {
"after": "备份后运行指令",
"backupAtMidnight": "午夜自动备份?", "backupAtMidnight": "午夜自动备份?",
"backupNow": "现在备份!", "backupNow": "现在备份!",
"backupTask": "一个备份任务已开始。", "backupTask": "一个备份任务已开始。",
"before": "备份前运行指令",
"cancel": "取消", "cancel": "取消",
"clickExclude": "点击来选择排除项", "clickExclude": "点击来选择排除项",
"compress": "压缩备份", "compress": "压缩备份",
@ -289,6 +335,8 @@
"deleteServerQuestionMessage": "您确定要删除此服务器吗?在此之后将无法撤销……", "deleteServerQuestionMessage": "您确定要删除此服务器吗?在此之后将无法撤销……",
"exeUpdateURL": "服务器可执行文件更新地址", "exeUpdateURL": "服务器可执行文件更新地址",
"exeUpdateURLDesc": "用于下载更新的直接链接。", "exeUpdateURLDesc": "用于下载更新的直接链接。",
"ignoredExits": "忽略的崩溃退出代码",
"ignoredExitsExplain": "Crafty 的崩溃检测应该忽略为正常的“停止”的退出代码(以英文逗号分隔)",
"javaNoChange": "不覆盖", "javaNoChange": "不覆盖",
"javaVersion": "覆盖当前的 Java 版本", "javaVersion": "覆盖当前的 Java 版本",
"javaVersionDesc": "如果你要覆盖 Java请确保你当前“运行命令”中的 Java 路径括在了引号中不包括默认的“java”变量", "javaVersionDesc": "如果你要覆盖 Java请确保你当前“运行命令”中的 Java 路径括在了引号中不包括默认的“java”变量",
@ -319,7 +367,13 @@
"serverPortDesc": "Crafty 要连接以获取状态的端口", "serverPortDesc": "Crafty 要连接以获取状态的端口",
"serverStopCommand": "服务器停止指令", "serverStopCommand": "服务器停止指令",
"serverStopCommandDesc": "要发送给程序以关闭它的指令", "serverStopCommandDesc": "要发送给程序以关闭它的指令",
"showStatus": "在公开状态页面上显示",
"shutdownTimeout": "停止超时",
"statsHint1": "此处应填写您的服务器运行在的端口。这是 Crafty 与您的服务器建立连接以获取状态的方式。",
"statsHint2": "此选项不会更改您的服务器的端口。您仍必须更改您的服务器配置文件中的端口。",
"stopBeforeDeleting": "请在删除之前停止服务器", "stopBeforeDeleting": "请在删除之前停止服务器",
"timeoutExplain1": "Crafty 执行",
"timeoutExplain2": "指令之后,在强制结束进程前等待您的服务器停止的时间。",
"update": "更新可执行文件", "update": "更新可执行文件",
"yesDelete": "是,删除", "yesDelete": "是,删除",
"yesDeleteFiles": "是,删除文件" "yesDeleteFiles": "是,删除文件"
@ -345,8 +399,12 @@
"backup": "备份", "backup": "备份",
"config": "配置", "config": "配置",
"files": "文件", "files": "文件",
"filter": "过滤日志",
"filterList": "被过滤的字符",
"logs": "日志", "logs": "日志",
"metrics": "指标",
"playerControls": "玩家管理", "playerControls": "玩家管理",
"reset": "重置滚动",
"schedule": "计划", "schedule": "计划",
"serverDetails": "服务器详情", "serverDetails": "服务器详情",
"terminal": "终端" "terminal": "终端"
@ -383,6 +441,11 @@
"waitUpload": "请等待,我们正在上传您的文件……这需要一点时间。", "waitUpload": "请等待,我们正在上传您的文件……这需要一点时间。",
"yesDelete": "是,我知道结果" "yesDelete": "是,我知道结果"
}, },
"serverMetrics": {
"resetZoom": "重置缩放",
"zoomHint1": "按住 shift 键并使用您的滚轮以缩放图表。",
"zoomHint2": "或者按住 shift 键并拖动选择您想放大的区域。"
},
"serverPlayerManagement": { "serverPlayerManagement": {
"bannedPlayers": "已封禁的玩家", "bannedPlayers": "已封禁的玩家",
"loadingBannedPlayers": "正在加载已封禁的玩家", "loadingBannedPlayers": "正在加载已封禁的玩家",
@ -410,18 +473,38 @@
"parent-explain": "哪个计划会触发这一个计划?", "parent-explain": "哪个计划会触发这一个计划?",
"reaction": "响应", "reaction": "响应",
"restart": "重启服务器", "restart": "重启服务器",
"select": "基本 / 定时Cron / 连锁反应选择",
"start": "启动服务器", "start": "启动服务器",
"stop": "停止服务器", "stop": "停止服务器",
"time": "时间", "time": "时间",
"time-explain": "你想要在什么时候执行这个计划?" "time-explain": "你想要在什么时候执行这个计划?"
}, },
"serverSchedules": { "serverSchedules": {
"action": "操作",
"areYouSure": "删除计划任务?", "areYouSure": "删除计划任务?",
"cancel": "取消", "cancel": "取消",
"cannotSee": "什么都看不到?", "cannotSee": "什么都看不到?",
"cannotSeeOnMobile": "尝试点击一个计划任务来查看全部详细信息。", "cannotSeeOnMobile": "尝试点击一个计划任务来查看全部详细信息。",
"child": "父计划 ID",
"close": "关闭",
"command": "指令",
"confirm": "确认", "confirm": "确认",
"confirmDelete": "您想要删除这个计划任务吗?此操作不能撤销。" "confirmDelete": "您想要删除这个计划任务吗?此操作不能撤销。",
"create": "创建新计划",
"cron": "定时Cron字符串",
"delete": "删除",
"details": "计划详细信息",
"edit": "编辑",
"enabled": "已启用",
"every": "每",
"interval": "间隔",
"name": "名称",
"newSchedule": "新计划",
"nextRun": "下次运行",
"no": "否",
"no-schedule": "此服务器当前没有计划。要开始使用计划,点击",
"scheduledTasks": "计划任务",
"yes": "是"
}, },
"serverStats": { "serverStats": {
"cpuUsage": "CPU 使用率", "cpuUsage": "CPU 使用率",
@ -444,6 +527,8 @@
"commandInput": "输入您的指令", "commandInput": "输入您的指令",
"delay-explained": "服务进程已经在刚才启动,并且正在延迟 Minecraft 服务器实例的启动", "delay-explained": "服务进程已经在刚才启动,并且正在延迟 Minecraft 服务器实例的启动",
"downloading": "下载中……", "downloading": "下载中……",
"importing": "正在导入……",
"installing": "正在安装……",
"restart": "重启", "restart": "重启",
"sendCommand": "发送指令", "sendCommand": "发送指令",
"start": "启动", "start": "启动",
@ -468,6 +553,7 @@
"importServerButton": "导入服务器!", "importServerButton": "导入服务器!",
"importZip": "从 Zip 文件导入", "importZip": "从 Zip 文件导入",
"importing": "导入服务器中……", "importing": "导入服务器中……",
"labelZipFile": "选择您的 Zip 文件",
"maxMem": "最大内存", "maxMem": "最大内存",
"minMem": "最小内存", "minMem": "最小内存",
"myNewServer": "我的新服务器", "myNewServer": "我的新服务器",
@ -478,6 +564,7 @@
"save": "保存", "save": "保存",
"selectRole": "选择角色", "selectRole": "选择角色",
"selectRoot": "选择压缩文件中的根目录", "selectRoot": "选择压缩文件中的根目录",
"selectServer": "选择一个服务器",
"selectType": "选择一种类型", "selectType": "选择一种类型",
"selectVersion": "选择一个版本", "selectVersion": "选择一个版本",
"selectZipDir": "选择你想要我们解压的压缩文件中的目录", "selectZipDir": "选择你想要我们解压的压缩文件中的目录",
@ -485,9 +572,13 @@
"serverName": "服务器名称", "serverName": "服务器名称",
"serverPath": "服务器路径", "serverPath": "服务器路径",
"serverPort": "服务器端口", "serverPort": "服务器端口",
"serverSelect": "服务器选择",
"serverType": "服务器类型", "serverType": "服务器类型",
"serverUpload": "上传打包为 Zip 文件的服务器",
"serverVersion": "服务器版本", "serverVersion": "服务器版本",
"sizeInGB": "大小(以 GB 为单位)", "sizeInGB": "大小(以 GB 为单位)",
"uploadButton": "上传",
"uploadZip": "上传 Zip 文件以导入服务器",
"zipPath": "服务器路径" "zipPath": "服务器路径"
}, },
"sidebar": { "sidebar": {
@ -495,6 +586,7 @@
"credits": "鸣谢", "credits": "鸣谢",
"dashboard": "仪表板", "dashboard": "仪表板",
"documentation": "文档", "documentation": "文档",
"inApp": "内置文档",
"navigation": "导航栏", "navigation": "导航栏",
"newServer": "创建新服务器", "newServer": "创建新服务器",
"servers": "服务器" "servers": "服务器"
@ -519,6 +611,7 @@
"lastLogin": "上次登录:", "lastLogin": "上次登录:",
"lastUpdate": "上次更新:", "lastUpdate": "上次更新:",
"leaveBlank": "如果要编辑此用户但不更改密码,请留空。", "leaveBlank": "如果要编辑此用户但不更改密码,请留空。",
"manager": "管理员",
"member": "成员?", "member": "成员?",
"notExist": "您不能删除不存在的东西!", "notExist": "您不能删除不存在的东西!",
"pageTitle": "编辑用户", "pageTitle": "编辑用户",
@ -527,6 +620,7 @@
"permName": "权限名称", "permName": "权限名称",
"repeat": "重复密码", "repeat": "重复密码",
"roleName": "角色名称", "roleName": "角色名称",
"selectManager": "选择用户的管理员",
"super": "超级用户", "super": "超级用户",
"userLang": "用户语言", "userLang": "用户语言",
"userName": "用户名称", "userName": "用户名称",
@ -534,6 +628,32 @@
"userRoles": "用户角色", "userRoles": "用户角色",
"userRolesDesc": "此用户充当成员的角色。", "userRolesDesc": "此用户充当成员的角色。",
"userSettings": "用户设置", "userSettings": "用户设置",
"userTheme": "UI 主题",
"uses": "使用次数限制(-1==无限制)" "uses": "使用次数限制(-1==无限制)"
},
"webhooks": {
"areYouSureDel": "您确定要删除此 webhook 吗?",
"areYouSureRun": "您确定要测试此 webhook 吗?",
"backup_server": "服务器备份完成",
"bot_name": "机器人名称",
"color": "选择主题色",
"crash_detected": "服务器已崩溃",
"edit": "编辑",
"enabled": "已启用",
"jar_update": "服务器可执行文件已更新",
"kill": "服务器进程已杀死",
"name": "名称",
"new": "新 Webhook",
"newWebhook": "新 Webhook",
"no-webhook": "此服务器当前没有 Webhook。要开始使用 Webhook点击",
"run": "测试 Webhook",
"send_command": "服务器指令已接收",
"start_server": "服务器已启动",
"stop_server": "服务器已停止",
"trigger": "触发器",
"type": "Webhook 类型",
"url": "Webhook 地址",
"webhook_body": "Webhook 消息体Body",
"webhooks": "Webhook"
} }
} }

View File

@ -3,7 +3,7 @@ sonar.organization=crafty-controller
# This is the name and version displayed in the SonarCloud UI. # This is the name and version displayed in the SonarCloud UI.
sonar.projectName=Crafty 4 sonar.projectName=Crafty 4
sonar.projectVersion=4.2.0 sonar.projectVersion=4.2.1
sonar.python.version=3.9, 3.10, 3.11 sonar.python.version=3.9, 3.10, 3.11
sonar.exclusions=app/migrations/**, app/frontend/static/assets/vendors/** sonar.exclusions=app/migrations/**, app/frontend/static/assets/vendors/**