Various UI improvements (#176)
* add retry/backoff to reconnecting log streams * update favicons
@@ -3,7 +3,11 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="icon" type="image/png" href="/favicon.ico" />
|
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<link rel="shortcut icon" href="/favicon.ico" />
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||||
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
<title>llama-swap</title>
|
<title>llama-swap</title>
|
||||||
</head>
|
</head>
|
||||||
<body >
|
<body >
|
||||||
|
|||||||
BIN
ui/public/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
ui/public/favicon-96x96.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
17
ui/public/favicon.svg
Normal file
|
After Width: | Height: | Size: 38 KiB |
21
ui/public/site.webmanifest
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "llama-swap",
|
||||||
|
"short_name": "llama-swap",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/web-app-manifest-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/web-app-manifest-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"display": "standalone"
|
||||||
|
}
|
||||||
BIN
ui/public/web-app-manifest-192x192.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
ui/public/web-app-manifest-512x512.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
@@ -58,9 +58,27 @@ export function APIProvider({ children }: APIProviderProps) {
|
|||||||
const enableProxyLogs = useCallback(
|
const enableProxyLogs = useCallback(
|
||||||
(enabled: boolean) => {
|
(enabled: boolean) => {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
const eventSource = new EventSource("/logs/streamSSE/proxy");
|
let retryCount = 0;
|
||||||
eventSource.onmessage = handleProxyMessage;
|
const maxRetries = 3;
|
||||||
proxyEventSource.current = eventSource;
|
const initialDelay = 1000; // 1 second
|
||||||
|
|
||||||
|
const connect = () => {
|
||||||
|
const eventSource = new EventSource("/logs/streamSSE/proxy");
|
||||||
|
|
||||||
|
eventSource.onmessage = handleProxyMessage;
|
||||||
|
eventSource.onerror = () => {
|
||||||
|
eventSource.close();
|
||||||
|
if (retryCount < maxRetries) {
|
||||||
|
retryCount++;
|
||||||
|
const delay = initialDelay * Math.pow(2, retryCount - 1);
|
||||||
|
setTimeout(connect, delay);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
proxyEventSource.current = eventSource;
|
||||||
|
};
|
||||||
|
|
||||||
|
connect();
|
||||||
} else {
|
} else {
|
||||||
proxyEventSource.current?.close();
|
proxyEventSource.current?.close();
|
||||||
proxyEventSource.current = null;
|
proxyEventSource.current = null;
|
||||||
@@ -72,15 +90,33 @@ export function APIProvider({ children }: APIProviderProps) {
|
|||||||
const enableUpstreamLogs = useCallback(
|
const enableUpstreamLogs = useCallback(
|
||||||
(enabled: boolean) => {
|
(enabled: boolean) => {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
const eventSource = new EventSource("/logs/streamSSE/upstream");
|
let retryCount = 0;
|
||||||
eventSource.onmessage = handleUpstreamMessage;
|
const maxRetries = 3;
|
||||||
upstreamEventSource.current = eventSource;
|
const initialDelay = 1000; // 1 second
|
||||||
|
|
||||||
|
const connect = () => {
|
||||||
|
const eventSource = new EventSource("/logs/streamSSE/upstream");
|
||||||
|
|
||||||
|
eventSource.onmessage = handleUpstreamMessage;
|
||||||
|
eventSource.onerror = () => {
|
||||||
|
eventSource.close();
|
||||||
|
if (retryCount < maxRetries) {
|
||||||
|
retryCount++;
|
||||||
|
const delay = initialDelay * Math.pow(2, retryCount - 1);
|
||||||
|
setTimeout(connect, delay);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
upstreamEventSource.current = eventSource;
|
||||||
|
};
|
||||||
|
|
||||||
|
connect();
|
||||||
} else {
|
} else {
|
||||||
upstreamEventSource.current?.close();
|
upstreamEventSource.current?.close();
|
||||||
upstreamEventSource.current = null;
|
upstreamEventSource.current = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[upstreamEventSource, handleUpstreamMessage]
|
[handleUpstreamMessage]
|
||||||
);
|
);
|
||||||
|
|
||||||
const enableModelUpdates = useCallback(
|
const enableModelUpdates = useCallback(
|
||||||
|
|||||||