I have a process that takes some time to complete and I wanted to add a Vue Timeline to show which steps are being executed. So the idea was that in the process (long chain of various nodes), at certain steps I branch out to the below ui-template node. So the same message is sent to this UI template, with different content, some properies are getting added as more steps are executed in the process.
The ui-template looks like this:
<template>
<v-timeline side="end">
<v-timeline-item :dot-color="voice_color" size="small">
<div class="d-flex">
<strong class="me-4">{{voice_amount}}</strong>
<div>
<strong>Audio recording</strong>
<div class="text-body-small">
{{voice_text}}
</div>
</div>
</div>
</v-timeline-item>
<v-timeline-item :dot-color="whisper_color" size="small">
<div class="d-flex">
<strong class="me-4">{{whisper_amount}}</strong>
<div>
<strong>Transcribe Audio</strong>
<div class="text-body-small">
{{whisper_text}}
</div>
</div>
</div>
</v-timeline-item>
<v-timeline-item :dot-color="llm_color" size="small">
<div class="d-flex">
<strong class="me-4">{{llm_amount}}</strong>
<div>
<strong>Recognize Intent</strong>
<div class="text-body-small">
{{llm_text}}
</div>
</div>
</div>
</v-timeline-item>
</v-timeline>
</template>
<script>
export default {
data() {
// define variables available component-wide
// (in <template> and component functions)
return {
voice_color: 'grey',
voice_text: 'No Audio',
voice_amount: '',
whisper_color: 'grey',
whisper_text: 'Not completed yet',
whisper_amount: '',
llm_color: 'grey',
llm_text: 'Not triggered yet',
llm_amount: '',
}
},
watch: {
// watch for any changes of "count"
msg: function(){
this.resetDefaults();
if (this.msg.rec_start) {
this.voice_color = 'red';
this.voice_amount = '';
this.voice_text = 'Recording...';
}
if (this.msg.fname !== undefined) {
this.voice_color = 'green';
this.voice_amount = 'Saved';
this.voice_text = this.msg.fname;
this.whisper_color = 'yellow';
}
if (this.msg.transcribedtext !== undefined) {
this.whisper_color = 'green';
this.whisper_amount = this.msg.whisperseconds + "ms";
this.whisper_text = this.msg.transcribedtext;
this.llm_color = 'yellow';
}
if (this.msg.llmoutputstep) {
if (!this.msg.payload.done) {
this.llm_color = 'red';
this.llm_amount = this.msg.llmseconds + "ms";
this.llm_text = "Error";
} else {
this.llm_color = 'green';
this.llm_amount = this.msg.llmseconds + "ms";
this.llm_text = this.msg.payload.message.content;
}
}
}
},
computed: {
},
methods: {
// expose a method to our <template> and Vue Application
resetDefaults() {
this.voice_color = 'grey';
this.voice_text = 'No Audio';
this.voice_amount = '';
this.whisper_color = 'grey';
this.whisper_text = 'Not completed yet';
this.whisper_amount = '';
this.llm_color = 'grey';
this.llm_text = 'Not triggered yet';
this.llm_amount = '';
}
},
mounted() {
// code here when the component is first loaded
},
unmounted() {
// code here when the component is removed from the Dashboard
// i.e. when the user navigates away from the page
}
}
</script>
It sort of works and sort of not:
- when I restart the process, I would expect step 2 and 3 to be grey because the default values, but they seem to show the values from the previous message. Although the new message clearly does not have the properties in the if statements.
- if I send an empty payload, it does not reset the UI to the grey states that I expect.
I have not done much Node-Red work in the past few months, but I am sure I have not forgotten that much, and the basic if logic is correct. If certain attributes do not exists the UI should fall back to the default color/text.
I asked Gemini about this, he said that insteal of this.msg.... I should change the watch to a handler: function(val) { and deep: true, but that seem to make no difference at all.
I am looking at this for a few hours now and just can't figure out what I have done wrong.
P.S. ignore some of the comments on the code, it is from an earlier template node.