Enhances messages system with JS-based messages
parent
ffe08f913b
commit
752f519ccc
|
@ -18,6 +18,13 @@ $configObject = new Config();
|
||||||
$isAjax = !empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
|
$isAjax = !empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
|
||||||
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
|
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
|
||||||
|
|
||||||
|
// Check if file is writable
|
||||||
|
$isWritable = is_writable($config_file);
|
||||||
|
$configMessage = '';
|
||||||
|
if (!$isWritable) {
|
||||||
|
$configMessage = Messages::render('ERROR', 'DEFAULT', 'Config file is not writable', false);
|
||||||
|
}
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
// Ensure no output before this point
|
// Ensure no output before this point
|
||||||
ob_clean();
|
ob_clean();
|
||||||
|
@ -39,16 +46,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if file is writable
|
|
||||||
if (!is_writable($config_file)) {
|
|
||||||
Messages::flash('ERROR', 'DEFAULT', 'Config file is not writable', true);
|
|
||||||
echo json_encode([
|
|
||||||
'success' => false,
|
|
||||||
'message' => 'Config file is not writable'
|
|
||||||
]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to update config file
|
// Try to update config file
|
||||||
$result = $configObject->editConfigFile($postData, $config_file);
|
$result = $configObject->editConfigFile($postData, $config_file);
|
||||||
if ($result === true) {
|
if ($result === true) {
|
||||||
|
@ -70,16 +67,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle non-AJAX POST
|
// Handle non-AJAX POST
|
||||||
if (!is_writable($config_file)) {
|
|
||||||
Messages::flash('ERROR', 'DEFAULT', 'Config file is not writable', true);
|
|
||||||
} else {
|
|
||||||
$result = $configObject->editConfigFile($_POST, $config_file);
|
$result = $configObject->editConfigFile($_POST, $config_file);
|
||||||
if ($result === true) {
|
if ($result === true) {
|
||||||
Messages::flash('NOTICE', 'DEFAULT', 'Config file updated successfully', true);
|
Messages::flash('NOTICE', 'DEFAULT', 'Config file updated successfully', true);
|
||||||
} else {
|
} else {
|
||||||
Messages::flash('ERROR', 'DEFAULT', "Error updating config file: $result", true);
|
Messages::flash('ERROR', 'DEFAULT', "Error updating config file: $result", true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
header('Location: ' . htmlspecialchars($app_root) . '?page=config');
|
header('Location: ' . htmlspecialchars($app_root) . '?page=config');
|
||||||
exit;
|
exit;
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col-12 mb-4">
|
<div class="col-12 mb-4">
|
||||||
<h2>Configuration</h2>
|
<h2>Configuration</h2>
|
||||||
|
<?php if ($configMessage): ?>
|
||||||
|
<?= $configMessage ?>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -16,7 +19,7 @@
|
||||||
</h5>
|
</h5>
|
||||||
<?php if ($userObject->hasRight($user_id, 'edit config file')): ?>
|
<?php if ($userObject->hasRight($user_id, 'edit config file')): ?>
|
||||||
<div>
|
<div>
|
||||||
<button type="button" class="btn btn-outline-primary btn-sm toggle-edit">
|
<button type="button" class="btn btn-outline-primary btn-sm toggle-edit" <?= !$isWritable ? 'disabled' : '' ?>>
|
||||||
<i class="fas fa-edit me-2"></i>Edit
|
<i class="fas fa-edit me-2"></i>Edit
|
||||||
</button>
|
</button>
|
||||||
<div class="edit-controls d-none">
|
<div class="edit-controls d-none">
|
||||||
|
@ -109,7 +112,7 @@
|
||||||
<script>
|
<script>
|
||||||
$(function() {
|
$(function() {
|
||||||
function showMessage(messageData) {
|
function showMessage(messageData) {
|
||||||
const dismissClass = messageData.dismissible ? ' alert-dismissible fade show' : '';
|
const dismissClass = messageData.dismissible ? ' alert-dismissible fade' : '';
|
||||||
const dismissButton = messageData.dismissible ?
|
const dismissButton = messageData.dismissible ?
|
||||||
`<button type="button" class="btn-close${messageData.small ? ' btn-close-sm' : ''}" data-bs-dismiss="alert" aria-label="Close"></button>` : '';
|
`<button type="button" class="btn-close${messageData.small ? ' btn-close-sm' : ''}" data-bs-dismiss="alert" aria-label="Close"></button>` : '';
|
||||||
const smallClass = messageData.small ? ' alert-sm' : '';
|
const smallClass = messageData.small ? ' alert-sm' : '';
|
||||||
|
@ -119,12 +122,22 @@ $(function() {
|
||||||
.attr('role', 'alert')
|
.attr('role', 'alert')
|
||||||
.html(`${messageData.message}${dismissButton}`);
|
.html(`${messageData.message}${dismissButton}`);
|
||||||
|
|
||||||
$('#messages-container').html($alert);
|
// Remove any existing alerts
|
||||||
|
$('#messages-container').empty().append($alert);
|
||||||
|
|
||||||
|
// Trigger reflow to ensure transition works
|
||||||
|
$alert[0].offsetHeight;
|
||||||
|
|
||||||
|
// Show the alert with transition
|
||||||
|
$alert.addClass('show');
|
||||||
|
|
||||||
if (messageData.dismissible) {
|
if (messageData.dismissible) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
$alert.alert('close');
|
$alert.removeClass('show');
|
||||||
}, 5000);
|
setTimeout(() => {
|
||||||
|
$alert.remove();
|
||||||
|
}, 200); // Same as transition duration
|
||||||
|
}, 1500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,6 +192,12 @@ $(function() {
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
// Show message first
|
||||||
|
if (response.messageData) {
|
||||||
|
showMessage(response.messageData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only update UI if save was successful
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
// Update view mode values
|
// Update view mode values
|
||||||
Object.entries(data).forEach(([key, value]) => {
|
Object.entries(data).forEach(([key, value]) => {
|
||||||
|
@ -219,11 +238,6 @@ $(function() {
|
||||||
$('.edit-mode').addClass('d-none');
|
$('.edit-mode').addClass('d-none');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show message
|
|
||||||
if (response.messageData) {
|
|
||||||
showMessage(response.messageData);
|
|
||||||
}
|
|
||||||
|
|
||||||
$btn.prop('disabled', false).html('<i class="fas fa-save me-2"></i>Save');
|
$btn.prop('disabled', false).html('<i class="fas fa-save me-2"></i>Save');
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="stylesheet" type="text/css" href="<?= htmlspecialchars($app_root) ?>static/bootstrap/bootstrap.min.css">
|
<link rel="stylesheet" type="text/css" href="<?= htmlspecialchars($app_root) ?>static/bootstrap/bootstrap.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="<?= htmlspecialchars($app_root) ?>static/css/main.css">
|
<link rel="stylesheet" type="text/css" href="<?= htmlspecialchars($app_root) ?>static/css/main.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="<?= htmlspecialchars($app_root) ?>static/css/messages.css">
|
||||||
<?php if ($page === 'logs') { ?>
|
<?php if ($page === 'logs') { ?>
|
||||||
<link rel="stylesheet" type="text/css" href="<?= htmlspecialchars($app_root) ?>static/css/logs.css">
|
<link rel="stylesheet" type="text/css" href="<?= htmlspecialchars($app_root) ?>static/css/logs.css">
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
#messages-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 40px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 1050;
|
||||||
|
width: auto;
|
||||||
|
min-width: 300px;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#messages-container .alert {
|
||||||
|
margin-bottom: 0;
|
||||||
|
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||||
|
background-color: rgba(var(--bs-light-rgb), 0.95);
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-20px);
|
||||||
|
transition: all 0.2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#messages-container .alert.show {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#messages-container .alert-success {
|
||||||
|
background-color: rgba(var(--bs-success-rgb), 0.95);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#messages-container .alert-danger {
|
||||||
|
background-color: rgba(var(--bs-danger-rgb), 0.95);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#messages-container .alert-info {
|
||||||
|
background-color: rgba(var(--bs-info-rgb), 0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
#messages-container .alert-warning {
|
||||||
|
background-color: rgba(var(--bs-warning-rgb), 0.95);
|
||||||
|
}
|
Loading…
Reference in New Issue