Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 79b3caa35a | |||
| 6102c8f590 | |||
| 88e53c5698 | |||
| ec1c3486c5 | |||
| 3742477aef | |||
| bb8e4a258a | |||
| e6d646011a | |||
| 726291995c |
@@ -5,7 +5,7 @@
|
|||||||
# FILE INFORMATION
|
# FILE INFORMATION
|
||||||
# DEFGROUP: Gitea.Workflow
|
# DEFGROUP: Gitea.Workflow
|
||||||
# INGROUP: mokocli.Automation
|
# INGROUP: mokocli.Automation
|
||||||
# VERSION: 01.43.00
|
# VERSION: 01.43.05
|
||||||
# BRIEF: Auto-create feature branch when an issue is opened
|
# BRIEF: Auto-create feature branch when an issue is opened
|
||||||
|
|
||||||
name: "Universal: Issue Branch"
|
name: "Universal: Issue Branch"
|
||||||
|
|||||||
@@ -245,7 +245,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
label="COM_MOKOJOOMBACKUP_CONFIG_NTFY_SERVER"
|
label="COM_MOKOJOOMBACKUP_CONFIG_NTFY_SERVER"
|
||||||
description="COM_MOKOJOOMBACKUP_CONFIG_NTFY_SERVER_DESC"
|
description="COM_MOKOJOOMBACKUP_CONFIG_NTFY_SERVER_DESC"
|
||||||
default="https://ntfy.sh"
|
default="https://ntfy.mokoconsulting.tech"
|
||||||
filter="url"
|
filter="url"
|
||||||
/>
|
/>
|
||||||
<field
|
<field
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
default="a.ordering ASC"
|
default="a.ordering ASC"
|
||||||
onchange="this.form.submit();"
|
onchange="this.form.submit();"
|
||||||
>
|
>
|
||||||
<option value="a.ordering ASC">JFIELD_ORDERING_LABEL_ASC</option>
|
<option value="a.ordering ASC">JFIELD_ORDERING_ASC</option>
|
||||||
<option value="a.title ASC">COM_MOKOJOOMBACKUP_HEADING_TITLE_ASC</option>
|
<option value="a.title ASC">COM_MOKOJOOMBACKUP_HEADING_TITLE_ASC</option>
|
||||||
<option value="a.title DESC">COM_MOKOJOOMBACKUP_HEADING_TITLE_DESC</option>
|
<option value="a.title DESC">COM_MOKOJOOMBACKUP_HEADING_TITLE_DESC</option>
|
||||||
<option value="a.id DESC">JGRID_HEADING_ID_DESC</option>
|
<option value="a.id DESC">JGRID_HEADING_ID_DESC</option>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
; @license GPL-3.0-or-later
|
; @license GPL-3.0-or-later
|
||||||
|
|
||||||
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
|
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
|
||||||
|
COM_MOKOJOOMBACKUP_CONFIGURATION="MokoSuiteBackup Options"
|
||||||
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla"
|
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla"
|
||||||
|
|
||||||
; Submenu
|
; Submenu
|
||||||
@@ -275,9 +276,9 @@ COM_MOKOJOOMBACKUP_FIELD_SFTP_PORT_DESC="SSH port (default: 22)"
|
|||||||
COM_MOKOJOOMBACKUP_FIELD_SFTP_USERNAME="SSH Username"
|
COM_MOKOJOOMBACKUP_FIELD_SFTP_USERNAME="SSH Username"
|
||||||
COM_MOKOJOOMBACKUP_FIELD_SFTP_USERNAME_DESC="Username for SSH authentication"
|
COM_MOKOJOOMBACKUP_FIELD_SFTP_USERNAME_DESC="Username for SSH authentication"
|
||||||
COM_MOKOJOOMBACKUP_FIELD_SFTP_PASSWORD="SSH Password"
|
COM_MOKOJOOMBACKUP_FIELD_SFTP_PASSWORD="SSH Password"
|
||||||
COM_MOKOJOOMBACKUP_FIELD_SFTP_PASSWORD_DESC="Password for SSH authentication. Leave blank if using a key file."
|
COM_MOKOJOOMBACKUP_FIELD_SFTP_PASSWORD_DESC="Password for SSH authentication."
|
||||||
COM_MOKOJOOMBACKUP_FIELD_SFTP_KEY="SSH Private Key"
|
COM_MOKOJOOMBACKUP_FIELD_SFTP_KEY="SSH Private Key"
|
||||||
COM_MOKOJOOMBACKUP_FIELD_SFTP_KEY_DESC="Upload your SSH private key (id_rsa, id_ed25519). Stored base64-encoded in DB, written to temp file during upload only. Leave blank for password auth."
|
COM_MOKOJOOMBACKUP_FIELD_SFTP_KEY_DESC="Upload your SSH private key (id_rsa, id_ed25519). Stored base64-encoded in DB, written to temp file during upload only."
|
||||||
COM_MOKOJOOMBACKUP_FIELD_SFTP_KEY_UPLOAD="Upload Key File"
|
COM_MOKOJOOMBACKUP_FIELD_SFTP_KEY_UPLOAD="Upload Key File"
|
||||||
COM_MOKOJOOMBACKUP_FIELD_SFTP_KEY_REPLACE="Replace Key"
|
COM_MOKOJOOMBACKUP_FIELD_SFTP_KEY_REPLACE="Replace Key"
|
||||||
COM_MOKOJOOMBACKUP_FIELD_SFTP_KEY_LOADED="Key loaded"
|
COM_MOKOJOOMBACKUP_FIELD_SFTP_KEY_LOADED="Key loaded"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="component" method="upgrade">
|
<extension type="component" method="upgrade">
|
||||||
<name>MokoSuiteBackup</name>
|
<name>MokoSuiteBackup</name>
|
||||||
<version>01.43.00</version>
|
<version>01.43.05</version>
|
||||||
<creationDate>2026-06-02</creationDate>
|
<creationDate>2026-06-02</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -1769,8 +1769,23 @@ async function post(action, extra) {
|
|||||||
form.append(k, v);
|
form.append(k, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const res = await fetch('restore.php', { method: 'POST', body: form });
|
var res;
|
||||||
return res.json();
|
try {
|
||||||
|
res = await fetch('restore.php', { method: 'POST', body: form });
|
||||||
|
} catch (e) {
|
||||||
|
log('Network error: ' + e.message);
|
||||||
|
return { success: false, message: 'Network error: ' + e.message, checks: [] };
|
||||||
|
}
|
||||||
|
if (!res.ok) {
|
||||||
|
log('Server error: HTTP ' + res.status);
|
||||||
|
return { success: false, message: 'Server error (HTTP ' + res.status + ')', checks: [] };
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return await res.json();
|
||||||
|
} catch (e) {
|
||||||
|
log('Invalid response from server (not JSON)');
|
||||||
|
return { success: false, message: 'Invalid server response — check PHP error log', checks: [] };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function goStep(n) {
|
function goStep(n) {
|
||||||
@@ -1845,7 +1860,17 @@ async function runPreflight() {
|
|||||||
setBtnLoading(btn, true);
|
setBtnLoading(btn, true);
|
||||||
log('Running pre-flight checks...');
|
log('Running pre-flight checks...');
|
||||||
|
|
||||||
|
try {
|
||||||
const r = await post('preflight');
|
const r = await post('preflight');
|
||||||
|
|
||||||
|
if (!r.success && !r.checks.length) {
|
||||||
|
log('Pre-flight error: ' + (r.message || 'Unknown error'));
|
||||||
|
setBtnLoading(btn, false);
|
||||||
|
btn.textContent = 'Re-check';
|
||||||
|
setStatus('checkList', r.message || 'Pre-flight check failed', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const list = document.getElementById('checkList');
|
const list = document.getElementById('checkList');
|
||||||
while (list.firstChild) list.removeChild(list.firstChild);
|
while (list.firstChild) list.removeChild(list.firstChild);
|
||||||
|
|
||||||
@@ -1882,6 +1907,11 @@ async function runPreflight() {
|
|||||||
btn.textContent = 'Re-check';
|
btn.textContent = 'Re-check';
|
||||||
log('Some checks failed');
|
log('Some checks failed');
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log('Pre-flight error: ' + e.message);
|
||||||
|
setBtnLoading(btn, false);
|
||||||
|
btn.textContent = 'Re-check';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
<select id="mb-profile-select" class="form-select" style="max-width:300px;">
|
<select id="mb-profile-select" class="form-select" style="max-width:300px;">
|
||||||
<?php foreach ($this->profiles as $profile) : ?>
|
<?php foreach ($this->profiles as $profile) : ?>
|
||||||
<option value="<?php echo (int) $profile->id; ?>">
|
<option value="<?php echo (int) $profile->id; ?>">
|
||||||
|
#<?php echo (int) $profile->id; ?> —
|
||||||
<?php echo $this->escape($profile->title); ?>
|
<?php echo $this->escape($profile->title); ?>
|
||||||
(<?php echo $this->escape($profile->backup_type); ?>)
|
(<?php echo $this->escape($profile->backup_type); ?>)
|
||||||
</option>
|
</option>
|
||||||
@@ -188,18 +189,24 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- Stepped Backup Modal (for shared hosting) -->
|
<!-- Stepped Backup Modal (for shared hosting) -->
|
||||||
<div id="mokosuitebackup-modal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.6); z-index:10000;">
|
<div class="modal fade" id="mokosuitebackup-modal" tabindex="-1" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
|
||||||
<div style="max-width:500px; margin:10% auto; background:#fff; border-radius:8px; padding:2rem; box-shadow:0 4px 20px rgba(0,0,0,0.3);">
|
<div class="modal-dialog">
|
||||||
<h3 id="mb-modal-title" style="margin:0 0 1rem;">Backup in Progress</h3>
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="mb-modal-title">Backup in Progress</h5>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
<div class="alert alert-warning py-1 px-2 mb-2" style="font-size:0.85rem;">
|
<div class="alert alert-warning py-1 px-2 mb-2" style="font-size:0.85rem;">
|
||||||
<span class="icon-warning-circle" aria-hidden="true"></span>
|
<span class="icon-warning-circle" aria-hidden="true"></span>
|
||||||
<strong>Do not navigate away or close this window</strong> while the backup is running.
|
<strong>Do not navigate away or close this window</strong> while the backup is running.
|
||||||
</div>
|
</div>
|
||||||
<div style="background:#e9ecef; border-radius:4px; overflow:hidden; height:24px; margin-bottom:0.5rem;">
|
<div class="progress mb-2" style="height:24px;">
|
||||||
<div id="mb-progress-bar" style="height:100%; background:#0d6efd; transition:width 0.3s; width:0%; display:flex; align-items:center; justify-content:center; color:#fff; font-size:0.8rem; font-weight:bold;">0%</div>
|
<div id="mb-progress-bar" class="progress-bar" role="progressbar" style="width:0%;">0%</div>
|
||||||
|
</div>
|
||||||
|
<p id="mb-status" class="text-muted mb-1" style="font-size:0.9rem;">Initializing...</p>
|
||||||
|
<p id="mb-phase" class="text-muted mb-0" style="font-size:0.8rem;">Phase: init</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p id="mb-status" style="color:#666; font-size:0.9rem; margin:0.5rem 0;">Initializing...</p>
|
|
||||||
<p id="mb-phase" style="color:#999; font-size:0.8rem; margin:0;">Phase: init</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -235,12 +242,12 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
|
|
||||||
function showModal() {
|
function showModal() {
|
||||||
backupRunning = true;
|
backupRunning = true;
|
||||||
document.getElementById('mokosuitebackup-modal').style.display = 'block';
|
bootstrap.Modal.getOrCreateInstance(document.getElementById('mokosuitebackup-modal')).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideModal() {
|
function hideModal() {
|
||||||
backupRunning = false;
|
backupRunning = false;
|
||||||
document.getElementById('mokosuitebackup-modal').style.display = 'none';
|
bootstrap.Modal.getInstance(document.getElementById('mokosuitebackup-modal'))?.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateProgress(progress, message, phase) {
|
function updateProgress(progress, message, phase) {
|
||||||
@@ -344,31 +351,26 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
document.getElementById('mb-restore-record-id').value = checked[0].value;
|
document.getElementById('mb-restore-record-id').value = checked[0].value;
|
||||||
document.getElementById('mb-restore-modal').style.display = 'block';
|
bootstrap.Modal.getOrCreateInstance(document.getElementById('mb-restore-modal')).show();
|
||||||
return false;
|
return false;
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Close restore modal
|
// Close restore modal handled by Bootstrap data-bs-dismiss
|
||||||
document.addEventListener('click', function(e) {
|
|
||||||
if (e.target.classList.contains('mb-restore-close') || e.target.id === 'mb-restore-modal') {
|
|
||||||
document.getElementById('mb-restore-modal').style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// AJAX stepped restore
|
// AJAX stepped restore
|
||||||
var restoreRunning = false;
|
var restoreRunning = false;
|
||||||
|
|
||||||
function showRestoreProgress() {
|
function showRestoreProgress() {
|
||||||
restoreRunning = true;
|
restoreRunning = true;
|
||||||
document.getElementById('mb-restore-modal').style.display = 'none';
|
bootstrap.Modal.getInstance(document.getElementById('mb-restore-modal'))?.hide();
|
||||||
document.getElementById('mb-restore-progress-modal').style.display = 'block';
|
bootstrap.Modal.getOrCreateInstance(document.getElementById('mb-restore-progress-modal')).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideRestoreProgress() {
|
function hideRestoreProgress() {
|
||||||
restoreRunning = false;
|
restoreRunning = false;
|
||||||
document.getElementById('mb-restore-progress-modal').style.display = 'none';
|
bootstrap.Modal.getInstance(document.getElementById('mb-restore-progress-modal'))?.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateRestoreProgress(progress, message, phase) {
|
function updateRestoreProgress(progress, message, phase) {
|
||||||
@@ -466,7 +468,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
var modal = document.getElementById('mb-log-modal');
|
var modal = document.getElementById('mb-log-modal');
|
||||||
var body = document.getElementById('mb-log-body');
|
var body = document.getElementById('mb-log-body');
|
||||||
body.textContent = 'Loading...';
|
body.textContent = 'Loading...';
|
||||||
modal.style.display = 'block';
|
bootstrap.Modal.getOrCreateInstance(modal).show();
|
||||||
|
|
||||||
var form = new URLSearchParams();
|
var form = new URLSearchParams();
|
||||||
form.append('task', 'ajax.viewLog');
|
form.append('task', 'ajax.viewLog');
|
||||||
@@ -491,11 +493,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('click', function(e) {
|
// Log modal close handled by Bootstrap data-bs-dismiss
|
||||||
if (e.target.id === 'mb-log-modal' || e.target.classList.contains('mb-log-close')) {
|
|
||||||
document.getElementById('mb-log-modal').style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Browse Archive modal handler
|
// Browse Archive modal handler
|
||||||
function formatFileSize(bytes) {
|
function formatFileSize(bytes) {
|
||||||
@@ -551,7 +549,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
var summary = document.getElementById('mb-browse-summary');
|
var summary = document.getElementById('mb-browse-summary');
|
||||||
browseSetMessage(tbody, 'Loading...');
|
browseSetMessage(tbody, 'Loading...');
|
||||||
summary.textContent = '';
|
summary.textContent = '';
|
||||||
modal.style.display = 'block';
|
bootstrap.Modal.getOrCreateInstance(modal).show();
|
||||||
|
|
||||||
postAjax({ task: 'ajax.browseArchive', id: recordId })
|
postAjax({ task: 'ajax.browseArchive', id: recordId })
|
||||||
.then(function(data) {
|
.then(function(data) {
|
||||||
@@ -578,24 +576,21 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('click', function(e) {
|
// Browse modal close handled by Bootstrap data-bs-dismiss
|
||||||
if (e.target.id === 'mb-browse-modal' || e.target.classList.contains('mb-browse-close')) {
|
|
||||||
document.getElementById('mb-browse-modal').style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Restore Confirmation Modal -->
|
<!-- Restore Confirmation Modal -->
|
||||||
<div id="mb-restore-modal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.6); z-index:10000;">
|
<div class="modal fade" id="mb-restore-modal" tabindex="-1" aria-hidden="true">
|
||||||
<div style="max-width:500px; margin:8% auto; background:#fff; border-radius:8px; box-shadow:0 4px 20px rgba(0,0,0,0.3);">
|
<div class="modal-dialog">
|
||||||
<div style="display:flex; justify-content:space-between; align-items:center; padding:1rem 1.5rem; border-bottom:1px solid #dee2e6;">
|
<div class="modal-content">
|
||||||
<h4 style="margin:0;"><?php echo Text::_('COM_MOKOJOOMBACKUP_TOOLBAR_RESTORE'); ?></h4>
|
<div class="modal-header">
|
||||||
<button type="button" class="btn-close mb-restore-close" aria-label="Close"></button>
|
<h5 class="modal-title"><?php echo Text::_('COM_MOKOJOOMBACKUP_TOOLBAR_RESTORE'); ?></h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<form action="<?php echo Route::_('index.php?option=com_mokosuitebackup&task=backups.restore'); ?>" method="post" id="mb-restore-form">
|
<form action="<?php echo Route::_('index.php?option=com_mokosuitebackup&task=backups.restore'); ?>" method="post" id="mb-restore-form">
|
||||||
<input type="hidden" name="id" id="mb-restore-record-id" value="">
|
<input type="hidden" name="id" id="mb-restore-record-id" value="">
|
||||||
<div style="padding:1.5rem;">
|
<div class="modal-body">
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger">
|
||||||
<span class="icon-warning-circle" aria-hidden="true"></span>
|
<span class="icon-warning-circle" aria-hidden="true"></span>
|
||||||
<strong><?php echo Text::_('COM_MOKOJOOMBACKUP_RESTORE_CONFIRM'); ?></strong>
|
<strong><?php echo Text::_('COM_MOKOJOOMBACKUP_RESTORE_CONFIRM'); ?></strong>
|
||||||
@@ -629,8 +624,8 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
placeholder="<?php echo Text::_('COM_MOKOJOOMBACKUP_RESTORE_PASSWORD_PLACEHOLDER'); ?>" autocomplete="off">
|
placeholder="<?php echo Text::_('COM_MOKOJOOMBACKUP_RESTORE_PASSWORD_PLACEHOLDER'); ?>" autocomplete="off">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:0 1.5rem 1.5rem; text-align:right;">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary mb-restore-close"><?php echo Text::_('JCANCEL'); ?></button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo Text::_('JCANCEL'); ?></button>
|
||||||
<button type="submit" class="btn btn-danger">
|
<button type="submit" class="btn btn-danger">
|
||||||
<span class="icon-upload" aria-hidden="true"></span>
|
<span class="icon-upload" aria-hidden="true"></span>
|
||||||
<?php echo Text::_('COM_MOKOJOOMBACKUP_TOOLBAR_RESTORE'); ?>
|
<?php echo Text::_('COM_MOKOJOOMBACKUP_TOOLBAR_RESTORE'); ?>
|
||||||
@@ -642,44 +637,53 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Restore Progress Modal -->
|
<!-- Restore Progress Modal -->
|
||||||
<div id="mb-restore-progress-modal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.6); z-index:10000;">
|
<div class="modal fade" id="mb-restore-progress-modal" tabindex="-1" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
|
||||||
<div style="max-width:500px; margin:10% auto; background:#fff; border-radius:8px; padding:2rem; box-shadow:0 4px 20px rgba(0,0,0,0.3);">
|
<div class="modal-dialog">
|
||||||
<h3 id="mb-restore-title" style="margin:0 0 1rem;">Restore in Progress</h3>
|
<div class="modal-content">
|
||||||
<div style="background:#e9ecef; border-radius:4px; overflow:hidden; height:24px; margin-bottom:0.5rem;">
|
<div class="modal-header">
|
||||||
<div id="mb-restore-progress-bar" style="height:100%; background:#dc3545; transition:width 0.3s; width:0%; display:flex; align-items:center; justify-content:center; color:#fff; font-size:0.8rem; font-weight:bold;">0%</div>
|
<h5 class="modal-title" id="mb-restore-title">Restore in Progress</h5>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="progress mb-2" style="height:24px;">
|
||||||
|
<div id="mb-restore-progress-bar" class="progress-bar bg-danger" role="progressbar" style="width:0%;">0%</div>
|
||||||
|
</div>
|
||||||
|
<p id="mb-restore-status" class="text-muted mb-1" style="font-size:0.9rem;">Initializing...</p>
|
||||||
|
<p id="mb-restore-phase" class="text-muted mb-0" style="font-size:0.8rem;">Phase: init</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p id="mb-restore-status" style="color:#666; font-size:0.9rem; margin:0.5rem 0;">Initializing...</p>
|
|
||||||
<p id="mb-restore-phase" style="color:#999; font-size:0.8rem; margin:0;">Phase: init</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Log Viewer Modal -->
|
<!-- Log Viewer Modal -->
|
||||||
<div id="mb-log-modal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.6); z-index:10000;">
|
<div class="modal fade" id="mb-log-modal" tabindex="-1" aria-hidden="true">
|
||||||
<div style="max-width:700px; margin:5% auto; background:#fff; border-radius:8px; box-shadow:0 4px 20px rgba(0,0,0,0.3); display:flex; flex-direction:column; max-height:80vh;">
|
<div class="modal-dialog modal-lg">
|
||||||
<div style="display:flex; justify-content:space-between; align-items:center; padding:1rem 1.5rem; border-bottom:1px solid #dee2e6;">
|
<div class="modal-content">
|
||||||
<h4 style="margin:0;"><?php echo Text::_('COM_MOKOJOOMBACKUP_VIEW_LOG'); ?></h4>
|
<div class="modal-header">
|
||||||
<button type="button" class="btn-close mb-log-close" aria-label="Close"></button>
|
<h5 class="modal-title"><?php echo Text::_('COM_MOKOJOOMBACKUP_VIEW_LOG'); ?></h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:1rem 1.5rem; overflow-y:auto; flex:1;">
|
<div class="modal-body" style="max-height:60vh; overflow-y:auto;">
|
||||||
<pre id="mb-log-body" style="white-space:pre-wrap; word-break:break-word; font-size:0.85rem; margin:0; background:#f8f9fa; padding:1rem; border-radius:4px;"></pre>
|
<pre id="mb-log-body" style="white-space:pre-wrap; word-break:break-word; font-size:0.85rem; margin:0; background:#f8f9fa; padding:1rem; border-radius:4px;"></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Archive Browser Modal -->
|
<!-- Archive Browser Modal -->
|
||||||
<div id="mb-browse-modal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.6); z-index:10000;">
|
<div class="modal fade" id="mb-browse-modal" tabindex="-1" aria-hidden="true">
|
||||||
<div style="max-width:800px; margin:5% auto; background:#fff; border-radius:8px; box-shadow:0 4px 20px rgba(0,0,0,0.3); display:flex; flex-direction:column; max-height:80vh;">
|
<div class="modal-dialog modal-lg">
|
||||||
<div style="display:flex; justify-content:space-between; align-items:center; padding:1rem 1.5rem; border-bottom:1px solid #dee2e6;">
|
<div class="modal-content">
|
||||||
<h4 style="margin:0;">
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">
|
||||||
<span class="icon-folder-open" aria-hidden="true"></span>
|
<span class="icon-folder-open" aria-hidden="true"></span>
|
||||||
<?php echo Text::_('COM_MOKOJOOMBACKUP_BROWSE_ARCHIVE'); ?>
|
<?php echo Text::_('COM_MOKOJOOMBACKUP_BROWSE_ARCHIVE'); ?>
|
||||||
</h4>
|
</h5>
|
||||||
<button type="button" class="btn-close mb-browse-close" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:0.75rem 1.5rem; border-bottom:1px solid #dee2e6; background:#f8f9fa;">
|
<div class="modal-body p-0">
|
||||||
|
<div class="px-3 py-2 bg-light border-bottom">
|
||||||
<small id="mb-browse-summary" class="text-muted"></small>
|
<small id="mb-browse-summary" class="text-muted"></small>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:0; overflow-y:auto; flex:1;">
|
<div style="max-height:60vh; overflow-y:auto;">
|
||||||
<table class="table table-sm table-striped mb-0">
|
<table class="table table-sm table-striped mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -694,21 +698,24 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Purge Backups Modal -->
|
<!-- Purge Backups Modal -->
|
||||||
<?php $canDelete = $user->authorise('core.delete', 'com_mokosuitebackup'); ?>
|
<?php $canDelete = $user->authorise('core.delete', 'com_mokosuitebackup'); ?>
|
||||||
<?php if ($canDelete) : ?>
|
<?php if ($canDelete) : ?>
|
||||||
<div id="mb-purge-modal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.6); z-index:10000;">
|
<div class="modal fade" id="mb-purge-modal" tabindex="-1" aria-hidden="true">
|
||||||
<div style="max-width:500px; margin:8% auto; background:#fff; border-radius:8px; box-shadow:0 4px 20px rgba(0,0,0,0.3);">
|
<div class="modal-dialog">
|
||||||
<div style="display:flex; justify-content:space-between; align-items:center; padding:1rem 1.5rem; border-bottom:1px solid #dee2e6;">
|
<div class="modal-content">
|
||||||
<h4 style="margin:0;">
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">
|
||||||
<span class="icon-trash" aria-hidden="true"></span>
|
<span class="icon-trash" aria-hidden="true"></span>
|
||||||
<?php echo Text::_('COM_MOKOJOOMBACKUP_PURGE_TITLE'); ?>
|
<?php echo Text::_('COM_MOKOJOOMBACKUP_PURGE_TITLE'); ?>
|
||||||
</h4>
|
</h5>
|
||||||
<button type="button" class="btn-close mb-purge-close" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<form action="<?php echo Route::_('index.php?option=com_mokosuitebackup&task=backups.purge'); ?>" method="post" id="mb-purge-form">
|
<form action="<?php echo Route::_('index.php?option=com_mokosuitebackup&task=backups.purge'); ?>" method="post" id="mb-purge-form">
|
||||||
<div style="padding:1.5rem;">
|
<div class="modal-body">
|
||||||
<p><?php echo Text::_('COM_MOKOJOOMBACKUP_PURGE_DESC'); ?></p>
|
<p><?php echo Text::_('COM_MOKOJOOMBACKUP_PURGE_DESC'); ?></p>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="mb-purge-date" class="form-label fw-bold"><?php echo Text::_('COM_MOKOJOOMBACKUP_PURGE_DATE_LABEL'); ?></label>
|
<label for="mb-purge-date" class="form-label fw-bold"><?php echo Text::_('COM_MOKOJOOMBACKUP_PURGE_DATE_LABEL'); ?></label>
|
||||||
@@ -721,8 +728,8 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
<div class="alert alert-info mb-0"><?php echo Text::_('COM_MOKOJOOMBACKUP_PURGE_NONE_FOUND'); ?></div>
|
<div class="alert alert-info mb-0"><?php echo Text::_('COM_MOKOJOOMBACKUP_PURGE_NONE_FOUND'); ?></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:0 1.5rem 1.5rem; text-align:right;">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary mb-purge-close"><?php echo Text::_('JCANCEL'); ?></button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo Text::_('JCANCEL'); ?></button>
|
||||||
<button type="submit" class="btn btn-danger" id="mb-purge-submit" disabled>
|
<button type="submit" class="btn btn-danger" id="mb-purge-submit" disabled>
|
||||||
<span class="icon-trash" aria-hidden="true"></span>
|
<span class="icon-trash" aria-hidden="true"></span>
|
||||||
<?php echo Text::_('COM_MOKOJOOMBACKUP_PURGE_SUBMIT'); ?>
|
<?php echo Text::_('COM_MOKOJOOMBACKUP_PURGE_SUBMIT'); ?>
|
||||||
@@ -732,20 +739,22 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<!-- Backup Comparison Modal -->
|
<!-- Backup Comparison Modal -->
|
||||||
<div id="mb-compare-modal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.6); z-index:10000;">
|
<div class="modal fade" id="mb-compare-modal" tabindex="-1" aria-hidden="true">
|
||||||
<div style="max-width:800px; margin:5% auto; background:#fff; border-radius:8px; box-shadow:0 4px 20px rgba(0,0,0,0.3); display:flex; flex-direction:column; max-height:85vh;">
|
<div class="modal-dialog modal-lg">
|
||||||
<div style="display:flex; justify-content:space-between; align-items:center; padding:1rem 1.5rem; border-bottom:1px solid #dee2e6;">
|
<div class="modal-content">
|
||||||
<h4 style="margin:0;">
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">
|
||||||
<span class="icon-copy" aria-hidden="true"></span>
|
<span class="icon-copy" aria-hidden="true"></span>
|
||||||
<?php echo Text::_('COM_MOKOJOOMBACKUP_COMPARE_TITLE'); ?>
|
<?php echo Text::_('COM_MOKOJOOMBACKUP_COMPARE_TITLE'); ?>
|
||||||
</h4>
|
</h5>
|
||||||
<button type="button" class="btn-close mb-compare-close" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:1rem 1.5rem; overflow-y:auto; flex:1;">
|
<div class="modal-body" style="max-height:65vh; overflow-y:auto;">
|
||||||
<div id="mb-compare-loading" style="text-align:center; padding:2rem;">
|
<div id="mb-compare-loading" class="text-center py-4">
|
||||||
<span class="icon-spinner icon-spin" aria-hidden="true"></span>
|
<span class="icon-spinner icon-spin" aria-hidden="true"></span>
|
||||||
<?php echo Text::_('COM_MOKOJOOMBACKUP_COMPARE_LOADING'); ?>
|
<?php echo Text::_('COM_MOKOJOOMBACKUP_COMPARE_LOADING'); ?>
|
||||||
</div>
|
</div>
|
||||||
@@ -764,6 +773,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
(function() {
|
(function() {
|
||||||
@@ -807,7 +817,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
var table = document.getElementById('mb-compare-table');
|
var table = document.getElementById('mb-compare-table');
|
||||||
var body = document.getElementById('mb-compare-body');
|
var body = document.getElementById('mb-compare-body');
|
||||||
|
|
||||||
modal.style.display = 'block';
|
bootstrap.Modal.getOrCreateInstance(modal).show();
|
||||||
loading.style.display = 'block';
|
loading.style.display = 'block';
|
||||||
errorEl.style.display = 'none';
|
errorEl.style.display = 'none';
|
||||||
table.style.display = 'none';
|
table.style.display = 'none';
|
||||||
@@ -874,12 +884,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close compare modal
|
// Compare modal close handled by Bootstrap data-bs-dismiss
|
||||||
document.addEventListener('click', function(e) {
|
|
||||||
if (e.target.id === 'mb-compare-modal' || e.target.classList.contains('mb-compare-close')) {
|
|
||||||
document.getElementById('mb-compare-modal').style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Intercept Compare toolbar button
|
// Intercept Compare toolbar button
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
@@ -922,7 +927,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
document.getElementById('mb-purge-count-wrapper').style.display = 'none';
|
document.getElementById('mb-purge-count-wrapper').style.display = 'none';
|
||||||
document.getElementById('mb-purge-none-wrapper').style.display = 'none';
|
document.getElementById('mb-purge-none-wrapper').style.display = 'none';
|
||||||
document.getElementById('mb-purge-submit').disabled = true;
|
document.getElementById('mb-purge-submit').disabled = true;
|
||||||
document.getElementById('mb-purge-modal').style.display = 'block';
|
bootstrap.Modal.getOrCreateInstance(document.getElementById('mb-purge-modal')).show();
|
||||||
return false;
|
return false;
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
@@ -936,12 +941,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close modal
|
// Purge modal close handled by Bootstrap data-bs-dismiss
|
||||||
document.addEventListener('click', function(e) {
|
|
||||||
if (e.target.id === 'mb-purge-modal' || e.target.classList.contains('mb-purge-close')) {
|
|
||||||
document.getElementById('mb-purge-modal').style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Confirm on submit
|
// Confirm on submit
|
||||||
var purgeForm = document.getElementById('mb-purge-form');
|
var purgeForm = document.getElementById('mb-purge-form');
|
||||||
|
|||||||
@@ -238,6 +238,7 @@ document.querySelectorAll('.mb-tile').forEach(function(tile) {
|
|||||||
<select id="mb-profile-select" class="form-select mb-2">
|
<select id="mb-profile-select" class="form-select mb-2">
|
||||||
<?php foreach ($this->profiles as $profile) : ?>
|
<?php foreach ($this->profiles as $profile) : ?>
|
||||||
<option value="<?php echo (int) $profile->id; ?>">
|
<option value="<?php echo (int) $profile->id; ?>">
|
||||||
|
#<?php echo (int) $profile->id; ?> —
|
||||||
<?php echo $this->escape($profile->title); ?>
|
<?php echo $this->escape($profile->title); ?>
|
||||||
(<?php echo $this->escape($profile->backup_type); ?>)
|
(<?php echo $this->escape($profile->backup_type); ?>)
|
||||||
</option>
|
</option>
|
||||||
|
|||||||
@@ -132,14 +132,15 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- Create Snapshot Modal -->
|
<!-- Create Snapshot Modal -->
|
||||||
<div id="mb-snapshot-create-modal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.6); z-index:10000;">
|
<div class="modal fade" id="mb-snapshot-create-modal" tabindex="-1" aria-hidden="true">
|
||||||
<div style="max-width:500px; margin:8% auto; background:#fff; border-radius:8px; box-shadow:0 4px 20px rgba(0,0,0,0.3);">
|
<div class="modal-dialog">
|
||||||
<div style="display:flex; justify-content:space-between; align-items:center; padding:1rem 1.5rem; border-bottom:1px solid #dee2e6;">
|
<div class="modal-content">
|
||||||
<h4 style="margin:0;"><?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_CREATE'); ?></h4>
|
<div class="modal-header">
|
||||||
<button type="button" class="btn-close mb-modal-close" aria-label="Close"></button>
|
<h5 class="modal-title"><?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_CREATE'); ?></h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<form action="<?php echo Route::_('index.php?option=com_mokosuitebackup&task=snapshots.create'); ?>" method="post" id="mb-snapshot-create-form">
|
<form action="<?php echo Route::_('index.php?option=com_mokosuitebackup&task=snapshots.create'); ?>" method="post" id="mb-snapshot-create-form">
|
||||||
<div style="padding:1.5rem;">
|
<div class="modal-body">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="mb-snap-desc" class="form-label fw-bold"><?php echo Text::_('COM_MOKOJOOMBACKUP_HEADING_DESCRIPTION'); ?></label>
|
<label for="mb-snap-desc" class="form-label fw-bold"><?php echo Text::_('COM_MOKOJOOMBACKUP_HEADING_DESCRIPTION'); ?></label>
|
||||||
<input type="text" class="form-control" id="mb-snap-desc" name="description" placeholder="<?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_DESC_PLACEHOLDER'); ?>">
|
<input type="text" class="form-control" id="mb-snap-desc" name="description" placeholder="<?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_DESC_PLACEHOLDER'); ?>">
|
||||||
@@ -169,8 +170,8 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:0 1.5rem 1.5rem; text-align:right;">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary mb-modal-close"><?php echo Text::_('JCANCEL'); ?></button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo Text::_('JCANCEL'); ?></button>
|
||||||
<button type="submit" class="btn btn-primary">
|
<button type="submit" class="btn btn-primary">
|
||||||
<span class="icon-camera" aria-hidden="true"></span>
|
<span class="icon-camera" aria-hidden="true"></span>
|
||||||
<?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_CREATE'); ?>
|
<?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_CREATE'); ?>
|
||||||
@@ -180,17 +181,19 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Restore Snapshot Modal -->
|
<!-- Restore Snapshot Modal -->
|
||||||
<div id="mb-snapshot-restore-modal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.6); z-index:10000;">
|
<div class="modal fade" id="mb-snapshot-restore-modal" tabindex="-1" aria-hidden="true">
|
||||||
<div style="max-width:500px; margin:8% auto; background:#fff; border-radius:8px; box-shadow:0 4px 20px rgba(0,0,0,0.3);">
|
<div class="modal-dialog">
|
||||||
<div style="display:flex; justify-content:space-between; align-items:center; padding:1rem 1.5rem; border-bottom:1px solid #dee2e6;">
|
<div class="modal-content">
|
||||||
<h4 style="margin:0;"><?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_RESTORE'); ?></h4>
|
<div class="modal-header">
|
||||||
<button type="button" class="btn-close mb-modal-close" aria-label="Close"></button>
|
<h5 class="modal-title"><?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_RESTORE'); ?></h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<form action="<?php echo Route::_('index.php?option=com_mokosuitebackup&task=snapshots.restore'); ?>" method="post" id="mb-snapshot-restore-form">
|
<form action="<?php echo Route::_('index.php?option=com_mokosuitebackup&task=snapshots.restore'); ?>" method="post" id="mb-snapshot-restore-form">
|
||||||
<input type="hidden" name="id" id="mb-restore-id" value="">
|
<input type="hidden" name="id" id="mb-restore-id" value="">
|
||||||
<div style="padding:1.5rem;">
|
<div class="modal-body">
|
||||||
<p id="mb-restore-desc" class="fw-bold"></p>
|
<p id="mb-restore-desc" class="fw-bold"></p>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@@ -213,7 +216,6 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
|
|
||||||
<div class="mb-3" id="mb-restore-types-container">
|
<div class="mb-3" id="mb-restore-types-container">
|
||||||
<label class="form-label fw-bold"><?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_RESTORE_TYPES'); ?></label>
|
<label class="form-label fw-bold"><?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_RESTORE_TYPES'); ?></label>
|
||||||
<!-- Populated by JS from data-types -->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="alert alert-warning mb-0" id="mb-replace-warning">
|
<div class="alert alert-warning mb-0" id="mb-replace-warning">
|
||||||
@@ -221,8 +223,8 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
<?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_REPLACE_WARNING'); ?>
|
<?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_REPLACE_WARNING'); ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:0 1.5rem 1.5rem; text-align:right;">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary mb-modal-close"><?php echo Text::_('JCANCEL'); ?></button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo Text::_('JCANCEL'); ?></button>
|
||||||
<button type="submit" class="btn btn-danger">
|
<button type="submit" class="btn btn-danger">
|
||||||
<span class="icon-upload" aria-hidden="true"></span>
|
<span class="icon-upload" aria-hidden="true"></span>
|
||||||
<?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_RESTORE'); ?>
|
<?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_RESTORE'); ?>
|
||||||
@@ -232,17 +234,19 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Browse Snapshot Detail Modal -->
|
<!-- Browse Snapshot Detail Modal -->
|
||||||
<div id="mb-snapshot-browse-modal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.6); z-index:10000;">
|
<div class="modal fade" id="mb-snapshot-browse-modal" tabindex="-1" aria-hidden="true">
|
||||||
<div style="max-width:800px; margin:5% auto; background:#fff; border-radius:8px; box-shadow:0 4px 20px rgba(0,0,0,0.3); max-height:80vh; display:flex; flex-direction:column;">
|
<div class="modal-dialog modal-xl">
|
||||||
<div style="display:flex; justify-content:space-between; align-items:center; padding:1rem 1.5rem; border-bottom:1px solid #dee2e6;">
|
<div class="modal-content">
|
||||||
<h4 style="margin:0;" id="mb-browse-title"><?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_BROWSE'); ?></h4>
|
<div class="modal-header">
|
||||||
<button type="button" class="btn-close mb-modal-close" aria-label="Close"></button>
|
<h5 class="modal-title" id="mb-browse-title"><?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_BROWSE'); ?></h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<form action="<?php echo Route::_('index.php?option=com_mokosuitebackup&task=snapshots.restoreSelected'); ?>" method="post" id="mb-snapshot-browse-form">
|
<form action="<?php echo Route::_('index.php?option=com_mokosuitebackup&task=snapshots.restoreSelected'); ?>" method="post" id="mb-snapshot-browse-form">
|
||||||
<input type="hidden" name="id" id="mb-browse-id" value="">
|
<input type="hidden" name="id" id="mb-browse-id" value="">
|
||||||
<div style="padding:1rem 1.5rem; overflow-y:auto; flex:1;">
|
<div class="modal-body" style="max-height:60vh; overflow-y:auto;">
|
||||||
<div id="mb-browse-loading" class="text-center py-4">
|
<div id="mb-browse-loading" class="text-center py-4">
|
||||||
<span class="spinner-border spinner-border-sm" role="status"></span>
|
<span class="spinner-border spinner-border-sm" role="status"></span>
|
||||||
<?php echo Text::_('COM_MOKOJOOMBACKUP_LOADING'); ?>
|
<?php echo Text::_('COM_MOKOJOOMBACKUP_LOADING'); ?>
|
||||||
@@ -331,8 +335,8 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:0.75rem 1.5rem; border-top:1px solid #dee2e6; text-align:right;">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary mb-modal-close"><?php echo Text::_('JCANCEL'); ?></button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><?php echo Text::_('JCANCEL'); ?></button>
|
||||||
<button type="submit" class="btn btn-success" id="mb-browse-restore-btn" disabled>
|
<button type="submit" class="btn btn-success" id="mb-browse-restore-btn" disabled>
|
||||||
<span class="icon-upload" aria-hidden="true"></span>
|
<span class="icon-upload" aria-hidden="true"></span>
|
||||||
<?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_RESTORE_SELECTED'); ?>
|
<?php echo Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_RESTORE_SELECTED'); ?>
|
||||||
@@ -342,6 +346,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
(function() {
|
(function() {
|
||||||
@@ -352,7 +357,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
createBtn.addEventListener('click', function(e) {
|
createBtn.addEventListener('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
document.getElementById('mb-snapshot-create-modal').style.display = 'block';
|
bootstrap.Modal.getOrCreateInstance(document.getElementById('mb-snapshot-create-modal')).show();
|
||||||
return false;
|
return false;
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
@@ -413,7 +418,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
// Show/hide replace warning based on mode
|
// Show/hide replace warning based on mode
|
||||||
toggleReplaceWarning();
|
toggleReplaceWarning();
|
||||||
|
|
||||||
document.getElementById('mb-snapshot-restore-modal').style.display = 'block';
|
bootstrap.Modal.getOrCreateInstance(document.getElementById('mb-snapshot-restore-modal')).show();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Toggle warning when mode changes
|
// Toggle warning when mode changes
|
||||||
@@ -454,7 +459,7 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
tab.show();
|
tab.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('mb-snapshot-browse-modal').style.display = 'block';
|
bootstrap.Modal.getOrCreateInstance(document.getElementById('mb-snapshot-browse-modal')).show();
|
||||||
|
|
||||||
// Fetch snapshot content via AJAX
|
// Fetch snapshot content via AJAX
|
||||||
var token = <?php echo json_encode(Session::getFormToken()); ?>;
|
var token = <?php echo json_encode(Session::getFormToken()); ?>;
|
||||||
@@ -617,16 +622,6 @@ $listDirn = $this->escape($this->state->get('list.direction'));
|
|||||||
: <?php echo json_encode(Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_RESTORE_SELECTED')); ?>;
|
: <?php echo json_encode(Text::_('COM_MOKOJOOMBACKUP_SNAPSHOT_RESTORE_SELECTED')); ?>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close modals
|
// Modal close handled by Bootstrap data-bs-dismiss
|
||||||
document.addEventListener('click', function(e) {
|
|
||||||
if (e.target.classList.contains('mb-modal-close') ||
|
|
||||||
e.target.id === 'mb-snapshot-create-modal' ||
|
|
||||||
e.target.id === 'mb-snapshot-restore-modal' ||
|
|
||||||
e.target.id === 'mb-snapshot-browse-modal') {
|
|
||||||
document.getElementById('mb-snapshot-create-modal').style.display = 'none';
|
|
||||||
document.getElementById('mb-snapshot-restore-modal').style.display = 'none';
|
|
||||||
document.getElementById('mb-snapshot-browse-modal').style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="module" client="administrator" method="upgrade">
|
<extension type="module" client="administrator" method="upgrade">
|
||||||
<name>mod_mokosuitebackup_cpanel</name>
|
<name>mod_mokosuitebackup_cpanel</name>
|
||||||
<version>01.43.00</version>
|
<version>01.43.05</version>
|
||||||
<creationDate>2026-06-23</creationDate>
|
<creationDate>2026-06-23</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ $moduleId = 'mod-msb-cpanel-' . $displayData['module']->id;
|
|||||||
class="btn btn-sm btn-outline-primary msb-cpanel-backup-btn"
|
class="btn btn-sm btn-outline-primary msb-cpanel-backup-btn"
|
||||||
data-profile-id="<?php echo (int) $profile->id; ?>"
|
data-profile-id="<?php echo (int) $profile->id; ?>"
|
||||||
data-module-id="<?php echo $moduleId; ?>">
|
data-module-id="<?php echo $moduleId; ?>">
|
||||||
<?php echo htmlspecialchars($profile->title); ?>
|
#<?php echo (int) $profile->id; ?> <?php echo htmlspecialchars($profile->title); ?>
|
||||||
<span class="badge bg-secondary ms-1"><?php echo htmlspecialchars($profile->backup_type); ?></span>
|
<span class="badge bg-secondary ms-1"><?php echo htmlspecialchars($profile->backup_type); ?></span>
|
||||||
</button>
|
</button>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="actionlog" method="upgrade">
|
<extension type="plugin" group="actionlog" method="upgrade">
|
||||||
<name>Action Log - MokoSuiteBackup</name>
|
<name>Action Log - MokoSuiteBackup</name>
|
||||||
<version>01.43.00</version>
|
<version>01.43.05</version>
|
||||||
<creationDate>2026-06-04</creationDate>
|
<creationDate>2026-06-04</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="console" method="upgrade">
|
<extension type="plugin" group="console" method="upgrade">
|
||||||
<name>Console - MokoSuiteBackup</name>
|
<name>Console - MokoSuiteBackup</name>
|
||||||
<version>01.43.00</version>
|
<version>01.43.05</version>
|
||||||
<creationDate>2026-06-04</creationDate>
|
<creationDate>2026-06-04</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="content" method="upgrade">
|
<extension type="plugin" group="content" method="upgrade">
|
||||||
<name>Content - MokoSuiteBackup</name>
|
<name>Content - MokoSuiteBackup</name>
|
||||||
<version>01.43.00</version>
|
<version>01.43.05</version>
|
||||||
<creationDate>2026-06-04</creationDate>
|
<creationDate>2026-06-04</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<extension type="plugin" group="quickicon" method="upgrade">
|
<extension type="plugin" group="quickicon" method="upgrade">
|
||||||
<name>Quick Icon - MokoSuiteBackup</name>
|
<name>Quick Icon - MokoSuiteBackup</name>
|
||||||
<version>01.43.00</version>
|
<version>01.43.05</version>
|
||||||
<creationDate>2026-06-02</creationDate>
|
<creationDate>2026-06-02</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="system" method="upgrade">
|
<extension type="plugin" group="system" method="upgrade">
|
||||||
<name>System - MokoSuiteBackup</name>
|
<name>System - MokoSuiteBackup</name>
|
||||||
<version>01.43.00</version>
|
<version>01.43.05</version>
|
||||||
<creationDate>2026-06-02</creationDate>
|
<creationDate>2026-06-02</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="task" method="upgrade">
|
<extension type="plugin" group="task" method="upgrade">
|
||||||
<name>Task - MokoSuiteBackup</name>
|
<name>Task - MokoSuiteBackup</name>
|
||||||
<version>01.43.00</version>
|
<version>01.43.05</version>
|
||||||
<creationDate>2026-06-02</creationDate>
|
<creationDate>2026-06-02</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
<extension type="plugin" group="webservices" method="upgrade">
|
<extension type="plugin" group="webservices" method="upgrade">
|
||||||
<name>Web Services - MokoSuiteBackup</name>
|
<name>Web Services - MokoSuiteBackup</name>
|
||||||
<version>01.43.00</version>
|
<version>01.43.05</version>
|
||||||
<creationDate>2026-06-02</creationDate>
|
<creationDate>2026-06-02</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<extension type="package" method="upgrade">
|
<extension type="package" method="upgrade">
|
||||||
<name>Package - MokoSuiteBackup</name>
|
<name>Package - MokoSuiteBackup</name>
|
||||||
<packagename>mokosuitebackup</packagename>
|
<packagename>mokosuitebackup</packagename>
|
||||||
<version>01.43.00</version>
|
<version>01.43.05</version>
|
||||||
<creationDate>2026-06-02</creationDate>
|
<creationDate>2026-06-02</creationDate>
|
||||||
<author>Moko Consulting</author>
|
<author>Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
|
|||||||
Reference in New Issue
Block a user