Files
MokoSuiteClient/source/packages/mod_mokosuiteclient_cache/tmpl/default.php
T
jmiller e563d08543
Universal: Auto Version Bump / Version Bump (push) Successful in 10s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 24s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 39s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
feat: SupportPinHelper, 4-button status bar, help buttons, PIN in heartbeat
- Add shared SupportPinHelper for consistent PIN generation across
  dashboard, cpanel module, cache module, and AJAX controller
- Cache module status bar now has 4 buttons: Site (frontend link),
  Support PIN, Clear Cache, Clear Temp
- Add ToolbarHelper::help() to all 10 admin views pointing to
  Gitea wiki pages
- Include support PIN in heartbeat payload to MokoSuiteHQ
- Fix license plugin missing src/ and language/ directories
- Refactor dashboard and cpanel module to use SupportPinHelper
2026-06-25 08:31:21 -05:00

147 lines
5.4 KiB
PHP

<?php
/**
* MokoSuiteClient Cache & Temp Cleaner — status bar split button
*
* 4 buttons: Frontend link | Support PIN | Clear Cache | Clear Temp
*/
defined('_JEXEC') or die;
use Joomla\CMS\Session\Session;
$token = Session::getFormToken();
$cacheUrl = 'index.php?option=com_mokosuiteclient&task=display.clearCache&format=json';
$tempUrl = 'index.php?option=com_mokosuiteclient&task=display.clearTemp&format=json';
$pinUrl = 'index.php?option=com_mokosuiteclient&task=display.requestPin&format=json';
$pinAvailable = $supportPinAvailable ?? false;
$pin = $supportPin ?? '';
$frontendUrl = $frontendUrl ?? '';
?>
<div class="header-item">
<div class="header-item-content d-flex align-items-center gap-0" style="padding:0;">
<?php if ($frontendUrl): ?>
<a href="<?php echo htmlspecialchars($frontendUrl); ?>" target="_blank" rel="noopener" class="btn btn-sm btn-outline-success rounded-0 rounded-start border-end-0 d-flex align-items-center gap-1 px-3 py-2" title="Open frontend" style="font-size:0.8rem;">
<span class="icon-external-link-alt" aria-hidden="true"></span> Site
</a>
<?php endif; ?>
<?php if ($pinAvailable): ?>
<a href="#" class="btn btn-sm btn-outline-secondary <?php echo $frontendUrl ? 'rounded-0 border-end-0' : 'rounded-0 rounded-start border-end-0'; ?> d-flex align-items-center gap-1 px-3 py-2" id="mokosuiteclient-pin" title="<?php echo $pin ? 'Support PIN — click to copy' : 'Request support PIN'; ?>" style="font-size:0.8rem;">
<span class="icon-key" aria-hidden="true" id="mokosuiteclient-pin-icon"></span>
<span id="mokosuiteclient-pin-text"><?php echo $pin ? htmlspecialchars($pin) : 'PIN'; ?></span>
</a>
<?php endif; ?>
<a href="#" class="btn btn-sm btn-outline-primary <?php echo ($pinAvailable || $frontendUrl) ? 'rounded-0 border-end-0' : 'rounded-0 rounded-start border-end-0'; ?> d-flex align-items-center gap-1 px-3 py-2" id="mokosuiteclient-clear-cache" title="Clear all Joomla cache" style="font-size:0.8rem;">
<span class="icon-bolt" aria-hidden="true" id="mokosuiteclient-cache-icon"></span> Cache
</a>
<a href="#" class="btn btn-sm btn-outline-danger rounded-0 rounded-end d-flex align-items-center gap-1 px-3 py-2" id="mokosuiteclient-clear-temp" title="Clear temp directory" style="font-size:0.8rem;">
<span class="icon-trash" aria-hidden="true" id="mokosuiteclient-temp-icon"></span> Temp
</a>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
function setupCleaner(btnId, iconId, url, token) {
var btn = document.getElementById(btnId);
var icon = document.getElementById(iconId);
if (!btn || !icon) return;
var origClass = icon.className;
btn.addEventListener('click', function(e) {
e.preventDefault();
if (btn.dataset.busy) return;
btn.dataset.busy = '1';
icon.className = 'icon-spinner icon-spin';
var formData = new FormData();
formData.append(token, '1');
fetch(url, {
method: 'POST',
headers: {'X-Requested-With': 'XMLHttpRequest'},
body: formData
})
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.success) {
icon.className = 'icon-check';
icon.style.color = '#198754';
} else {
icon.className = 'icon-times';
icon.style.color = '#dc3545';
}
setTimeout(function() {
icon.className = origClass;
icon.style.color = '';
delete btn.dataset.busy;
}, 2000);
})
.catch(function() {
icon.className = 'icon-times';
icon.style.color = '#dc3545';
setTimeout(function() {
icon.className = origClass;
icon.style.color = '';
delete btn.dataset.busy;
}, 2000);
});
});
}
setupCleaner('mokosuiteclient-clear-cache', 'mokosuiteclient-cache-icon', '<?php echo $cacheUrl; ?>', '<?php echo $token; ?>');
setupCleaner('mokosuiteclient-clear-temp', 'mokosuiteclient-temp-icon', '<?php echo $tempUrl; ?>', '<?php echo $token; ?>');
// Support PIN button
var pinBtn = document.getElementById('mokosuiteclient-pin');
var pinIcon = document.getElementById('mokosuiteclient-pin-icon');
var pinText = document.getElementById('mokosuiteclient-pin-text');
if (pinBtn && pinText) {
pinBtn.addEventListener('click', function(e) {
e.preventDefault();
var current = pinText.textContent.trim();
if (current.indexOf('MOKO-') === 0) {
navigator.clipboard.writeText(current).then(function() {
var orig = pinText.textContent;
pinText.textContent = 'Copied!';
setTimeout(function() { pinText.textContent = orig; }, 1500);
});
return;
}
if (pinBtn.dataset.busy) return;
pinBtn.dataset.busy = '1';
if (pinIcon) pinIcon.className = 'icon-spinner icon-spin';
pinText.textContent = '...';
var fd = new FormData();
fd.append('<?php echo $token; ?>', '1');
fetch('<?php echo $pinUrl; ?>', {
method: 'POST',
headers: {'X-Requested-With': 'XMLHttpRequest'},
body: fd
})
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.success && data.pin) {
pinText.textContent = data.pin;
pinBtn.title = 'Support PIN — click to copy';
if (pinIcon) pinIcon.className = 'icon-key';
} else {
pinText.textContent = 'PIN';
if (pinIcon) pinIcon.className = 'icon-key';
}
delete pinBtn.dataset.busy;
})
.catch(function() {
pinText.textContent = 'PIN';
if (pinIcon) pinIcon.className = 'icon-key';
delete pinBtn.dataset.busy;
});
});
}
});
</script>