mirror of
https://github.com/A6-9V/MQL5-Google-Onedrive.git
synced 2026-04-10 22:30:56 +00:00
- Replaced #667eea with #4f46e5 to meet WCAG AA contrast standards. - Updated hover color to #4338ca. - Added aria-label to Service Worker update button. - Updated manifest.json theme color.
457 lines
15 KiB
HTML
457 lines
15 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Service Worker Inspector - MQL5 Trading Automation</title>
|
|
<link rel="manifest" href="/manifest.json">
|
|
<meta name="theme-color" content="#4f46e5">
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
background: linear-gradient(135deg, #4f46e5 0%, #764ba2 100%);
|
|
min-height: 100vh;
|
|
padding: 20px;
|
|
}
|
|
|
|
.container {
|
|
max-width: 1000px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.header {
|
|
background: white;
|
|
padding: 30px;
|
|
border-radius: 15px;
|
|
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
|
|
margin-bottom: 30px;
|
|
text-align: center;
|
|
}
|
|
|
|
.header h1 {
|
|
color: #333;
|
|
font-size: 2em;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.header p {
|
|
color: #666;
|
|
font-size: 1em;
|
|
}
|
|
|
|
.card {
|
|
background: white;
|
|
padding: 25px;
|
|
border-radius: 15px;
|
|
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.card h2 {
|
|
color: #4f46e5;
|
|
margin-bottom: 15px;
|
|
font-size: 1.5em;
|
|
}
|
|
|
|
.info-grid {
|
|
display: grid;
|
|
grid-template-columns: 200px 1fr;
|
|
gap: 15px;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.info-label {
|
|
color: #666;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.info-value {
|
|
color: #333;
|
|
word-break: break-all;
|
|
}
|
|
|
|
.status-badge {
|
|
display: inline-block;
|
|
padding: 5px 15px;
|
|
border-radius: 20px;
|
|
font-size: 0.9em;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.status-active {
|
|
background: #10b981;
|
|
color: white;
|
|
}
|
|
|
|
.status-inactive {
|
|
background: #ef4444;
|
|
color: white;
|
|
}
|
|
|
|
.status-installing {
|
|
background: #f59e0b;
|
|
color: white;
|
|
}
|
|
|
|
.btn {
|
|
display: inline-block;
|
|
padding: 12px 24px;
|
|
background: #4f46e5;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 8px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: background 0.3s;
|
|
margin-right: 10px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.btn:hover {
|
|
background: #4338ca;
|
|
}
|
|
|
|
.btn-danger {
|
|
background: #ef4444;
|
|
}
|
|
|
|
.btn-danger:hover {
|
|
background: #dc2626;
|
|
}
|
|
|
|
.log-container {
|
|
background: #1a1a1a;
|
|
color: #0f0;
|
|
padding: 15px;
|
|
border-radius: 8px;
|
|
font-family: 'Courier New', monospace;
|
|
font-size: 0.9em;
|
|
max-height: 300px;
|
|
overflow-y: auto;
|
|
margin-top: 15px;
|
|
}
|
|
|
|
.log-entry {
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.log-timestamp {
|
|
color: #888;
|
|
}
|
|
|
|
.cache-list {
|
|
list-style: none;
|
|
}
|
|
|
|
.cache-item {
|
|
padding: 10px;
|
|
border-bottom: 1px solid #eee;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.cache-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.cache-name {
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
|
|
.cache-size {
|
|
color: #4f46e5;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.back-link {
|
|
display: inline-block;
|
|
color: white;
|
|
text-decoration: none;
|
|
margin-bottom: 20px;
|
|
padding: 10px 20px;
|
|
background: rgba(255, 255, 255, 0.2);
|
|
border-radius: 8px;
|
|
transition: background 0.3s;
|
|
}
|
|
|
|
.back-link:hover {
|
|
background: rgba(255, 255, 255, 0.3);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<a href="/" class="back-link">← Back to Dashboard</a>
|
|
|
|
<div class="header">
|
|
<h1><span role="img" aria-label="Magnifying Glass">🔍</span> Service Worker Inspector</h1>
|
|
<p>Monitor and manage your Progressive Web App</p>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>Service Worker Status</h2>
|
|
<div class="info-grid">
|
|
<div class="info-label">Status:</div>
|
|
<div class="info-value">
|
|
<span id="sw-status" class="status-badge status-inactive">Checking...</span>
|
|
</div>
|
|
|
|
<div class="info-label">State:</div>
|
|
<div class="info-value" id="sw-state">-</div>
|
|
|
|
<div class="info-label">Scope:</div>
|
|
<div class="info-value" id="sw-scope">-</div>
|
|
|
|
<div class="info-label">Script URL:</div>
|
|
<div class="info-value" id="sw-url">-</div>
|
|
|
|
<div class="info-label">Update Available:</div>
|
|
<div class="info-value" id="sw-update">-</div>
|
|
</div>
|
|
|
|
<div style="margin-top: 20px;">
|
|
<button class="btn" onclick="checkUpdate()">Check for Updates</button>
|
|
<button class="btn" onclick="forceUpdate()">Force Update</button>
|
|
<button class="btn btn-danger" onclick="unregisterSW()">Unregister</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>Cache Storage</h2>
|
|
<div id="cache-info">
|
|
<p>Loading cache information...</p>
|
|
</div>
|
|
<div style="margin-top: 20px;">
|
|
<button class="btn" onclick="refreshCacheInfo()">Refresh Cache Info</button>
|
|
<button class="btn btn-danger" onclick="clearAllCaches()">Clear All Caches</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>Activity Log</h2>
|
|
<div class="log-container" id="log-container">
|
|
<div class="log-entry">
|
|
<span class="log-timestamp">[Starting]</span> Service Worker Inspector initialized
|
|
</div>
|
|
</div>
|
|
<div style="margin-top: 15px;">
|
|
<button class="btn" onclick="clearLog()">Clear Log</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>PWA Installation</h2>
|
|
<div class="info-grid">
|
|
<div class="info-label">Installable:</div>
|
|
<div class="info-value" id="pwa-installable">Checking...</div>
|
|
|
|
<div class="info-label">Display Mode:</div>
|
|
<div class="info-value" id="display-mode">-</div>
|
|
</div>
|
|
<div style="margin-top: 20px;">
|
|
<button class="btn" id="install-btn" style="display: none;" onclick="installPWA()">Install App</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let deferredPrompt;
|
|
const logs = [];
|
|
|
|
function log(message) {
|
|
const timestamp = new Date().toLocaleTimeString();
|
|
logs.push({ timestamp, message });
|
|
const logContainer = document.getElementById('log-container');
|
|
const entry = document.createElement('div');
|
|
entry.className = 'log-entry';
|
|
entry.innerHTML = `<span class="log-timestamp">[${timestamp}]</span> ${message}`;
|
|
logContainer.appendChild(entry);
|
|
logContainer.scrollTop = logContainer.scrollHeight;
|
|
}
|
|
|
|
function clearLog() {
|
|
logs.length = 0;
|
|
document.getElementById('log-container').innerHTML = '';
|
|
log('Log cleared');
|
|
}
|
|
|
|
async function updateServiceWorkerInfo() {
|
|
if ('serviceWorker' in navigator) {
|
|
const registration = await navigator.serviceWorker.getRegistration();
|
|
|
|
if (registration) {
|
|
const statusBadge = document.getElementById('sw-status');
|
|
statusBadge.textContent = 'Active';
|
|
statusBadge.className = 'status-badge status-active';
|
|
|
|
const sw = registration.active || registration.installing || registration.waiting;
|
|
if (sw) {
|
|
document.getElementById('sw-state').textContent = sw.state;
|
|
document.getElementById('sw-url').textContent = sw.scriptURL;
|
|
}
|
|
|
|
document.getElementById('sw-scope').textContent = registration.scope;
|
|
|
|
if (registration.waiting) {
|
|
document.getElementById('sw-update').textContent = 'Yes - Update available!';
|
|
log('Service worker update available');
|
|
} else {
|
|
document.getElementById('sw-update').textContent = 'No';
|
|
}
|
|
|
|
log('Service worker information updated');
|
|
} else {
|
|
const statusBadge = document.getElementById('sw-status');
|
|
statusBadge.textContent = 'Not Registered';
|
|
statusBadge.className = 'status-badge status-inactive';
|
|
log('No service worker registered');
|
|
}
|
|
} else {
|
|
document.getElementById('sw-status').textContent = 'Not Supported';
|
|
log('Service workers not supported in this browser');
|
|
}
|
|
}
|
|
|
|
async function checkUpdate() {
|
|
log('Checking for service worker updates...');
|
|
const registration = await navigator.serviceWorker.getRegistration();
|
|
if (registration) {
|
|
await registration.update();
|
|
log('Update check complete');
|
|
updateServiceWorkerInfo();
|
|
}
|
|
}
|
|
|
|
async function forceUpdate() {
|
|
log('Forcing service worker update...');
|
|
const registration = await navigator.serviceWorker.getRegistration();
|
|
if (registration && registration.waiting) {
|
|
registration.waiting.postMessage({ type: 'SKIP_WAITING' });
|
|
log('Update forced, reloading page...');
|
|
setTimeout(() => window.location.reload(), 1000);
|
|
} else {
|
|
log('No update available to force');
|
|
}
|
|
}
|
|
|
|
async function unregisterSW() {
|
|
if (confirm('Are you sure you want to unregister the service worker?')) {
|
|
log('Unregistering service worker...');
|
|
const registration = await navigator.serviceWorker.getRegistration();
|
|
if (registration) {
|
|
await registration.unregister();
|
|
log('Service worker unregistered');
|
|
updateServiceWorkerInfo();
|
|
}
|
|
}
|
|
}
|
|
|
|
async function refreshCacheInfo() {
|
|
log('Refreshing cache information...');
|
|
const cacheNames = await caches.keys();
|
|
const cacheInfo = document.getElementById('cache-info');
|
|
|
|
if (cacheNames.length === 0) {
|
|
cacheInfo.innerHTML = '<p>No caches found</p>';
|
|
log('No caches found');
|
|
return;
|
|
}
|
|
|
|
const cacheStats = await Promise.all(
|
|
cacheNames.map(async (name) => {
|
|
const cache = await caches.open(name);
|
|
const keys = await cache.keys();
|
|
return { name, size: keys.length };
|
|
})
|
|
);
|
|
|
|
cacheInfo.innerHTML = '<ul class="cache-list">' +
|
|
cacheStats.map(stat =>
|
|
`<li class="cache-item">
|
|
<span class="cache-name">${stat.name}</span>
|
|
<span class="cache-size">${stat.size} items</span>
|
|
</li>`
|
|
).join('') +
|
|
'</ul>';
|
|
|
|
log(`Found ${cacheNames.length} cache(s)`);
|
|
}
|
|
|
|
async function clearAllCaches() {
|
|
if (confirm('Are you sure you want to clear all caches? This will remove offline capabilities until the next page load.')) {
|
|
log('Clearing all caches...');
|
|
const cacheNames = await caches.keys();
|
|
await Promise.all(cacheNames.map(name => caches.delete(name)));
|
|
log(`Cleared ${cacheNames.length} cache(s)`);
|
|
refreshCacheInfo();
|
|
}
|
|
}
|
|
|
|
function checkDisplayMode() {
|
|
const displayMode = window.matchMedia('(display-mode: standalone)').matches ?
|
|
'Standalone (PWA)' : 'Browser';
|
|
document.getElementById('display-mode').textContent = displayMode;
|
|
log(`Display mode: ${displayMode}`);
|
|
}
|
|
|
|
function installPWA() {
|
|
if (deferredPrompt) {
|
|
deferredPrompt.prompt();
|
|
deferredPrompt.userChoice.then((choiceResult) => {
|
|
if (choiceResult.outcome === 'accepted') {
|
|
log('User accepted PWA installation');
|
|
} else {
|
|
log('User dismissed PWA installation');
|
|
}
|
|
deferredPrompt = null;
|
|
document.getElementById('install-btn').style.display = 'none';
|
|
});
|
|
}
|
|
}
|
|
|
|
// Listen for install prompt
|
|
window.addEventListener('beforeinstallprompt', (e) => {
|
|
e.preventDefault();
|
|
deferredPrompt = e;
|
|
document.getElementById('pwa-installable').textContent = 'Yes';
|
|
document.getElementById('install-btn').style.display = 'inline-block';
|
|
log('PWA installation prompt available');
|
|
});
|
|
|
|
// Listen for successful install
|
|
window.addEventListener('appinstalled', () => {
|
|
log('PWA successfully installed');
|
|
document.getElementById('pwa-installable').textContent = 'Installed';
|
|
document.getElementById('install-btn').style.display = 'none';
|
|
});
|
|
|
|
// Initialize on page load
|
|
window.addEventListener('load', () => {
|
|
log('Page loaded, initializing inspector...');
|
|
updateServiceWorkerInfo();
|
|
refreshCacheInfo();
|
|
checkDisplayMode();
|
|
|
|
if (window.matchMedia('(display-mode: standalone)').matches) {
|
|
document.getElementById('pwa-installable').textContent = 'Already installed';
|
|
}
|
|
});
|
|
|
|
// Listen for service worker updates
|
|
if ('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
|
log('Service worker controller changed');
|
|
updateServiceWorkerInfo();
|
|
});
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|