| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- import {
- createContext,
- ReactNode,
- useCallback,
- useContext,
- useEffect,
- useRef,
- useState,
- } from 'react'
- export enum PipelineStatusRequestStatus {
- None = 'None',
- StartRequested = 'StartRequested',
- StopRequested = 'StopRequested',
- RestartRequested = 'RestartRequested',
- }
- interface PipelineRequestStatusContextType {
- requestStatus: Record<number, PipelineStatusRequestStatus>
- pipelineStatusSnapshot: Record<number, string | undefined>
- setRequestStatus: (
- pipelineId: number,
- status: PipelineStatusRequestStatus,
- snapshotStatus?: string
- ) => void
- getRequestStatus: (pipelineId: number) => PipelineStatusRequestStatus
- updatePipelineStatus: (pipelineId: number, backendStatus: string | undefined) => void
- }
- interface PipelineRequestStatusProviderProps {
- children: ReactNode
- }
- const PipelineRequestStatusContext = createContext<PipelineRequestStatusContextType | undefined>(
- undefined
- )
- // [Joshen] Leaving a comment for future investigation
- // Do we need this? Afaict the status is getting returned from the API so we might not need
- // to track the pipeline status on the client side
- export const PipelineRequestStatusProvider = ({ children }: PipelineRequestStatusProviderProps) => {
- const [requestStatus, setRequestStatusState] = useState<
- Record<number, PipelineStatusRequestStatus>
- >({})
- const [pipelineStatusSnapshot, setPipelineStatusSnapshot] = useState<
- Record<number, string | undefined>
- >({})
- const timeoutsRef = useRef<Record<number, number>>({})
- const REQUEST_TIMEOUT_MS = 10_000
- const setRequestStatus = (
- pipelineId: number,
- status: PipelineStatusRequestStatus,
- snapshotStatus?: string
- ) => {
- setRequestStatusState((prev) => ({
- ...prev,
- [pipelineId]: status,
- }))
- setPipelineStatusSnapshot((prev) => {
- if (status === PipelineStatusRequestStatus.None) {
- const { [pipelineId]: _omit, ...rest } = prev
- return rest
- }
- // Only set snapshot when provided to avoid undefined entries
- if (snapshotStatus !== undefined) {
- return { ...prev, [pipelineId]: snapshotStatus }
- }
- return prev
- })
- // Clear existing timeout for this pipeline
- const existing = timeoutsRef.current[pipelineId]
- if (existing !== undefined) {
- clearTimeout(existing)
- delete timeoutsRef.current[pipelineId]
- }
- // Start auto-reset timer for non-None states
- if (status !== PipelineStatusRequestStatus.None) {
- const id = window.setTimeout(() => {
- // If still pending, clear to None to show backend state
- setRequestStatusState((prev) => {
- if (prev[pipelineId] && prev[pipelineId] !== PipelineStatusRequestStatus.None) {
- return { ...prev, [pipelineId]: PipelineStatusRequestStatus.None }
- }
- return prev
- })
- setPipelineStatusSnapshot((prev) => {
- const { [pipelineId]: _omit, ...rest } = prev
- return rest
- })
- delete timeoutsRef.current[pipelineId]
- }, REQUEST_TIMEOUT_MS)
- timeoutsRef.current[pipelineId] = id
- }
- }
- const getRequestStatus = (pipelineId: number): PipelineStatusRequestStatus => {
- return requestStatus[pipelineId] || PipelineStatusRequestStatus.None
- }
- const updatePipelineStatus = useCallback(
- (pipelineId: number, newStatus: string | undefined) => {
- const currentRequestStatus = requestStatus[pipelineId] || PipelineStatusRequestStatus.None
- if (currentRequestStatus === PipelineStatusRequestStatus.None) return
- // Only remove when backend status differs from snapshot
- const snapshotStatus = pipelineStatusSnapshot[pipelineId]
- if (newStatus !== snapshotStatus) {
- setRequestStatus(pipelineId, PipelineStatusRequestStatus.None)
- }
- },
- [requestStatus, pipelineStatusSnapshot]
- )
- // Cleanup all timers on unmount
- useEffect(() => {
- return () => {
- Object.values(timeoutsRef.current).forEach((id) => clearTimeout(id))
- timeoutsRef.current = {}
- }
- }, [])
- return (
- <PipelineRequestStatusContext.Provider
- value={{
- requestStatus,
- pipelineStatusSnapshot,
- setRequestStatus,
- getRequestStatus,
- updatePipelineStatus,
- }}
- >
- {children}
- </PipelineRequestStatusContext.Provider>
- )
- }
- export const usePipelineRequestStatus = () => {
- const context = useContext(PipelineRequestStatusContext)
- if (context === undefined) {
- throw new Error('usePipelineRequestStatus must be used within a PipelineRequestStatusProvider')
- }
- return context
- }
|