diff --git a/ui/desktop/src/components/sessions/SessionsInsights.tsx b/ui/desktop/src/components/sessions/SessionsInsights.tsx
index 84ebb69f7b..e42302b3f2 100644
--- a/ui/desktop/src/components/sessions/SessionsInsights.tsx
+++ b/ui/desktop/src/components/sessions/SessionsInsights.tsx
@@ -10,6 +10,7 @@ import { Button } from '../ui/button';
import { ChatSmart } from '../icons/';
import { motion, AnimatePresence } from 'framer-motion';
import { Goose } from '../icons/Goose';
+import { Skeleton } from '../ui/skeleton';
interface SessionInsightsType {
totalSessions: number;
@@ -114,8 +115,113 @@ export function SessionInsights() {
.replace(/\//g, '/');
};
+ // Render skeleton loader while data is loading
+ const renderSkeleton = () => (
+
+ {/* Header container with rounded bottom */}
+
+
+ {/* Stats containers - full bleed with 2px gaps */}
+
+ {/* Top row with three equal columns */}
+
+ {/* Total Sessions Card Skeleton */}
+
+
+
+
+ Total sessions
+
+
+
+
+ {/* Average Duration Card Skeleton */}
+
+
+
+
+ Avg. chat length
+
+
+
+
+ {/* Total Tokens Card Skeleton */}
+
+
+
+
+ Total tokens
+
+
+
+
+
+ {/* Recent Chats Card Skeleton */}
+
+
+
+
+
+ Recent chats
+
+
+
+
+ {/* Skeleton chat items */}
+
+
+
+
+
+
+
+
+ {/* Filler container - extends to fill remaining space */}
+
+
+
+ );
+
+ // Show skeleton while loading, then show actual content
if (!insights) {
- return <>>;
+ return renderSkeleton();
}
return (
diff --git a/ui/desktop/src/components/settings/models/ModelsSection.tsx b/ui/desktop/src/components/settings/models/ModelsSection.tsx
index f4abf1fa18..9d665d5b27 100644
--- a/ui/desktop/src/components/settings/models/ModelsSection.tsx
+++ b/ui/desktop/src/components/settings/models/ModelsSection.tsx
@@ -16,12 +16,14 @@ interface ModelsSectionProps {
export default function ModelsSection({ setView }: ModelsSectionProps) {
const [provider, setProvider] = useState(null);
const [displayModelName, setDisplayModelName] = useState('');
+ const [isLoading, setIsLoading] = useState(true);
const { read, getProviders } = useConfig();
const { getCurrentModelDisplayName, getCurrentProviderDisplayName } = useModelAndProvider();
// Function to load model data
const loadModelData = useCallback(async () => {
try {
+ setIsLoading(true);
const gooseProvider = (await read('GOOSE_PROVIDER', false)) as string;
const providers = await getProviders(true);
@@ -50,6 +52,8 @@ export default function ModelsSection({ setView }: ModelsSectionProps) {
}
} catch (error) {
console.error('Error loading model data:', error);
+ } finally {
+ setIsLoading(false);
}
}, [read, getProviders, getCurrentModelDisplayName, getCurrentProviderDisplayName]);
@@ -62,8 +66,17 @@ export default function ModelsSection({ setView }: ModelsSectionProps) {
- {displayModelName}
- {provider}
+ {isLoading ? (
+ <>
+
+
+ >
+ ) : (
+
+
{displayModelName}
+ {provider}
+
+ )}