fix(alerts): разделить загрузку каталогов целей и правил
This commit is contained in:
1 parent
a8a3eb59fb
commit
526f305aa6
11 files changed
+153
-77
No files matched your search
@@ -0,0 +1,44 @@
|
||||
"use client"
|
||||
|
||||
import {useCallback,useEffect,useRef,useState} from "react"
|
||||
import {can} from "@/lib/auth"
|
||||
import {getAlertsBgpTargets,getAlertsServerTargets,getAlertsGreTargets} from "@/shared/api/alerts-targets"
|
||||
|
||||
type Snapshot<T>={data:T|undefined;loading:boolean;error:string|null;receivedAt:string|null}
|
||||
type Reader<T>=(base:string,options:{signal:AbortSignal})=>Promise<T>
|
||||
|
||||
// Each catalog owns its lifetime and revision. The page is keyed by source.
|
||||
function useCatalog<T>(base:string,live:boolean,permission:string,read:Reader<T>){
|
||||
const [snapshot,setSnapshot]=useState<Snapshot<T>>({data:undefined,loading:false,error:null,receivedAt:null})
|
||||
const active=useRef(false),revision=useRef(0),controller=useRef<AbortController|null>(null)
|
||||
const refresh=useCallback(async()=>{
|
||||
if(!active.current||!live)return
|
||||
controller.current?.abort();const requestRevision=++revision.current
|
||||
if(!can(permission)){setSnapshot({data:undefined,loading:false,error:"Нет доступа к каталогу",receivedAt:null});return}
|
||||
const request=new AbortController();controller.current=request
|
||||
setSnapshot(previous=>({...previous,loading:true,error:null}))
|
||||
const current=()=>active.current&&requestRevision===revision.current&&can(permission)
|
||||
try{
|
||||
const data=await read(base,{signal:request.signal})
|
||||
if(current())setSnapshot({data,loading:false,error:null,receivedAt:new Date().toISOString()})
|
||||
}catch(error){
|
||||
if(current())setSnapshot(previous=>({...previous,loading:false,error:error instanceof Error?error.message:"Не удалось получить каталог"}))
|
||||
}
|
||||
},[base,live,permission,read])
|
||||
useEffect(()=>{const generation=revision;active.current=true;let pending=true;queueMicrotask(()=>{if(pending)void refresh()});return()=>{pending=false;active.current=false;generation.current++;controller.current?.abort()}},[refresh])
|
||||
return {...snapshot,refresh}
|
||||
}
|
||||
|
||||
async function readGre(base:string,options:{signal:AbortSignal}){
|
||||
const result=await getAlertsGreTargets(base,options)
|
||||
if(result.failures?.length)throw Error("Неполный каталог GRE: не ответили устройства — "+result.failures.map(f=>f.serverName||f.serverId).join(", "))
|
||||
return result
|
||||
}
|
||||
|
||||
export function useAlertsTargets(base:string,live:boolean){
|
||||
const bgp=useCatalog(base,live,"mm:bgp:read",getAlertsBgpTargets)
|
||||
const servers=useCatalog(base,live,"mm:servers:read",getAlertsServerTargets)
|
||||
const gre=useCatalog(base,live,"mm:filters:read",readGre)
|
||||
const refresh=()=>{void bgp.refresh();void servers.refresh();void gre.refresh()}
|
||||
return {bgp,servers,gre,refresh}
|
||||
}
|
||||
Reference in new issue
Block a user