Spaces:
Runtime error
Runtime error
feat: disable PWA and add developer tools for cache management
Browse files- Disable PWA service worker registration to fix refresh issues
- Add cache clearing utilities (clearAllCache, hardRefresh, checkCacheStatus)
- Modify service worker to skip caching in development (localhost)
- Add Developer Tools section in settings with:
- Cache management buttons (Clear All Cache, Hard Refresh, Check Status)
- Storage management (Clear Local Storage)
- PWA status indicator
- Add CSS styles for developer tools interface
- Provide multiple solutions for PWA-related refresh problems
This addresses the issue where PWA caching was interfering with page refresh behavior during development.
- public/sw.js +9 -0
- src/components/Settings.jsx +91 -0
- src/index.css +107 -0
- src/main.jsx +3 -3
- src/utils/clearCache.js +68 -0
public/sw.js
CHANGED
|
@@ -38,6 +38,15 @@ self.addEventListener('activate', event => {
|
|
| 38 |
|
| 39 |
// Fetch event - serve from cache if available, otherwise fetch from network
|
| 40 |
self.addEventListener('fetch', event => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
event.respondWith(
|
| 42 |
caches.match(event.request)
|
| 43 |
.then(response => {
|
|
|
|
| 38 |
|
| 39 |
// Fetch event - serve from cache if available, otherwise fetch from network
|
| 40 |
self.addEventListener('fetch', event => {
|
| 41 |
+
// Skip caching for localhost/development
|
| 42 |
+
const isLocalhost = event.request.url.includes('localhost') || event.request.url.includes('127.0.0.1');
|
| 43 |
+
|
| 44 |
+
if (isLocalhost) {
|
| 45 |
+
// In development, always fetch from network (no caching)
|
| 46 |
+
event.respondWith(fetch(event.request));
|
| 47 |
+
return;
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
event.respondWith(
|
| 51 |
caches.match(event.request)
|
| 52 |
.then(response => {
|
src/components/Settings.jsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
import { useState, useEffect } from 'react';
|
|
|
|
| 2 |
|
| 3 |
function Settings({
|
| 4 |
profiles,
|
|
@@ -706,6 +707,96 @@ function Settings({
|
|
| 706 |
)}
|
| 707 |
</div>
|
| 708 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 709 |
<div className="settings-actions">
|
| 710 |
<button type="submit" className="save-button">Save Settings</button>
|
| 711 |
<button type="button" className="cancel-button" onClick={onCloseSettings}>Cancel</button>
|
|
|
|
| 1 |
import { useState, useEffect } from 'react';
|
| 2 |
+
import { clearAllCache, hardRefresh, checkCacheStatus } from '../utils/clearCache';
|
| 3 |
|
| 4 |
function Settings({
|
| 5 |
profiles,
|
|
|
|
| 707 |
)}
|
| 708 |
</div>
|
| 709 |
|
| 710 |
+
{/* Developer Tools Section */}
|
| 711 |
+
<div className="profiles-section">
|
| 712 |
+
<h3>Developer Tools</h3>
|
| 713 |
+
<div className="developer-tools-section">
|
| 714 |
+
<div className="tool-group">
|
| 715 |
+
<h4>Cache Management</h4>
|
| 716 |
+
<p className="tool-description">Clear PWA cache and service workers that might interfere with page refreshing.</p>
|
| 717 |
+
|
| 718 |
+
<div className="tool-buttons">
|
| 719 |
+
<button
|
| 720 |
+
type="button"
|
| 721 |
+
className="dev-tool-button"
|
| 722 |
+
onClick={async () => {
|
| 723 |
+
try {
|
| 724 |
+
await clearAllCache();
|
| 725 |
+
alert('Cache cleared successfully! Page will refresh.');
|
| 726 |
+
window.location.reload();
|
| 727 |
+
} catch (error) {
|
| 728 |
+
alert('Error clearing cache: ' + error.message);
|
| 729 |
+
}
|
| 730 |
+
}}
|
| 731 |
+
>
|
| 732 |
+
Clear All Cache
|
| 733 |
+
</button>
|
| 734 |
+
|
| 735 |
+
<button
|
| 736 |
+
type="button"
|
| 737 |
+
className="dev-tool-button secondary"
|
| 738 |
+
onClick={async () => {
|
| 739 |
+
try {
|
| 740 |
+
await hardRefresh();
|
| 741 |
+
} catch (error) {
|
| 742 |
+
alert('Error performing hard refresh: ' + error.message);
|
| 743 |
+
}
|
| 744 |
+
}}
|
| 745 |
+
>
|
| 746 |
+
Hard Refresh
|
| 747 |
+
</button>
|
| 748 |
+
|
| 749 |
+
<button
|
| 750 |
+
type="button"
|
| 751 |
+
className="dev-tool-button secondary"
|
| 752 |
+
onClick={async () => {
|
| 753 |
+
try {
|
| 754 |
+
await checkCacheStatus();
|
| 755 |
+
alert('Check console for cache status details');
|
| 756 |
+
} catch (error) {
|
| 757 |
+
alert('Error checking cache status: ' + error.message);
|
| 758 |
+
}
|
| 759 |
+
}}
|
| 760 |
+
>
|
| 761 |
+
Check Cache Status
|
| 762 |
+
</button>
|
| 763 |
+
</div>
|
| 764 |
+
</div>
|
| 765 |
+
|
| 766 |
+
<div className="tool-group">
|
| 767 |
+
<h4>Storage Management</h4>
|
| 768 |
+
<p className="tool-description">Clear local storage data including chat history and settings.</p>
|
| 769 |
+
|
| 770 |
+
<div className="tool-buttons">
|
| 771 |
+
<button
|
| 772 |
+
type="button"
|
| 773 |
+
className="dev-tool-button warning"
|
| 774 |
+
onClick={() => {
|
| 775 |
+
if (confirm('This will clear all local data including chat history. Are you sure?')) {
|
| 776 |
+
localStorage.clear();
|
| 777 |
+
sessionStorage.clear();
|
| 778 |
+
alert('Local storage cleared! Page will refresh.');
|
| 779 |
+
window.location.reload();
|
| 780 |
+
}
|
| 781 |
+
}}
|
| 782 |
+
>
|
| 783 |
+
Clear Local Storage
|
| 784 |
+
</button>
|
| 785 |
+
</div>
|
| 786 |
+
</div>
|
| 787 |
+
|
| 788 |
+
<div className="tool-group">
|
| 789 |
+
<h4>PWA Status</h4>
|
| 790 |
+
<p className="tool-description">PWA (Progressive Web App) functionality is currently disabled to improve page refresh behavior.</p>
|
| 791 |
+
|
| 792 |
+
<div className="pwa-info">
|
| 793 |
+
<span className="status-indicator disabled">PWA Disabled</span>
|
| 794 |
+
<small>Service worker registration is commented out in main.jsx</small>
|
| 795 |
+
</div>
|
| 796 |
+
</div>
|
| 797 |
+
</div>
|
| 798 |
+
</div>
|
| 799 |
+
|
| 800 |
<div className="settings-actions">
|
| 801 |
<button type="submit" className="save-button">Save Settings</button>
|
| 802 |
<button type="button" className="cancel-button" onClick={onCloseSettings}>Cancel</button>
|
src/index.css
CHANGED
|
@@ -2,6 +2,113 @@
|
|
| 2 |
@import './styles/mcp.css';
|
| 3 |
@import './styles/mcp-settings.css';
|
| 4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
@tailwind base;
|
| 6 |
@tailwind components;
|
| 7 |
@tailwind utilities;
|
|
|
|
| 2 |
@import './styles/mcp.css';
|
| 3 |
@import './styles/mcp-settings.css';
|
| 4 |
|
| 5 |
+
/* Developer Tools Styles */
|
| 6 |
+
.developer-tools-section {
|
| 7 |
+
background: var(--background-secondary);
|
| 8 |
+
border-radius: var(--border-radius);
|
| 9 |
+
padding: 1rem;
|
| 10 |
+
margin-top: 1rem;
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
.tool-group {
|
| 14 |
+
margin-bottom: 1.5rem;
|
| 15 |
+
border-bottom: 1px solid var(--border-color);
|
| 16 |
+
padding-bottom: 1rem;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.tool-group:last-child {
|
| 20 |
+
border-bottom: none;
|
| 21 |
+
margin-bottom: 0;
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
.tool-group h4 {
|
| 25 |
+
color: var(--text-color);
|
| 26 |
+
font-size: 1rem;
|
| 27 |
+
font-weight: 600;
|
| 28 |
+
margin-bottom: 0.5rem;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
.tool-description {
|
| 32 |
+
color: var(--text-secondary);
|
| 33 |
+
font-size: 0.875rem;
|
| 34 |
+
margin-bottom: 1rem;
|
| 35 |
+
line-height: 1.5;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
.tool-buttons {
|
| 39 |
+
display: flex;
|
| 40 |
+
gap: 0.75rem;
|
| 41 |
+
flex-wrap: wrap;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
.dev-tool-button {
|
| 45 |
+
padding: 0.5rem 1rem;
|
| 46 |
+
border: 1px solid var(--border-color);
|
| 47 |
+
border-radius: var(--border-radius);
|
| 48 |
+
background: var(--background-primary);
|
| 49 |
+
color: var(--text-color);
|
| 50 |
+
font-size: 0.875rem;
|
| 51 |
+
cursor: pointer;
|
| 52 |
+
transition: all var(--transition-fast);
|
| 53 |
+
font-weight: 500;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
.dev-tool-button:hover {
|
| 57 |
+
background: var(--background-secondary);
|
| 58 |
+
border-color: var(--primary-color);
|
| 59 |
+
color: var(--primary-color);
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
.dev-tool-button.secondary {
|
| 63 |
+
background: var(--background-secondary);
|
| 64 |
+
color: var(--text-secondary);
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
.dev-tool-button.secondary:hover {
|
| 68 |
+
background: var(--background-tertiary);
|
| 69 |
+
color: var(--text-color);
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
.dev-tool-button.warning {
|
| 73 |
+
background: var(--warning-light);
|
| 74 |
+
color: var(--warning-color);
|
| 75 |
+
border-color: var(--warning-color);
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
.dev-tool-button.warning:hover {
|
| 79 |
+
background: var(--warning-color);
|
| 80 |
+
color: white;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
.pwa-info {
|
| 84 |
+
display: flex;
|
| 85 |
+
align-items: center;
|
| 86 |
+
gap: 0.75rem;
|
| 87 |
+
padding: 0.75rem;
|
| 88 |
+
background: var(--background-tertiary);
|
| 89 |
+
border-radius: var(--border-radius);
|
| 90 |
+
border: 1px solid var(--border-color);
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
.status-indicator {
|
| 94 |
+
padding: 0.25rem 0.75rem;
|
| 95 |
+
border-radius: 9999px;
|
| 96 |
+
font-size: 0.75rem;
|
| 97 |
+
font-weight: 600;
|
| 98 |
+
text-transform: uppercase;
|
| 99 |
+
letter-spacing: 0.05em;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
.status-indicator.disabled {
|
| 103 |
+
background: var(--error-light);
|
| 104 |
+
color: var(--error-color);
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
.pwa-info small {
|
| 108 |
+
color: var(--text-muted);
|
| 109 |
+
font-size: 0.75rem;
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
@tailwind base;
|
| 113 |
@tailwind components;
|
| 114 |
@tailwind utilities;
|
src/main.jsx
CHANGED
|
@@ -3,7 +3,7 @@ import ReactDOM from 'react-dom/client'
|
|
| 3 |
import App from './App'
|
| 4 |
import './tailwind.css'
|
| 5 |
import './index.css'
|
| 6 |
-
import { register as registerServiceWorker } from './serviceWorkerRegistration'
|
| 7 |
|
| 8 |
ReactDOM.createRoot(document.getElementById('root')).render(
|
| 9 |
<React.StrictMode>
|
|
@@ -11,5 +11,5 @@ ReactDOM.createRoot(document.getElementById('root')).render(
|
|
| 11 |
</React.StrictMode>,
|
| 12 |
)
|
| 13 |
|
| 14 |
-
//
|
| 15 |
-
registerServiceWorker()
|
|
|
|
| 3 |
import App from './App'
|
| 4 |
import './tailwind.css'
|
| 5 |
import './index.css'
|
| 6 |
+
// import { register as registerServiceWorker } from './serviceWorkerRegistration'
|
| 7 |
|
| 8 |
ReactDOM.createRoot(document.getElementById('root')).render(
|
| 9 |
<React.StrictMode>
|
|
|
|
| 11 |
</React.StrictMode>,
|
| 12 |
)
|
| 13 |
|
| 14 |
+
// PWA functionality disabled to allow proper refreshing
|
| 15 |
+
// registerServiceWorker()
|
src/utils/clearCache.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Utility to clear PWA cache and service worker
|
| 2 |
+
|
| 3 |
+
export async function clearAllCache() {
|
| 4 |
+
try {
|
| 5 |
+
// Unregister all service workers
|
| 6 |
+
if ('serviceWorker' in navigator) {
|
| 7 |
+
const registrations = await navigator.serviceWorker.getRegistrations();
|
| 8 |
+
for (let registration of registrations) {
|
| 9 |
+
await registration.unregister();
|
| 10 |
+
console.log('Service worker unregistered:', registration);
|
| 11 |
+
}
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
// Clear all caches
|
| 15 |
+
if ('caches' in window) {
|
| 16 |
+
const cacheNames = await caches.keys();
|
| 17 |
+
await Promise.all(
|
| 18 |
+
cacheNames.map(cacheName => {
|
| 19 |
+
console.log('Deleting cache:', cacheName);
|
| 20 |
+
return caches.delete(cacheName);
|
| 21 |
+
})
|
| 22 |
+
);
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
// Clear localStorage and sessionStorage
|
| 26 |
+
localStorage.clear();
|
| 27 |
+
sessionStorage.clear();
|
| 28 |
+
|
| 29 |
+
console.log('All cache and storage cleared!');
|
| 30 |
+
return true;
|
| 31 |
+
} catch (error) {
|
| 32 |
+
console.error('Error clearing cache:', error);
|
| 33 |
+
return false;
|
| 34 |
+
}
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
export async function hardRefresh() {
|
| 38 |
+
await clearAllCache();
|
| 39 |
+
|
| 40 |
+
// Force hard refresh
|
| 41 |
+
if (typeof window !== 'undefined') {
|
| 42 |
+
// Try different hard refresh methods
|
| 43 |
+
if (window.location.reload) {
|
| 44 |
+
window.location.reload(true); // Force reload
|
| 45 |
+
} else {
|
| 46 |
+
window.location.href = window.location.href;
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
// Debug function to check cache status
|
| 52 |
+
export async function checkCacheStatus() {
|
| 53 |
+
if ('caches' in window) {
|
| 54 |
+
const cacheNames = await caches.keys();
|
| 55 |
+
console.log('Active caches:', cacheNames);
|
| 56 |
+
|
| 57 |
+
for (const cacheName of cacheNames) {
|
| 58 |
+
const cache = await caches.open(cacheName);
|
| 59 |
+
const requests = await cache.keys();
|
| 60 |
+
console.log(`Cache ${cacheName} contains:`, requests.map(req => req.url));
|
| 61 |
+
}
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
if ('serviceWorker' in navigator) {
|
| 65 |
+
const registrations = await navigator.serviceWorker.getRegistrations();
|
| 66 |
+
console.log('Active service workers:', registrations);
|
| 67 |
+
}
|
| 68 |
+
}
|