feat: implement scenario caching and hot-reloading
Signed-off-by: Abhinav Sinha <[email protected]>
This commit is contained in:
@@ -13,6 +13,31 @@ export default function Header({ clusterReady }) {
|
||||
|
||||
const toggleTheme = () => setTheme(t => t === 'dark' ? 'light' : 'dark')
|
||||
|
||||
const handleReloadCache = async () => {
|
||||
const sendReloadRequest = async () => {
|
||||
return fetch('/api/cache/reload', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
try {
|
||||
let response = await sendReloadRequest();
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
alert(`Success: ${data.message}\nScenarios: ${data.scenarios_count}\nBundles: ${data.bundles_count}`);
|
||||
window.location.reload();
|
||||
} else {
|
||||
const data = await response.json().catch(() => ({}));
|
||||
alert(`Error reloading cache: ${data.error || 'Unknown error'}`);
|
||||
}
|
||||
} catch (err) {
|
||||
alert(`Network error reloading cache: ${err.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<header className={styles.header}>
|
||||
<div className={styles.brand}>
|
||||
@@ -54,6 +79,20 @@ export default function Header({ clusterReady }) {
|
||||
<span className={styles.dot} />
|
||||
<span>{clusterReady ? 'Cluster Ready' : 'Connecting…'}</span>
|
||||
</div>
|
||||
|
||||
{/* Reload cache */}
|
||||
<div className={styles.reloadBtnContainer}>
|
||||
<button
|
||||
className={styles.reloadBtn}
|
||||
onClick={handleReloadCache}
|
||||
aria-label="Reload scenario cache"
|
||||
>
|
||||
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M23 4v6h-6" />
|
||||
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
|
||||
@@ -107,6 +107,58 @@
|
||||
transform: rotate(12deg);
|
||||
}
|
||||
|
||||
.reloadBtnContainer {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.reloadBtnContainer::after {
|
||||
content: "Reload Scenario Cache";
|
||||
position: absolute;
|
||||
top: calc(100% + 8px);
|
||||
right: 0;
|
||||
background: var(--surface3);
|
||||
color: var(--text);
|
||||
font-family: var(--mono);
|
||||
font-size: 11px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--border2);
|
||||
white-space: nowrap;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.1s ease;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.reloadBtnContainer:hover::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.reloadBtn {
|
||||
background: none;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s, border-color 0.15s, transform 0.2s, color 0.15s;
|
||||
color: var(--text-2);
|
||||
line-height: 1;
|
||||
}
|
||||
.reloadBtn:hover {
|
||||
background: var(--surface2);
|
||||
border-color: var(--border2);
|
||||
color: var(--text);
|
||||
transform: rotate(12deg);
|
||||
}
|
||||
|
||||
.clusterBadge {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user