@@ -31,6 +31,14 @@ function BehaviorTreePanel({ context }: { context: PanelExtensionContext }): Rea
3131 const [ panelState , setPanelState ] = useState < PanelState > ( ( ) => {
3232 return ( context . initialState as PanelState | undefined ) ?? { } ;
3333 } ) ;
34+
35+
36+ // const [behaviorTreeXmlTopic, setBehaviorTreeXmlTopic] = useState<string | undefined>(
37+ // panelState.behaviorTreeXmlTopic,
38+ // );
39+ // const [behaviorTreeLogsTopic, setBehaviorTreeLogsTopic] = useState<string | undefined>(
40+ // panelState.behaviorTreeLogsTopic,
41+ // );
3442 const [ behaviorTreeXml , setBehaviorTreeXml ] = useState < string | undefined > ( ) ;
3543 const [ behaviorTreeLogs , setBehaviorTreeLogs ] = useState < BehaviorTreeLog | undefined > ( ) ;
3644
@@ -56,6 +64,16 @@ function BehaviorTreePanel({ context }: { context: PanelExtensionContext }): Rea
5664
5765 // We use a layout effect to setup render handling for our panel. We also setup some topic subscriptions.
5866 useLayoutEffect ( ( ) => {
67+ // After adding a render handler, you must indicate which fields from RenderState will trigger updates.
68+ // If you do not watch any fields then your panel will never render since the panel context will assume you do not want any updates.
69+
70+ // tell the panel context that we care about any update to the _topic_ field of RenderState
71+ context . watch ( "topics" ) ;
72+
73+ // tell the panel context we want messages for the current frame for topics we've subscribed to
74+ // This corresponds to the _currentFrame_ field of render state.
75+ context . watch ( "currentFrame" ) ;
76+
5977 // The render handler is run by the broader Foxglove system during playback when your panel
6078 // needs to render because the fields it is watching have changed. How you handle rendering depends on your framework.
6179 // You can only setup one render handler - usually early on in setting up your panel.
@@ -79,12 +97,25 @@ function BehaviorTreePanel({ context }: { context: PanelExtensionContext }): Rea
7997 const messages = renderState . currentFrame . filter (
8098 ( msg ) => msg . topic === panelState . behaviorTreeXmlTopic ,
8199 ) ;
82- const latestMessage = messages [ messages . length - 1 ] ; // Get the latest message
83100
84- if ( latestMessage ) {
85- const messageData = latestMessage . message as { data ?: string } ;
86- if ( messageData . data ) {
87- setBehaviorTreeXml ( messageData . data ) ;
101+ if ( messages . length > 0 ) {
102+ const latestMessage = messages [ messages . length - 1 ] ;
103+
104+ if ( latestMessage ?. message ) {
105+ let xmlData : string | undefined ;
106+
107+ if ( typeof latestMessage . message === "string" ) {
108+ xmlData = latestMessage . message ;
109+ } else if (
110+ typeof latestMessage . message === "object" &&
111+ "data" in latestMessage . message
112+ ) {
113+ xmlData = ( latestMessage . message as { data ?: string } ) . data ;
114+ }
115+
116+ if ( xmlData && typeof xmlData === "string" ) {
117+ setBehaviorTreeXml ( xmlData ) ;
118+ }
88119 }
89120 }
90121 }
@@ -93,48 +124,63 @@ function BehaviorTreePanel({ context }: { context: PanelExtensionContext }): Rea
93124 const messages = renderState . currentFrame . filter (
94125 ( msg ) => msg . topic === panelState . behaviorTreeLogsTopic ,
95126 ) ;
96- const latestMessage = messages [ messages . length - 1 ] ; // Get the latest message
97127
98- if ( latestMessage ) {
99- const messageData = latestMessage . message as { data ?: BehaviorTreeLog } ;
100- if ( messageData . data ) {
101- setBehaviorTreeLogs ( messageData . data ) ;
128+ if ( messages . length > 0 ) {
129+ const latestMessage = messages [ messages . length - 1 ] ;
130+
131+ if ( latestMessage ?. message ) {
132+ let logData : BehaviorTreeLog | undefined ;
133+
134+ if ( typeof latestMessage . message === "object" ) {
135+ if ( "data" in latestMessage . message ) {
136+ logData = ( latestMessage . message as { data ?: BehaviorTreeLog } ) . data ;
137+ } else {
138+ logData = latestMessage . message as BehaviorTreeLog ;
139+ }
140+ }
141+
142+ if ( logData ) {
143+ setBehaviorTreeLogs ( logData ) ;
144+ }
102145 }
103146 }
104147 }
105148 } ;
149+ } , [ context , panelState ] ) ;
106150
107- // After adding a render handler, you must indicate which fields from RenderState will trigger updates.
108- // If you do not watch any fields then your panel will never render since the panel context will assume you do not want any updates.
109-
110- // tell the panel context that we care about any update to the _topic_ field of RenderState
111- context . watch ( "topics" ) ;
112-
113- // tell the panel context we want messages for the current frame for topics we've subscribed to
114- // This corresponds to the _currentFrame_ field of render state.
115- context . watch ( "currentFrame" ) ;
151+ // Handle topic subscriptions in a separate effect that runs when topics change
152+ useEffect ( ( ) => {
153+ const subscriptions = [ ] ;
116154
117- // Subscribe to the selected topic
118155 if ( panelState . behaviorTreeXmlTopic ) {
119- context . subscribe ( [ { topic : panelState . behaviorTreeXmlTopic } ] ) ;
156+ subscriptions . push ( { topic : panelState . behaviorTreeXmlTopic } ) ;
120157 }
121158
122159 if ( panelState . behaviorTreeLogsTopic ) {
123- context . subscribe ( [ { topic : panelState . behaviorTreeLogsTopic } ] ) ;
160+ subscriptions . push ( { topic : panelState . behaviorTreeLogsTopic } ) ;
161+ }
162+
163+ if ( subscriptions . length > 0 ) {
164+ context . subscribe ( subscriptions ) ;
165+ } else {
166+ // Subscribe to empty array to clear previous subscriptions
167+ context . subscribe ( [ ] ) ;
124168 }
125169 } , [ context , panelState . behaviorTreeXmlTopic , panelState . behaviorTreeLogsTopic ] ) ;
126170
127171 // Setup panel settings
128172 useEffect ( ( ) => {
129173 const actionHandler = ( action : SettingsTreeAction ) => {
130- if (
131- action . action === "update" &&
132- action . payload . path [ 0 ] === "behaviorTreeXmlTopic" &&
133- action . payload . path [ 1 ] === "topic"
134- ) {
174+
175+ const path = action . payload . path . join ( "." ) ;
176+ if ( action . action === "update" && path === "behaviorTreeTopics.behaviorTreeXmlTopic" ) {
135177 const newTopic = action . payload . value as string ;
136178 setPanelState ( ( prev ) => ( { ...prev , behaviorTreeXmlTopic : newTopic } ) ) ;
137179 }
180+ if ( action . action === "update" && path === "behaviorTreeTopics.behaviorTreeLogsTopic" ) {
181+ const newTopic = action . payload . value as string ;
182+ setPanelState ( ( prev ) => ( { ...prev , behaviorTreeLogsTopic : newTopic } ) ) ;
183+ }
138184 } ;
139185
140186 context . updatePanelSettingsEditor ( {
0 commit comments