mirror of
https://github.com/A6-9V/MQL5-Google-Onedrive.git
synced 2026-10-08 23:21:37 +00:00
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="#667eea">
| |||
<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, #667eea 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: #667eea;
| |||
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: #667eea;
| |||
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: #5568d3;
| |||
}
| |||
| |||
.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: #667eea;
| |||
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>🔍 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>
|