diff --git a/frontend/src/components/drawers/expert/ExpertDrawer.vue b/frontend/src/components/drawers/expert/ExpertDrawer.vue index 4c2878c6e1..b7ab60d7c4 100644 --- a/frontend/src/components/drawers/expert/ExpertDrawer.vue +++ b/frontend/src/components/drawers/expert/ExpertDrawer.vue @@ -35,7 +35,7 @@ - + @@ -90,9 +90,9 @@ export default { } }, mounted () { - // Wait for drawer slide-in animation to complete (300ms) before focusing + // Wait for drawer slide-in animation to complete (300ms) before focusing the chat input setTimeout(() => { - this.$refs.drawer?.focus() + this.$refs.panel?.focusInput() }, 350) }, methods: { diff --git a/frontend/src/components/expert/Expert.vue b/frontend/src/components/expert/Expert.vue index e0298b2017..ae82a1b764 100644 --- a/frontend/src/components/expert/Expert.vue +++ b/frontend/src/components/expert/Expert.vue @@ -18,7 +18,7 @@ - + @@ -153,6 +153,9 @@ export default { ]), ...mapActions(useProductExpertInsightsAgentStore, ['getCapabilities']), ...mapActions(useProductAssistantStore, ['reset']), + focusInput () { + this.$refs.chatInput?.focusInput() + }, handleStopGeneration () { if (this.abortController) { this.abortController.abort() diff --git a/frontend/src/components/expert/components/ExpertChatInput.vue b/frontend/src/components/expert/components/ExpertChatInput.vue index 0b4bfc8807..a485e64d76 100644 --- a/frontend/src/components/expert/components/ExpertChatInput.vue +++ b/frontend/src/components/expert/components/ExpertChatInput.vue @@ -242,6 +242,11 @@ export default { } }, watch: { + isWaitingForResponse (waiting, wasWaiting) { + if (wasWaiting && !waiting) { + this.$nextTick(() => this.$refs.textarea?.focus()) + } + }, pendingInput (text) { if (text) { this.inputText = text @@ -282,6 +287,9 @@ export default { methods: { ...mapActions(useProductAssistantStore, ['resetContextSelection']), ...mapActions(useProductExpertStore, ['startOver', 'handleQuery', 'setPendingInput', 'setComposerCommand', 'setQuestionCadence', 'setPlanMode', 'fetchToolCatalog']), + focusInput () { + this.$refs.textarea?.focus() + }, openSettings () { this.$refs.settingsDialog.show() }, @@ -295,15 +303,10 @@ export default { this.togglePinWithWidth() } - // handleQuery renders the reply itself (see the store); the composer only needs - // to refocus the input once the turn is on its way. - this.handleQuery({ query: message }) - .then(() => { - this.$nextTick(() => { - this.$refs.textarea.focus() - }) - }) - .catch(e => e) + // handleQuery renders the reply itself (see the store); the isWaitingForResponse + // watcher refocuses the input once the response completes (works for both HTTP + // and MQTT, where the promise resolves before the actual response arrives). + this.handleQuery({ query: message }).catch(e => e) this.inputText = '' this.requestingPlanChange = false