mirror of
https://github.com/Crosstalk-Solutions/project-nomad.git
synced 2026-03-28 03:29:25 +01:00
fix(ui): reduce SSE reconnect churn and polling overhead on navigation
This commit is contained in:
parent
b54d6838c1
commit
2f7716cd75
|
|
@ -3,7 +3,7 @@ import { defineConfig } from '@adonisjs/transmit'
|
|||
import { redis } from '@adonisjs/transmit/transports'
|
||||
|
||||
export default defineConfig({
|
||||
pingInterval: false,
|
||||
pingInterval: '30s',
|
||||
transport: {
|
||||
driver: redis({
|
||||
host: env.get('REDIS_HOST'),
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ createInertiaApp({
|
|||
createRoot(el).render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ThemeProvider>
|
||||
<TransmitProvider baseUrl={window.location.origin} enableLogging={true}>
|
||||
<TransmitProvider baseUrl={window.location.origin} enableLogging={environment === 'development'}>
|
||||
<NotificationsProvider>
|
||||
<ModalsProvider>
|
||||
<App {...props} />
|
||||
|
|
|
|||
|
|
@ -17,7 +17,11 @@ const useDownloads = (props: useDownloadsProps) => {
|
|||
const queryData = useQuery({
|
||||
queryKey: queryKey,
|
||||
queryFn: () => api.listDownloadJobs(props.filetype),
|
||||
refetchInterval: 2000, // Refetch every 2 seconds to get updated progress
|
||||
refetchInterval: (query) => {
|
||||
const data = query.state.data
|
||||
// Only poll when there are active downloads; otherwise use a slower interval
|
||||
return data && data.length > 0 ? 2000 : 30000
|
||||
},
|
||||
enabled: props.enabled ?? true,
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,11 @@ const useEmbedJobs = (props: { enabled?: boolean } = {}) => {
|
|||
const queryData = useQuery({
|
||||
queryKey: ['embed-jobs'],
|
||||
queryFn: () => api.getActiveEmbedJobs().then((data) => data ?? []),
|
||||
refetchInterval: 2000,
|
||||
refetchInterval: (query) => {
|
||||
const data = query.state.data
|
||||
// Only poll when there are active jobs; otherwise use a slower interval
|
||||
return data && data.length > 0 ? 2000 : 30000
|
||||
},
|
||||
enabled: props.enabled ?? true,
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useTransmit } from 'react-adonis-transmit'
|
||||
|
||||
export type OllamaModelDownload = {
|
||||
|
|
@ -10,6 +10,7 @@ export type OllamaModelDownload = {
|
|||
export default function useOllamaModelDownloads() {
|
||||
const { subscribe } = useTransmit()
|
||||
const [downloads, setDownloads] = useState<Map<string, OllamaModelDownload>>(new Map())
|
||||
const timeoutsRef = useRef<Set<ReturnType<typeof setTimeout>>>(new Set())
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = subscribe('ollama-model-download', (data: OllamaModelDownload) => {
|
||||
|
|
@ -19,13 +20,15 @@ export default function useOllamaModelDownloads() {
|
|||
if (data.percent >= 100) {
|
||||
// If download is complete, keep it for a short time before removing to allow UI to show 100% progress
|
||||
updated.set(data.model, data)
|
||||
setTimeout(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
timeoutsRef.current.delete(timeout)
|
||||
setDownloads((current) => {
|
||||
const next = new Map(current)
|
||||
next.delete(data.model)
|
||||
return next
|
||||
})
|
||||
}, 2000)
|
||||
timeoutsRef.current.add(timeout)
|
||||
} else {
|
||||
updated.set(data.model, data)
|
||||
}
|
||||
|
|
@ -36,7 +39,10 @@ export default function useOllamaModelDownloads() {
|
|||
|
||||
return () => {
|
||||
unsubscribe()
|
||||
timeoutsRef.current.forEach(clearTimeout)
|
||||
timeoutsRef.current.clear()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [subscribe])
|
||||
|
||||
const downloadsArray = Array.from(downloads.values())
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Head, Link, usePage } from '@inertiajs/react'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import SettingsLayout from '~/layouts/SettingsLayout'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import CircularGauge from '~/components/systeminfo/CircularGauge'
|
||||
|
|
@ -40,6 +40,7 @@ export default function BenchmarkPage(props: {
|
|||
const aiInstalled = useServiceInstalledStatus(SERVICE_NAMES.OLLAMA)
|
||||
const [progress, setProgress] = useState<BenchmarkProgressWithID | null>(null)
|
||||
const [isRunning, setIsRunning] = useState(props.benchmark.status !== 'idle')
|
||||
const refetchLatestRef = useRef(refetchLatest)
|
||||
const [showDetails, setShowDetails] = useState(false)
|
||||
const [showHistory, setShowHistory] = useState(false)
|
||||
const [showAIRequiredAlert, setShowAIRequiredAlert] = useState(false)
|
||||
|
|
@ -60,6 +61,7 @@ export default function BenchmarkPage(props: {
|
|||
},
|
||||
initialData: props.benchmark.latestResult,
|
||||
})
|
||||
refetchLatestRef.current = refetchLatest
|
||||
|
||||
// Fetch all benchmark results for history
|
||||
const { data: benchmarkHistory } = useQuery({
|
||||
|
|
@ -306,14 +308,15 @@ export default function BenchmarkPage(props: {
|
|||
setProgress(data)
|
||||
if (data.status === 'completed' || data.status === 'error') {
|
||||
setIsRunning(false)
|
||||
refetchLatest()
|
||||
refetchLatestRef.current()
|
||||
}
|
||||
})
|
||||
|
||||
return () => {
|
||||
unsubscribe()
|
||||
}
|
||||
}, [subscribe, refetchLatest])
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [subscribe])
|
||||
|
||||
const formatBytes = (bytes: number) => {
|
||||
const gb = bytes / (1024 * 1024 * 1024)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user