Feat: Server Props Search
Feat: Add custom prop adds Feat: Add Removing Props
This commit is contained in:
47
public/css/styles.min.css
vendored
47
public/css/styles.min.css
vendored
@ -42,6 +42,8 @@
|
|||||||
--spacing: 0.25rem;
|
--spacing: 0.25rem;
|
||||||
--container-md: 28rem;
|
--container-md: 28rem;
|
||||||
--container-xl: 36rem;
|
--container-xl: 36rem;
|
||||||
|
--text-xs: 0.75rem;
|
||||||
|
--text-xs--line-height: calc(1 / 0.75);
|
||||||
--text-sm: 0.875rem;
|
--text-sm: 0.875rem;
|
||||||
--text-sm--line-height: calc(1.25 / 0.875);
|
--text-sm--line-height: calc(1.25 / 0.875);
|
||||||
--text-lg: 1.125rem;
|
--text-lg: 1.125rem;
|
||||||
@ -224,6 +226,9 @@
|
|||||||
.inset-0 {
|
.inset-0 {
|
||||||
inset: calc(var(--spacing) * 0);
|
inset: calc(var(--spacing) * 0);
|
||||||
}
|
}
|
||||||
|
.z-50 {
|
||||||
|
z-index: 50;
|
||||||
|
}
|
||||||
.container {
|
.container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@media (width >= 40rem) {
|
@media (width >= 40rem) {
|
||||||
@ -251,6 +256,9 @@
|
|||||||
.mt-4 {
|
.mt-4 {
|
||||||
margin-top: calc(var(--spacing) * 4);
|
margin-top: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
|
.mr-2 {
|
||||||
|
margin-right: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
.mb-1 {
|
.mb-1 {
|
||||||
margin-bottom: calc(var(--spacing) * 1);
|
margin-bottom: calc(var(--spacing) * 1);
|
||||||
}
|
}
|
||||||
@ -278,6 +286,9 @@
|
|||||||
.inline-block {
|
.inline-block {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
.table {
|
||||||
|
display: table;
|
||||||
|
}
|
||||||
.h-24 {
|
.h-24 {
|
||||||
height: calc(var(--spacing) * 24);
|
height: calc(var(--spacing) * 24);
|
||||||
}
|
}
|
||||||
@ -296,9 +307,15 @@
|
|||||||
.min-h-full {
|
.min-h-full {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
|
.w-1 {
|
||||||
|
width: calc(var(--spacing) * 1);
|
||||||
|
}
|
||||||
.w-1\/3 {
|
.w-1\/3 {
|
||||||
width: calc(1/3 * 100%);
|
width: calc(1/3 * 100%);
|
||||||
}
|
}
|
||||||
|
.w-2 {
|
||||||
|
width: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
.w-2\/3 {
|
.w-2\/3 {
|
||||||
width: calc(2/3 * 100%);
|
width: calc(2/3 * 100%);
|
||||||
}
|
}
|
||||||
@ -320,9 +337,15 @@
|
|||||||
.flex-1 {
|
.flex-1 {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
.flex-shrink {
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
.flex-grow {
|
.flex-grow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
.border-collapse {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
.transform {
|
.transform {
|
||||||
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
|
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
|
||||||
}
|
}
|
||||||
@ -518,6 +541,10 @@
|
|||||||
font-size: var(--text-xl);
|
font-size: var(--text-xl);
|
||||||
line-height: var(--tw-leading, var(--text-xl--line-height));
|
line-height: var(--tw-leading, var(--text-xl--line-height));
|
||||||
}
|
}
|
||||||
|
.text-xs {
|
||||||
|
font-size: var(--text-xs);
|
||||||
|
line-height: var(--tw-leading, var(--text-xs--line-height));
|
||||||
|
}
|
||||||
.leading-relaxed {
|
.leading-relaxed {
|
||||||
--tw-leading: var(--leading-relaxed);
|
--tw-leading: var(--leading-relaxed);
|
||||||
line-height: var(--leading-relaxed);
|
line-height: var(--leading-relaxed);
|
||||||
@ -552,6 +579,9 @@
|
|||||||
.text-white {
|
.text-white {
|
||||||
color: var(--color-white);
|
color: var(--color-white);
|
||||||
}
|
}
|
||||||
|
.underline {
|
||||||
|
text-decoration-line: underline;
|
||||||
|
}
|
||||||
.opacity-50 {
|
.opacity-50 {
|
||||||
opacity: 50%;
|
opacity: 50%;
|
||||||
}
|
}
|
||||||
@ -559,6 +589,10 @@
|
|||||||
--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||||
}
|
}
|
||||||
|
.outline {
|
||||||
|
outline-style: var(--tw-outline-style);
|
||||||
|
outline-width: 1px;
|
||||||
|
}
|
||||||
.filter {
|
.filter {
|
||||||
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
|
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
|
||||||
}
|
}
|
||||||
@ -634,6 +668,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.hover\:text-red-700 {
|
||||||
|
&:hover {
|
||||||
|
@media (hover: hover) {
|
||||||
|
color: var(--color-red-700);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.sm\:w-\[90\%\] {
|
.sm\:w-\[90\%\] {
|
||||||
@media (width >= 40rem) {
|
@media (width >= 40rem) {
|
||||||
width: 90%;
|
width: 90%;
|
||||||
@ -1188,6 +1229,11 @@
|
|||||||
inherits: false;
|
inherits: false;
|
||||||
initial-value: 0 0 #0000;
|
initial-value: 0 0 #0000;
|
||||||
}
|
}
|
||||||
|
@property --tw-outline-style {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
initial-value: solid;
|
||||||
|
}
|
||||||
@property --tw-blur {
|
@property --tw-blur {
|
||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
@ -1296,6 +1342,7 @@
|
|||||||
--tw-ring-offset-width: 0px;
|
--tw-ring-offset-width: 0px;
|
||||||
--tw-ring-offset-color: #fff;
|
--tw-ring-offset-color: #fff;
|
||||||
--tw-ring-offset-shadow: 0 0 #0000;
|
--tw-ring-offset-shadow: 0 0 #0000;
|
||||||
|
--tw-outline-style: solid;
|
||||||
--tw-blur: initial;
|
--tw-blur: initial;
|
||||||
--tw-brightness: initial;
|
--tw-brightness: initial;
|
||||||
--tw-contrast: initial;
|
--tw-contrast: initial;
|
||||||
|
160
public/js/app.js
160
public/js/app.js
@ -1412,7 +1412,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
let displayProperties = {}; // Store original properties for filtering
|
let displayProperties = {}; // Store original properties for filtering
|
||||||
|
|
||||||
function parseServerProperties(content) {
|
function parseServerProperties(content) {
|
||||||
const properties = {};
|
const properties = {};
|
||||||
const lines = content.split('\n');
|
const lines = content.split('\n');
|
||||||
lines.forEach(line => {
|
lines.forEach(line => {
|
||||||
@ -1424,9 +1424,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPropertiesFields(properties, filter = '') {
|
function renderPropertiesFields(properties, filter = '') {
|
||||||
const fieldsContainer = elements.propertiesFields;
|
const fieldsContainer = elements.propertiesFields;
|
||||||
|
|
||||||
// Create search box only if not already present
|
// Create search box only if not already present
|
||||||
@ -1451,6 +1451,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
searchContainer.appendChild(searchLabel);
|
searchContainer.appendChild(searchLabel);
|
||||||
searchContainer.appendChild(searchInput);
|
searchContainer.appendChild(searchInput);
|
||||||
|
|
||||||
|
// Add custom property button (mini style)
|
||||||
|
const addButton = document.createElement('button');
|
||||||
|
addButton.textContent = 'Add Property';
|
||||||
|
addButton.type = 'button';
|
||||||
|
addButton.className = 'mt-2 bg-blue-600 hover:bg-blue-700 text-white px-2 py-1 rounded text-xs';
|
||||||
|
addButton.addEventListener('click', showCustomPropertyForm);
|
||||||
|
searchContainer.appendChild(addButton);
|
||||||
|
|
||||||
fieldsContainer.appendChild(searchContainer);
|
fieldsContainer.appendChild(searchContainer);
|
||||||
|
|
||||||
// Add input event listener
|
// Add input event listener
|
||||||
@ -1480,32 +1489,147 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
elements.searchInput.value = '';
|
elements.searchInput.value = '';
|
||||||
renderPropertiesList(displayProperties, '');
|
renderPropertiesList(displayProperties, '');
|
||||||
elements.editPropertiesModal.classList.add('hidden');
|
elements.editPropertiesModal.classList.add('hidden');
|
||||||
|
hideCustomPropertyForm();
|
||||||
});
|
});
|
||||||
closeButton.dataset.closeHandlerAdded = 'true';
|
closeButton.dataset.closeHandlerAdded = 'true';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showCustomPropertyForm() {
|
||||||
|
let formContainer = elements.propertiesFields.querySelector('#customPropertyForm');
|
||||||
|
if (formContainer) {
|
||||||
|
formContainer.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPropertiesList(properties, filter = '') {
|
formContainer = document.createElement('div');
|
||||||
|
formContainer.id = 'customPropertyForm';
|
||||||
|
formContainer.className = 'mb-4 p-4 bg-gray-800 rounded';
|
||||||
|
|
||||||
|
const form = document.createElement('form');
|
||||||
|
form.addEventListener('submit', (e) => e.preventDefault());
|
||||||
|
|
||||||
|
const keyInput = document.createElement('input');
|
||||||
|
keyInput.type = 'text';
|
||||||
|
keyInput.placeholder = 'Property name';
|
||||||
|
keyInput.className = 'bg-gray-700 px-4 py-2 rounded text-white w-full mb-2';
|
||||||
|
|
||||||
|
const valueInput = document.createElement('input');
|
||||||
|
valueInput.type = 'text';
|
||||||
|
valueInput.placeholder = 'Property value';
|
||||||
|
valueInput.className = 'bg-gray-700 px-4 py-2 rounded text-white w-full mb-2';
|
||||||
|
|
||||||
|
const addButton = document.createElement('button');
|
||||||
|
addButton.type = 'button';
|
||||||
|
addButton.textContent = 'Add';
|
||||||
|
addButton.className = 'bg-green-600 hover:bg-green-700 text-white px-2 py-1 rounded text-xs mr-2';
|
||||||
|
addButton.addEventListener('click', () => {
|
||||||
|
const key = keyInput.value.trim();
|
||||||
|
const value = valueInput.value.trim();
|
||||||
|
if (key && value) {
|
||||||
|
displayProperties[key] = value;
|
||||||
|
allProperties[key] = value;
|
||||||
|
renderPropertiesList(displayProperties, elements.searchInput.value);
|
||||||
|
formContainer.remove();
|
||||||
|
} else {
|
||||||
|
showNotification('Please enter both property name and value', 'error', 'custom-property-error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const cancelButton = document.createElement('button');
|
||||||
|
cancelButton.type = 'button';
|
||||||
|
cancelButton.textContent = 'Cancel';
|
||||||
|
cancelButton.className = 'bg-gray-600 hover:bg-gray-700 text-white px-2 py-1 rounded text-xs';
|
||||||
|
cancelButton.addEventListener('click', hideCustomPropertyForm);
|
||||||
|
|
||||||
|
form.appendChild(keyInput);
|
||||||
|
form.appendChild(valueInput);
|
||||||
|
form.appendChild(addButton);
|
||||||
|
form.appendChild(cancelButton);
|
||||||
|
formContainer.appendChild(form);
|
||||||
|
|
||||||
|
elements.propertiesFields.insertBefore(formContainer, elements.propertiesFields.querySelector('#propertiesList'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideCustomPropertyForm() {
|
||||||
|
const formContainer = elements.propertiesFields.querySelector('#customPropertyForm');
|
||||||
|
if (formContainer) {
|
||||||
|
formContainer.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showDeleteConfirmationModal(key) {
|
||||||
|
const modal = document.createElement('div');
|
||||||
|
modal.id = 'deleteConfirmationModal';
|
||||||
|
modal.className = 'absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50';
|
||||||
|
|
||||||
|
const modalContent = document.createElement('div');
|
||||||
|
modalContent.className = 'bg-gray-800 p-6 rounded-lg max-w-md w-full';
|
||||||
|
|
||||||
|
const header = document.createElement('h3');
|
||||||
|
header.className = 'text-lg font-medium text-white mb-4';
|
||||||
|
header.textContent = 'Confirm Deletion';
|
||||||
|
|
||||||
|
const message = document.createElement('p');
|
||||||
|
message.className = 'text-white mb-6';
|
||||||
|
message.textContent = `Are you sure you want to delete the property "${key}"? This action cannot be undone.`;
|
||||||
|
|
||||||
|
const buttonContainer = document.createElement('div');
|
||||||
|
buttonContainer.className = 'flex justify-end space-x-2';
|
||||||
|
|
||||||
|
const cancelButton = document.createElement('button');
|
||||||
|
cancelButton.type = 'button';
|
||||||
|
cancelButton.className = 'bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded';
|
||||||
|
cancelButton.textContent = 'Cancel';
|
||||||
|
cancelButton.addEventListener('click', () => modal.remove());
|
||||||
|
|
||||||
|
const deleteButton = document.createElement('button');
|
||||||
|
deleteButton.type = 'button';
|
||||||
|
deleteButton.className = 'bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded';
|
||||||
|
deleteButton.textContent = 'Delete';
|
||||||
|
deleteButton.addEventListener('click', () => {
|
||||||
|
delete displayProperties[key];
|
||||||
|
delete allProperties[key];
|
||||||
|
renderPropertiesList(displayProperties, elements.searchInput.value);
|
||||||
|
modal.remove();
|
||||||
|
showNotification(`Property "${key}" deleted`, 'success', 'delete-property-success');
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonContainer.appendChild(cancelButton);
|
||||||
|
buttonContainer.appendChild(deleteButton);
|
||||||
|
modalContent.appendChild(header);
|
||||||
|
modalContent.appendChild(message);
|
||||||
|
modalContent.appendChild(buttonContainer);
|
||||||
|
modal.appendChild(modalContent);
|
||||||
|
|
||||||
|
elements.editPropertiesModal.appendChild(modal);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPropertiesList(properties, filter = '') {
|
||||||
const propertiesList = elements.propertiesFields.querySelector('#propertiesList');
|
const propertiesList = elements.propertiesFields.querySelector('#propertiesList');
|
||||||
propertiesList.innerHTML = '';
|
propertiesList.innerHTML = '';
|
||||||
|
|
||||||
// Filter properties based on search input
|
|
||||||
const filteredProperties = Object.entries(properties).filter(([key]) =>
|
const filteredProperties = Object.entries(properties).filter(([key]) =>
|
||||||
key.toLowerCase().includes(filter.toLowerCase())
|
key.toLowerCase().includes(filter.toLowerCase())
|
||||||
);
|
);
|
||||||
|
|
||||||
// Render filtered properties
|
|
||||||
filteredProperties.forEach(([key, value]) => {
|
filteredProperties.forEach(([key, value]) => {
|
||||||
if (filteredSettings.includes(key)) {
|
if (filteredSettings.includes(key)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Rendering field for ${key}: ${value}`); // Debug log
|
console.log(`Rendering field for ${key}: ${value}`);
|
||||||
|
|
||||||
const fieldDiv = document.createElement('div');
|
const fieldDiv = document.createElement('div');
|
||||||
fieldDiv.className = 'flex items-center space-x-2';
|
fieldDiv.className = 'flex items-center space-x-2';
|
||||||
fieldDiv.style.display = 'flex';
|
fieldDiv.style.display = 'flex';
|
||||||
|
|
||||||
|
const deleteButton = document.createElement('button');
|
||||||
|
deleteButton.type = 'button';
|
||||||
|
deleteButton.className = 'text-red-500 hover:text-red-700';
|
||||||
|
deleteButton.innerHTML = '✕';
|
||||||
|
deleteButton.title = `Delete ${key}`;
|
||||||
|
deleteButton.addEventListener('click', () => showDeleteConfirmationModal(key));
|
||||||
|
|
||||||
let inputType = 'text';
|
let inputType = 'text';
|
||||||
let isBoolean = value.toLowerCase() === 'true' || value.toLowerCase() === 'false';
|
let isBoolean = value.toLowerCase() === 'true' || value.toLowerCase() === 'false';
|
||||||
if (isBoolean) {
|
if (isBoolean) {
|
||||||
@ -1520,7 +1644,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
label.setAttribute('for', `prop-${key}`);
|
label.setAttribute('for', `prop-${key}`);
|
||||||
|
|
||||||
if (inputType === 'switch') {
|
if (inputType === 'switch') {
|
||||||
// Hidden text input for accessibility and form association
|
|
||||||
const hiddenInput = document.createElement('input');
|
const hiddenInput = document.createElement('input');
|
||||||
hiddenInput.type = 'text';
|
hiddenInput.type = 'text';
|
||||||
hiddenInput.id = `prop-${key}`;
|
hiddenInput.id = `prop-${key}`;
|
||||||
@ -1556,7 +1679,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
switchHandle.style.position = 'absolute';
|
switchHandle.style.position = 'absolute';
|
||||||
switchHandle.style.zIndex = '11';
|
switchHandle.style.zIndex = '11';
|
||||||
|
|
||||||
// Handle click and keyboard events
|
|
||||||
const toggleSwitch = () => {
|
const toggleSwitch = () => {
|
||||||
const currentValue = hiddenInput.value === 'true';
|
const currentValue = hiddenInput.value === 'true';
|
||||||
const newValue = !currentValue;
|
const newValue = !currentValue;
|
||||||
@ -1576,6 +1698,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
switchContainer.appendChild(switchTrack);
|
switchContainer.appendChild(switchTrack);
|
||||||
switchContainer.appendChild(switchHandle);
|
switchContainer.appendChild(switchHandle);
|
||||||
|
fieldDiv.appendChild(deleteButton);
|
||||||
fieldDiv.appendChild(label);
|
fieldDiv.appendChild(label);
|
||||||
fieldDiv.appendChild(hiddenInput);
|
fieldDiv.appendChild(hiddenInput);
|
||||||
fieldDiv.appendChild(switchContainer);
|
fieldDiv.appendChild(switchContainer);
|
||||||
@ -1584,27 +1707,28 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
input.id = `prop-${key}`;
|
input.id = `prop-${key}`;
|
||||||
input.name = key;
|
input.name = key;
|
||||||
input.className = 'bg-gray-700 px-4 py-2 rounded text-white w-2/3';
|
input.className = 'bg-gray-700 px-4 py-2 rounded text-white w-2/3';
|
||||||
input.type = inputType;
|
input.type = 'number';
|
||||||
input.value = value;
|
input.value = value;
|
||||||
if (inputType === 'number') {
|
if (inputType === 'number') {
|
||||||
input.min = '0';
|
input.min = '0';
|
||||||
}
|
}
|
||||||
|
fieldDiv.appendChild(deleteButton);
|
||||||
fieldDiv.appendChild(label);
|
fieldDiv.appendChild(label);
|
||||||
fieldDiv.appendChild(input);
|
fieldDiv.appendChild(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
propertiesList.appendChild(fieldDiv);
|
propertiesList.appendChild(fieldDiv);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function propertiesToString(properties) {
|
function propertiesToString(properties) {
|
||||||
let header = `#Minecraft server properties\n#${new Date().toUTCString()}\n`;
|
let header = `#Minecraft server properties\n#${new Date().toUTCString()}\n`;
|
||||||
return header + Object.entries(properties)
|
return header + Object.entries(properties)
|
||||||
.map(([key, value]) => `${key}=${value}`)
|
.map(([key, value]) => `${key}=${value}`)
|
||||||
.join('\n');
|
.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchServerProperties() {
|
async function fetchServerProperties() {
|
||||||
try {
|
try {
|
||||||
const key = `action-fetch-properties`;
|
const key = `action-fetch-properties`;
|
||||||
const notification = showNotification('Loading server properties...', 'loading', key);
|
const notification = showNotification('Loading server properties...', 'loading', key);
|
||||||
@ -1628,14 +1752,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
console.error('Fetch server properties error:', error);
|
console.error('Fetch server properties error:', error);
|
||||||
showNotification(`Failed to load server properties: ${error.message}`, 'error', 'fetch-properties-error');
|
showNotification(`Failed to load server properties: ${error.message}`, 'error', 'fetch-properties-error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveServerProperties() {
|
async function saveServerProperties() {
|
||||||
try {
|
try {
|
||||||
const key = `action-save-properties`;
|
const key = `action-save-properties`;
|
||||||
const notification = showNotification('Saving server properties...', 'loading', key);
|
const notification = showNotification('Saving server properties...', 'loading', key);
|
||||||
const properties = {};
|
const properties = {};
|
||||||
const inputs = elements.propertiesFields.querySelectorAll('input:not(#propertiesSearch)');
|
const inputs = elements.propertiesFields.querySelectorAll('input:not(#propertiesSearch):not([id="customPropertyKey"]):not([id="customPropertyValue"])');
|
||||||
|
|
||||||
// Collect modified properties
|
// Collect modified properties
|
||||||
inputs.forEach(input => {
|
inputs.forEach(input => {
|
||||||
@ -1665,7 +1789,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
console.error('Save server properties error:', error);
|
console.error('Save server properties error:', error);
|
||||||
showNotification(`Failed to save server properties: ${error.message}`, 'error', 'save-properties-error');
|
showNotification(`Failed to save server properties: ${error.message}`, 'error', 'save-properties-error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateMods() {
|
async function updateMods() {
|
||||||
try {
|
try {
|
||||||
|
Reference in New Issue
Block a user