This commit is contained in:
Dusan Vojacek
2026-03-20 14:30:03 +01:00
parent 2cc5ccfda7
commit 897b95f728
48 changed files with 4034 additions and 842 deletions

View File

@@ -8,24 +8,40 @@ const POLL_MS = 30_000
export function useAuditDailyToday(siteId: number | null) {
const [row, setRow] = useState<AuditDailyRow | null>(null)
const [ready, setReady] = useState(false)
const [error, setError] = useState<string | null>(null)
const load = useCallback(async () => {
if (siteId == null) {
setRow(null)
setError(null)
setReady(true)
return
}
try {
const rows = await getJson<AuditDailyRow[]>('/vw_audit_daily', {
site_id: `eq.${siteId}`,
order: 'day_local.desc',
limit: '45',
})
const today = pragueCalendarDay()
const hit = Array.isArray(rows) ? rows.find((r) => instantPragueDay(r.day_local) === today) : undefined
setRow(hit ?? null)
let primary = await getJson<AuditDailyRow[]>('/vw_audit_daily', {
site_id: `eq.${siteId}`,
day_local: `eq.${today}`,
})
let chosen: AuditDailyRow | null = null
if (Array.isArray(primary) && primary.length > 0) {
chosen = primary.find((r) => instantPragueDay(r.day_local) === today) ?? null
}
if (chosen == null || instantPragueDay(chosen.day_local) !== today) {
const recent = await getJson<AuditDailyRow[]>('/vw_audit_daily', {
site_id: `eq.${siteId}`,
order: 'day_local.desc',
limit: '45',
})
chosen = Array.isArray(recent)
? recent.find((r) => instantPragueDay(r.day_local) === today) ?? null
: null
}
setRow(chosen)
setError(null)
} catch {
setRow(null)
setError('Denní souhrn auditu se nepodařil načíst')
} finally {
setReady(true)
}
@@ -40,6 +56,8 @@ export function useAuditDailyToday(siteId: number | null) {
return {
daily: row,
ready,
error,
hasDaily: row != null && (row.interval_count ?? 0) > 0,
reload: load,
}
}

View File

@@ -0,0 +1,47 @@
import { useCallback, useEffect, useState } from 'react'
import axios from 'axios'
import { getCurrentPlan } from '../api/backend'
import type { CurrentPlanResponse } from '../types/plan'
const POLL_MS = 30_000
const EMPTY: CurrentPlanResponse = { run: null, intervals: [], summary: null }
export function useCurrentPlan(siteId: number | null) {
const [data, setData] = useState<CurrentPlanResponse>(EMPTY)
const [ready, setReady] = useState(false)
const [error, setError] = useState<string | null>(null)
const load = useCallback(async () => {
if (siteId == null) {
setData(EMPTY)
setError(null)
setReady(true)
return
}
try {
const res = await getCurrentPlan(siteId)
setData(res)
setError(null)
} catch (e) {
if (axios.isAxiosError(e) && e.response?.status === 404) {
setData(EMPTY)
setError(null)
} else {
setData(EMPTY)
setError(e instanceof Error ? e.message : 'Nepodařilo se načíst plán')
}
} finally {
setReady(true)
}
}, [siteId])
useEffect(() => {
void load()
const id = window.setInterval(() => void load(), POLL_MS)
return () => window.clearInterval(id)
}, [load])
return { plan: data, ready, error, reload: load }
}

View File

@@ -0,0 +1,38 @@
import { useCallback, useEffect, useState } from 'react'
import { getActiveEvSessions, type ActiveEvSessionRow } from '../api/backend'
const POLL_MS = 30_000
export function useEVSessions(siteId: number | null) {
const [sessions, setSessions] = useState<ActiveEvSessionRow[]>([])
const [ready, setReady] = useState(false)
const [error, setError] = useState<string | null>(null)
const load = useCallback(async () => {
if (siteId == null) {
setSessions([])
setReady(true)
return
}
try {
const rows = await getActiveEvSessions(siteId)
setSessions(rows)
setError(null)
} catch {
setSessions([])
setError('EV session se nepodařilo načíst')
} finally {
setReady(true)
}
}, [siteId])
useEffect(() => {
void load()
if (siteId == null) return
const id = window.setInterval(() => void load(), POLL_MS)
return () => window.clearInterval(id)
}, [load, siteId])
return { sessions, ready, error, reload: load }
}

View File

@@ -0,0 +1,39 @@
import { useCallback, useEffect, useState } from 'react'
import { getSiteStatusFull } from '../api/backend'
import type { FullStatusResponse } from '../types/fullStatus'
const POLL_MS = 30_000
export function useFullStatus(siteId: number | null) {
const [data, setData] = useState<FullStatusResponse | null>(null)
const [ready, setReady] = useState(false)
const [error, setError] = useState<string | null>(null)
const load = useCallback(async () => {
if (siteId == null) {
setData(null)
setError(null)
setReady(true)
return
}
try {
const res = await getSiteStatusFull(siteId)
setData(res)
setError(null)
} catch {
setData(null)
setError('Monitoring stav se nepodařilo načíst')
} finally {
setReady(true)
}
}, [siteId])
useEffect(() => {
void load()
const id = window.setInterval(() => void load(), POLL_MS)
return () => window.clearInterval(id)
}, [load])
return { fullStatus: data, ready, error, reload: load }
}

View File

@@ -7,13 +7,16 @@ const POLL_MS = 5_000
export function useSiteStatus() {
const [row, setRow] = useState<SiteStatusRow | null>(null)
const [ready, setReady] = useState(false)
const [error, setError] = useState<string | null>(null)
const load = useCallback(async () => {
try {
const rows = await getJson<SiteStatusRow[]>('/vw_site_status')
setRow(Array.isArray(rows) && rows.length > 0 ? rows[0]! : null)
setError(null)
} catch {
setRow(null)
setError('Stav lokality se nepodařilo načíst')
} finally {
setReady(true)
}
@@ -35,6 +38,7 @@ export function useSiteStatus() {
return {
site: row,
ready,
error,
/** Máme řádek lokality a alespoň jednu telemetrickou hodnotu (jinak skeleton). */
hasLiveData: row != null && hasTelemetry,
reload: load,

View File

@@ -23,10 +23,12 @@ export type TelemetryChartPoint = {
export function useTelemetryToday(siteId: number | null) {
const [points, setPoints] = useState<TelemetryChartPoint[]>([])
const [ready, setReady] = useState(false)
const [error, setError] = useState<string | null>(null)
const load = useCallback(async () => {
if (siteId == null) {
setPoints([])
setError(null)
setReady(true)
return
}
@@ -37,6 +39,7 @@ export function useTelemetryToday(siteId: number | null) {
})
if (!Array.isArray(rows) || rows.length === 0) {
setPoints([])
setError(null)
return
}
const mapped: TelemetryChartPoint[] = rows.map((r) => {
@@ -55,8 +58,10 @@ export function useTelemetryToday(siteId: number | null) {
}
})
setPoints(mapped)
setError(null)
} catch {
setPoints([])
setError('Hodinová data auditu se nepodařila načíst')
} finally {
setReady(true)
}
@@ -68,5 +73,5 @@ export function useTelemetryToday(siteId: number | null) {
return () => window.clearInterval(id)
}, [load])
return { points, ready, hasChartData: points.length > 0 }
return { points, ready, error, hasChartData: points.length > 0, reload: load }
}