Skip to content

Commit a6a3e36

Browse files
authored
Merge branch 'main' into 6729-sass
2 parents fd02278 + 177fc53 commit a6a3e36

13 files changed

Lines changed: 535 additions & 90 deletions

File tree

.github/workflows/branch-deploy.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ jobs:
420420
echo "timestamp=$(date +%s)" >> $GITHUB_ENV
421421
422422
- name: Download artifact
423-
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
423+
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
424424
with:
425425
name: k8s-forge
426426
path: /tmp

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ jobs:
8686
private_key: ${{ secrets.GH_BOT_APP_KEY }}
8787

8888
- name: Trigger website rebuild
89-
uses: benc-uk/workflow-dispatch@e2e5e9a103e331dad343f381a29e654aea3cf8fc # v1.2.4
89+
uses: benc-uk/workflow-dispatch@7a027648b88c2413826b6ddd6c76114894dc5ec4 # v1.3.1
9090
with:
9191
workflow: build.yml
9292
repo: flowfuse/website

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ jobs:
122122
private_key: ${{ secrets.GH_BOT_APP_KEY }}
123123

124124
- name: Trigger flowforge container build
125-
uses: benc-uk/workflow-dispatch@e2e5e9a103e331dad343f381a29e654aea3cf8fc # v1.2.4
125+
uses: benc-uk/workflow-dispatch@7a027648b88c2413826b6ddd6c76114894dc5ec4 # v1.3.1
126126
with:
127127
workflow: flowforge-container.yml
128128
repo: flowfuse/helm

frontend/src/components/expert/Expert.vue

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,20 @@ export default {
236236
'product/expert/addWelcomeMessageIfNeeded'
237237
)
238238
}
239+
},
240+
'instance.meta.state': {
241+
handler (newState) {
242+
if (this.isEditorContext && newState !== 'running') {
243+
this.reset() // reset assistant state
244+
}
245+
}
246+
},
247+
'device.status': {
248+
handler (newState) {
249+
if (this.isEditorContext && newState !== 'running') {
250+
this.reset() // reset assistant state
251+
}
252+
}
239253
}
240254
},
241255
mounted () {
@@ -276,6 +290,7 @@ export default {
276290
'setAbortController',
277291
'resetSessionTimer'
278292
]),
293+
...mapActions('product/assistant', ['reset']),
279294
280295
async handleSendMessage (query) {
281296
if (!query.trim()) return

frontend/src/components/expert/ExpertChatInput.vue

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
<div class="left">
3737
<context-selector v-if="!isOperatorAgent" />
3838
<div class="context-items-container" @wheel="horizontalScrolling">
39-
<include-context-item v-for="(context, index) in selectedContext" :key="index" :contextItem="context" />
39+
<include-context-item v-for="(context, index) in selectedContextFiltered" :key="index" :contextItem="context" />
40+
<include-debug-context-button v-if="hasDebugLogsSelected && !isOperatorAgent" />
4041
<include-selection-button v-if="hasUserSelection && !isOperatorAgent" />
4142
</div>
4243
</div>
@@ -75,6 +76,7 @@ import ResizeBar from '../ResizeBar.vue'
7576
import CapabilitiesSelector from './components/CapabilitiesSelector.vue'
7677
import ContextSelector from './components/ContextSelector.vue'
7778
import IncludeContextItem from './components/IncludeContextItem.vue'
79+
import IncludeDebugContextButton from './components/IncludeDebugContextButton.vue'
7880
import IncludeSelectionButton from './components/IncludeSelectionButton.vue'
7981
8082
export default {
@@ -83,6 +85,7 @@ export default {
8385
CapabilitiesSelector,
8486
ContextSelector,
8587
IncludeContextItem,
88+
IncludeDebugContextButton,
8689
IncludeSelectionButton,
8790
ResizeBar
8891
},
@@ -131,7 +134,7 @@ export default {
131134
}
132135
},
133136
computed: {
134-
...mapGetters('product/assistant', ['hasUserSelection', 'getSelectedContext']),
137+
...mapGetters('product/assistant', ['getSelectedContext', 'hasDebugLogsSelected', 'hasUserSelection']),
135138
isInputDisabled () {
136139
if (this.isSessionExpired) return true
137140
if (this.isGenerating) return true
@@ -155,6 +158,9 @@ export default {
155158
return []
156159
}
157160
return this.getSelectedContext
161+
},
162+
selectedContextFiltered () {
163+
return this.selectedContext.filter(c => c.showAsChip !== false)
158164
}
159165
},
160166
mounted () {

frontend/src/components/expert/components/ContextSelector.vue

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
:hide-chevron="true"
1010
:icon-only="true"
1111
return-model
12-
label-key="name"
12+
label-key="label"
1313
placeholder="Context"
1414
open-above
15-
:min-options-width="220"
15+
:options-min-width="250"
1616
align-right
1717
@option-selected="selectItem"
1818
>
@@ -76,19 +76,23 @@ export default {
7676
pluralize,
7777
...mapActions('product/assistant', ['setSelectedContext']),
7878
selectItem (option) {
79-
const cleanOption = (option) => ({
80-
value: option.value,
81-
name: option.name,
82-
title: option.title,
83-
icon: option.icon
84-
})
85-
const cleanedOption = cleanOption(option)
86-
const currentSelection = this.selectedContext || []
87-
const exists = currentSelection.some(c => c.value === cleanedOption.value)
88-
if (exists) {
89-
return // already selected, do nothing
79+
if (option.onSelectAction) {
80+
this.$store.dispatch(`product/assistant/${option.onSelectAction}`)
81+
} else {
82+
const cleanOption = (option) => ({
83+
value: option.value,
84+
name: option.name,
85+
label: option.label,
86+
icon: option.icon
87+
})
88+
const cleanedOption = cleanOption(option)
89+
const currentSelection = this.selectedContext || []
90+
const exists = currentSelection.some(c => c.value === cleanedOption.value)
91+
if (exists) {
92+
return // already selected, do nothing
93+
}
94+
this.setSelectedContext([...currentSelection, cleanedOption].filter(Boolean))
9095
}
91-
this.setSelectedContext([...currentSelection, cleanedOption].filter(Boolean))
9296
}
9397
}
9498
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<template>
2+
<ContextChip
3+
class="flow-selection-button"
4+
:modelValue="modelValue"
5+
@toggle="toggleSelection"
6+
>
7+
<template #text>
8+
<span>Debug</span>
9+
<span class="counter italic" :title="selectionTitle">( {{ selectedCounter }} {{ pluralize('log', selectedCounter) }} )</span>
10+
</template>
11+
</ContextChip>
12+
</template>
13+
14+
<script>
15+
import { mapActions, mapState } from 'vuex'
16+
17+
import { pluralize } from '../../../composables/String.js'
18+
19+
import ContextChip from './ContextChip/index.vue'
20+
21+
export default {
22+
name: 'IncludeDebugContextButton',
23+
components: {
24+
ContextChip
25+
},
26+
props: {
27+
modelValue: {
28+
type: Boolean,
29+
required: false,
30+
default: true
31+
}
32+
},
33+
emits: ['update:modelValue'],
34+
computed: {
35+
...mapState('product/assistant', ['debugLog']),
36+
selectedCounter () {
37+
return this.debugLog.length
38+
},
39+
selectionTitle () {
40+
const map = {}
41+
this.debugLog.forEach(n => {
42+
map[n.type] = (map[n.type] ?? 0) + 1
43+
})
44+
45+
const tipBuilder = (logEntry, index) => {
46+
logEntry = logEntry || {}
47+
const level = logEntry.level || ''
48+
const nonDebugLevel = level !== 'debug' ? level : ''
49+
const topic = logEntry.metadata?.topic || ''
50+
const name = logEntry.source?.name || logEntry.source?.id || logEntry.metadata?.path || ''
51+
const format = logEntry.metadata?.format || ''
52+
const type = logEntry.source?.type || ''
53+
const property = logEntry.metadata?.property || ''
54+
const strBuilder = []
55+
if (name) strBuilder.push(`node: ${name}`)
56+
if (topic) strBuilder.push(`topic: ${topic}`)
57+
if (nonDebugLevel) {
58+
if (type) {
59+
strBuilder.push(`${type} : (${nonDebugLevel})`)
60+
}
61+
}
62+
if (property) {
63+
if (format) {
64+
strBuilder.push(`property: ${property} ${format}`)
65+
} else {
66+
strBuilder.push(`property: ${property}`)
67+
}
68+
}
69+
return `${index + 1}: ${strBuilder.join(', ')}`
70+
}
71+
72+
const list = this.debugLog.map(tipBuilder).join('\n')
73+
74+
return `Selected Logs: \n${list}`
75+
}
76+
},
77+
methods: {
78+
...mapActions('product/assistant', ['resetDebugLogContext']),
79+
pluralize,
80+
toggleSelection () {
81+
this.$emit('update:modelValue', !this.modelValue)
82+
this.resetDebugLogContext()
83+
}
84+
}
85+
}
86+
</script>
87+
88+
<style lang="scss">
89+
.flow-selection-button {
90+
.text {
91+
.counter {
92+
color: $ff-grey-500;
93+
margin-left: 4px;
94+
font-size: $ff-funit-xs;
95+
}
96+
}
97+
}
98+
</style>

0 commit comments

Comments
 (0)