@@ -2,6 +2,7 @@ import React, {
22 createContext ,
33 Fragment ,
44 useContext ,
5+ useEffect ,
56 useMemo ,
67 useRef ,
78 useState ,
@@ -34,6 +35,7 @@ export interface ActivityPlanProps {
3435
3536const ActivityPlanContext = createContext < {
3637 collapsed ?: boolean ;
38+ jobLevelMap ?: Map < string , number > ;
3739} > ( { } ) ;
3840
3941export function ActivityPlan ( { task } : ActivityPlanProps ) {
@@ -42,9 +44,12 @@ export function ActivityPlan({ task }: ActivityPlanProps) {
4244 const { toggleAutoScroll } = useContext ( StreamContext ) ;
4345 const flow = flowMap ?. get ( task . id ) ;
4446 const toggleRef = useRef < ReturnType < typeof setTimeout > | null > ( null ) ;
47+ const jobLevelMap = useRef < Map < string , number > > ( new Map ( ) ) ;
4548
4649 return (
47- < ActivityPlanContext . Provider value = { { collapsed } } >
50+ < ActivityPlanContext . Provider
51+ value = { { collapsed, jobLevelMap : jobLevelMap . current } }
52+ >
4853 < div
4954 className = { classNames ( styles . plan , { [ styles . collapsed ] : collapsed } ) }
5055 >
@@ -120,8 +125,34 @@ export interface PlanStepNodeProps {
120125function PlanStepNode ( { step, level, isLast } : PlanStepNodeProps ) {
121126 const isFirstLevel = level === 0 ;
122127 const { jobMap } = useContext ( TaskContext ) ;
123- const { collapsed } = useContext ( ActivityPlanContext ) ;
124- const job = step . jobId ? jobMap ?. get ( step . jobId ) : undefined ;
128+ const { collapsed, jobLevelMap } = useContext ( ActivityPlanContext ) ;
129+ const { jobId } = step ;
130+ const job = jobId ? jobMap ?. get ( jobId ) : undefined ;
131+ const jobLevel = jobId ? jobLevelMap ?. get ( jobId ) : undefined ;
132+ const isCircular = jobLevel !== undefined && jobLevel !== level ;
133+
134+ useEffect ( ( ) => {
135+ if ( ! isCircular && jobId ) {
136+ jobLevelMap ?. set ( jobId , level ) ;
137+ }
138+ } , [ isCircular , level , jobId , jobLevelMap ] ) ;
139+
140+ useEffect ( ( ) => {
141+ if ( isCircular ) {
142+ // eslint-disable-next-line no-console
143+ console . error ( `Circular plan steps detected for job ID: ${ jobId } ` ) ;
144+ }
145+ } , [ isCircular , jobId ] ) ;
146+
147+ if ( isCircular ) {
148+ return (
149+ < li >
150+ < div style = { { color : "var(--color-error)" } } >
151+ Circular plan steps detected
152+ </ div >
153+ </ li >
154+ ) ;
155+ }
125156
126157 return (
127158 < li className = { isFirstLevel ? styles . root : undefined } >
0 commit comments