22 <v-container fluid >
33 <v-row >
44 <v-col
5- sm =" 3 "
5+ sm =" 4 "
66 >
77 <v-sheet
88 rounded =" lg"
2121 />
2222 <v-list shaped >
2323 <v-list-item-group
24- v-model =" selected_topics "
25- multiple
24+ v-model =" selected_topic "
25+ mandatory
2626 >
2727 <template v-for =" (item , i ) in filtered_topics " >
2828 <v-list-item
3636 </v-list-item-content >
3737
3838 <v-list-item-action >
39- <v-checkbox
39+ <v-radio
4040 :input-value =" active"
4141 color =" deep-purple accent-4"
4242 />
5151 </v-col >
5252
5353 <v-col
54- sm =" 6"
55- height =" 700px"
56- >
57- <v-sheet
58- rounded =" lg"
59- >
60- <v-card >
61- <v-virtual-scroll
62- :items =" messages_in_view"
63- :item-height =" 40"
64- height =" 700px"
65- >
66- <template #default =" { item } " >
67- <v-list-item
68- @click =" showDetailed(item)"
69- >
70- <v-list-item-content >
71- <v-list-item-title >
72- {{ item.timestamp.toLocaleString() }} | {{ item.topic }}: {{ item.payload }}
73- </v-list-item-title >
74- </v-list-item-content >
75- </v-list-item >
76- </template >
77- </v-virtual-scroll >
78- </v-card >
79- </v-sheet >
80- </v-col >
81-
82- <v-col
83- sm =" 3"
54+ sm =" 8"
8455 >
8556 <v-card
86- v-if =" detailed_message "
57+ v-if =" selected_topic "
8758 outlined
8859 width =" 100%"
60+ height =" 700px"
8961 >
62+ <v-card-title >
63+ {{ selected_topic }}
64+ </v-card-title >
9065 <v-card-text
91- style =" overflow : auto ;"
66+ style =" overflow : auto ; height : calc ( 100 % - 48 px ); "
9267 >
93- <pre > {{ detailed_message }} </pre >
68+ <pre >{{ formatMessage(current_message) }}</pre >
9469 </v-card-text >
9570 </v-card >
9671 </v-col >
@@ -107,49 +82,14 @@ interface ZenohMessage {
10782 timestamp: Date
10883}
10984
110- class ZenohMessageTable {
111- messages: ZenohMessage [] = []
112- topics: Set <string > = new Set ()
113- size_limit = 1000 // Maximum number of messages to store
114-
115- add(topic : string , payload : string ): void {
116- const message: ZenohMessage = {
117- topic ,
118- payload ,
119- timestamp: new Date ()
120- }
121-
122- this .messages .push (message )
123- this .topics .add (topic )
124-
125- if (this .messages .length > this .size_limit ) {
126- this .messages .shift ()
127- }
128- }
129-
130- getTopics(): string [] {
131- return Array .from (this .topics ).sort ()
132- }
133-
134- getMessages(selectedTopics : string []): ZenohMessage [] {
135- if (selectedTopics .length === 0 ) return []
136- return this .messages
137- .filter (msg => selectedTopics .includes (msg .topic ))
138- .sort ((a , b ) => a .timestamp .getTime () - b .timestamp .getTime ())
139- }
140- }
141-
14285export default Vue .extend ({
14386 name: ' ZenohInspector' ,
14487 data() {
14588 return {
14689 topics: [] as string [],
147- message_table: new ZenohMessageTable () ,
90+ messages: {} as { [ key : string ] : ZenohMessage } ,
14891 topic_interval: 0 ,
149- messages_in_view_interval: 0 ,
150- messages_in_view: [] as ZenohMessage [],
151- selected_topics: [] as string [],
152- detailed_message: null as (null | ZenohMessage ),
92+ selected_topic: null as string | null ,
15393 topic_filter: ' ' ,
15494 session: null as Session | null ,
15595 subscriber: null as Subscriber | null ,
@@ -165,21 +105,37 @@ export default Vue.extend({
165105 return this .topics
166106 }
167107 },
108+ current_message(): ZenohMessage | null {
109+ if (! this .selected_topic ) return null
110+ return this .messages [this .selected_topic ] || null
111+ }
168112 },
169113 async mounted() {
170114 await this .setupZenoh ()
171115 },
172116 beforeDestroy() {
173117 clearInterval (this .topic_interval )
174- clearInterval (this .messages_in_view_interval )
175118 this .disconnectZenoh ()
176119 },
177120 methods: {
178- update_messages_in_view() {
179- this .messages_in_view = this .message_table .getMessages (this .selected_topics )
180- },
181- showDetailed(message : ZenohMessage ) {
182- this .detailed_message = message
121+ formatMessage(message : ZenohMessage | null ): string {
122+ if (! message ) return ' No messages received yet'
123+
124+ try {
125+ const parsedPayload = JSON .parse (message .payload )
126+ return JSON .stringify ({
127+ topic: message .topic ,
128+ timestamp: message .timestamp .toLocaleString (),
129+ payload: parsedPayload
130+ }, null , 2 )
131+ } catch (e ) {
132+ // If payload is not valid JSON, return the raw message
133+ return JSON .stringify ({
134+ topic: message .topic ,
135+ timestamp: message .timestamp .toLocaleString (),
136+ payload: message .payload
137+ }, null , 2 )
138+ }
183139 },
184140 async setupZenoh() {
185141 try {
@@ -190,15 +146,22 @@ export default Vue.extend({
190146 this .subscriber = await this .session .declare_subscriber (' **' , {
191147 handler : (sample : Sample ) => {
192148 const topic = sample .keyexpr ().toString ()
193- const payload = sample .payload ().to_string ()
194- this .message_table .add (topic , payload )
149+ const message: ZenohMessage = {
150+ topic ,
151+ payload: sample .payload ().to_string (),
152+ timestamp: new Date ()
153+ }
154+
155+ // Update messages and topics
156+ this .$set (this .messages , topic , message )
157+ if (! this .topics .includes (topic )) {
158+ this .topics = [... this .topics , topic ].sort ()
159+ }
160+
195161 return Promise .resolve ()
196162 }
197163 })
198164 console .log (' [Zenoh] Subscribed to all topics' )
199-
200- this .messages_in_view_interval = setInterval (() => this .update_messages_in_view (), 500 )
201- this .topic_interval = setInterval (() => { this .topics = this .message_table .getTopics () }, 1000 )
202165 } catch (error ) {
203166 console .error (' [Zenoh] Connection error:' , error )
204167 }
0 commit comments