Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d71c172
Alter the expert's chat input
cstns Jan 27, 2026
d03b8eb
Add horizontal resizing support to `ResizeBar` component
cstns Jan 27, 2026
ee0adb1
Add resizable height functionality to `ExpertChatInput` component
cstns Jan 27, 2026
75fcbde
Refactor `ExpertChatInput` to use `ResizingHelper` composable for hei…
cstns Jan 28, 2026
ebdb477
Merge branch 'refs/heads/main' into 6563_alter-expert-chat-input
cstns Jan 28, 2026
5d8f501
Refactor `ExpertChatInput` and adjust button styles for `Capabilities…
cstns Jan 28, 2026
73578c8
Merge branch '6561_create-ui-component-for-including-selection' into …
cstns Jan 28, 2026
806c083
Update `ExpertChatInput` to conditionally show `IncludeSelectionButto…
cstns Jan 29, 2026
ed003a6
Add `assistantFeatures` state and expose version, features, and selec…
cstns Jan 29, 2026
9f91e4b
Remove debug `console.log` from `assistant-ready` action handler
cstns Jan 29, 2026
0759ea6
Add `nodeRedVersion` state and mutation to manage Node-RED version in…
cstns Jan 29, 2026
70c0609
Fix inconsistent state referencing for `selectedNodes` in context module
cstns Jan 29, 2026
c662362
Fix inconsistent state referencing for `selectedNodes` in context mod…
cstns Jan 29, 2026
7c6dfd0
Fix inconsistent state access for `assistantVersion`, `nodeRedVersion…
cstns Jan 29, 2026
4a375ea
Refactor `nodeRedVersion` state placement for consistency in context …
cstns Jan 29, 2026
80d4320
Add dynamic event subscriptions
Steve-Mcl Jan 29, 2026
2e4e0e4
Show issues and suggestions in chat output
Steve-Mcl Jan 29, 2026
000aa64
Merge branch 'main' into 6563_alter-expert-chat-input
cstns Jan 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 134 additions & 49 deletions frontend/src/components/expert/ExpertChatInput.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<template>
<div class="ff-expert-input">
<div ref="resizeTarget" class="ff-expert-input" :style="{height: heightStyle}">
<resize-bar
direction="horizontal"
@mousedown="startResize"
/>
<!-- Action buttons row -->
<div class="action-buttons">
<button
Expand All @@ -12,44 +16,65 @@
</button>
<div class="right-buttons">
<capabilities-selector v-if="isOperatorAgent" />
<button
v-if="isGenerating && !isSessionExpired"
type="button"
class="btn-stop"
@click="handleStop"
>
Stop
</button>
<button
v-else-if="!isSessionExpired"
type="button"
class="btn-send"
:disabled="!canSend"
@click="handleSend"
>
Send
</button>
</div>
</div>
<div class="input-wrapper" :class="{ 'focused': isTextareaFocused }">
<!-- Textarea -->
<textarea
ref="textarea"
v-model="inputText"
class="chat-input"
:placeholder="placeholderText"
:disabled="isInputDisabled"
@keydown="handleKeydown"
@focus="isTextareaFocused = true"
@blur="isTextareaFocused = false"
/>

<!-- Textarea -->
<textarea
ref="textarea"
v-model="inputText"
class="chat-input"
:placeholder="placeholderText"
:disabled="isInputDisabled"
@keydown="handleKeydown"
/>
<div class="actions">
<div class="left">
<include-selection-button v-if="hasUserSelection && !isOperatorAgent" />
</div>

<div class="right">
<button
v-if="isGenerating && !isSessionExpired"
type="button"
class="btn-stop"
@click="handleStop"
>
Stop
</button>
<button
v-else-if="!isSessionExpired"
type="button"
class="btn-send"
:disabled="!canSend"
@click="handleSend"
>
Send
</button>
</div>
</div>
</div>
</div>
</template>

<script>
import { mapGetters } from 'vuex'

import { useResizingHelper } from '../../composables/ResizingHelper.js'

import ResizeBar from '../../pages/instance/Editor/components/drawer/ResizeBar.vue'

import CapabilitiesSelector from './components/CapabilitiesSelector.vue'
import IncludeSelectionButton from './components/IncludeSelectionButton.vue'

export default {
name: 'ExpertChatInput',
components: {
ResizeBar,
IncludeSelectionButton,
CapabilitiesSelector
},
props: {
Expand Down Expand Up @@ -79,12 +104,24 @@ export default {
}
},
emits: ['send', 'stop', 'start-over'],
setup () {
const { startResize, heightStyle, bindResizer } = useResizingHelper()

return {
startResize,
bindResizer,
heightStyle
}
},
data () {
return {
inputText: ''
inputText: '',
includeSelection: true,
isTextareaFocused: false
}
},
computed: {
...mapGetters('product/assistant', ['hasUserSelection']),
isInputDisabled () {
if (this.isSessionExpired) return true
if (this.isGenerating) return true
Expand All @@ -103,6 +140,15 @@ export default {
: 'Tell us what you need help with'
}
},
mounted () {
this.bindResizer({
component: this.$refs.resizeTarget,
mobileBreakpoint: 640, // match your app breakpoint
maxHeightRatio: 0.9, // whatever you want the cap to be
minHeight: 120, // optional: stop it collapsing to 0
maxViewportMarginY: 80 // optional: keep some space
})
},
methods: {
handleSend () {
if (!this.canSend) return
Expand Down Expand Up @@ -142,13 +188,16 @@ export default {
border-top: 1px solid #E5E7EB; // border-gray-200
background: white;
flex-shrink: 0; // Prevent input area from shrinking
position: relative;
min-height: 15vh;
max-height: 40vh;
}

.action-buttons {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem; // pb-4
margin-bottom: 0.5rem;
}

.right-buttons {
Expand All @@ -174,6 +223,8 @@ button {
background-color: white;
color: inherit;
border-color: #C7D2FE; // indigo-300
padding: 0.25rem 0.50rem;
border-radius: 5px;

&:hover:not(:disabled) {
background-color: #F9FAFB; // gray-50
Expand All @@ -184,6 +235,8 @@ button {
background-color: $ff-indigo-600;
color: white;
border-color: $ff-indigo-600;
border-radius: 5px;
padding: 0.25rem 0.50rem;

&:hover:not(:disabled) {
background-color: $ff-indigo-700;
Expand All @@ -197,6 +250,8 @@ button {
display: flex;
align-items: center;
gap: 0.5rem;
border-radius: 5px;
padding: 0.25rem 0.50rem;

&::before {
content: '';
Expand All @@ -211,33 +266,63 @@ button {
}
}

.chat-input {
width: 100%;
height: 6rem; // h-24
padding: 1rem; // p-4
.input-wrapper {
flex: 1;
display: flex;
flex-direction: column;
min-height: 10vh;
border: 2px solid #D1D5DB; // border-2 border-gray-300
border-radius: 0.5rem; // rounded-lg
font-size: 0.875rem; // text-sm
line-height: 1.5;
color: #111827; // text-gray-900
resize: none;
outline: none;
font-family: inherit;
background: white;
transition: border-color 0.2s ease;

&:focus {
border-color: $ff-indigo-500; // focus:border-indigo-500
outline: none;
&.focused {
border-color: $ff-indigo-500;
}

&:disabled {
cursor: not-allowed;
background-color: #F9FAFB; // bg-gray-50
color: #6B7280; // text-gray-500
.chat-input {
flex: 1;
width: 100%;
padding: 1rem; // p-4
box-sizing: border-box;
overflow-y: auto;
border: none;
outline: none;
font-size: 0.875rem; // text-sm
line-height: 1.5;
color: #111827; // text-gray-900
resize: none;
font-family: inherit;
background: white;

&:focus {
outline: none;
}

&:disabled {
cursor: not-allowed;
background-color: #F9FAFB; // bg-gray-50
color: #6B7280; // text-gray-500
}

&::placeholder {
color: #9CA3AF; // placeholder gray
}
}

&::placeholder {
color: #9CA3AF; // placeholder gray
.actions {
padding: .5rem;
display: flex;
justify-content: space-between;

.left {
display: flex;
justify-content: flex-start;
}

.right {
display: flex;
justify-content: flex-end;
}
}
}
</style>
27 changes: 26 additions & 1 deletion frontend/src/components/expert/ExpertChatMessage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,19 @@ export default {
return this.sanitize(this.message.content)
}
// Convert markdown to HTML
const html = marked(this.message.content || '', {
const content = []
content.push(this.message.content || '')
if (this.message.resources?.issues?.length > 0) {
content.push('\n\n')
content.push('**Issues:**')
content.push(this.message.resources.issues.map(issue => `\n- ${this.sanitize(issue)}`).join(''))
}
if (this.message.resources?.suggestions?.length > 0) {
content.push('\n\n')
content.push('**Suggestions:**')
content.push(this.message.resources.suggestions.map(suggestion => `\n- ${this.sanitize(suggestion)}`).join(''))
}
const html = marked(content.join('\n'), {
breaks: true,
gfm: true
})
Expand All @@ -65,6 +77,18 @@ export default {
utm_campaign: 'expert-chat'
}
})
},
issues () {
return this.resources.issues
},
suggestions () {
return this.resources.suggestions
},
hasIssues () {
return (this.resources.issues && this.resources.issues.length > 0)
},
hasSuggestions () {
return (this.resources.suggestions && this.resources.suggestions.length > 0)
}
}
}
Expand Down Expand Up @@ -149,6 +173,7 @@ export default {
:deep(ul), :deep(ol) {
margin: 0.5rem 0;
padding-left: 1.5rem;
list-style: square;
}

:deep(li) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ export default {
}

button.ff-button {
padding: 0.5rem 0.75rem;
border: 1px solid #c7d2fe; // indigo-300 to match other buttons
border-radius: 9999px; // pill shape
border-radius: 5px;
padding: 0.25rem 0.50rem;
background: $ff-white;
color: #1f2937; // gray-800, explicit dark text
font-size: 0.875rem;
Expand Down Expand Up @@ -201,7 +201,6 @@ export default {
background: $ff-indigo-600;
border-color: $ff-indigo-600;
color: $ff-white;
border-radius: 9999px; // keep pill shape when open

.icon {
svg {
Expand Down
Loading
Loading