Skip to content

Commit

Permalink
feat(editor): Retrieve previous chat message on arrow-up (#8696)
Browse files Browse the repository at this point in the history
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
  • Loading branch information
OlegIvaniv authored Feb 22, 2024
1 parent a5e6f59 commit 246f8cf
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 5 deletions.
1 change: 1 addition & 0 deletions packages/editor-ui/src/Interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,7 @@ export interface WorkflowsState {
workflowExecutionData: IExecutionResponse | null;
workflowExecutionPairedItemMappings: { [itemId: string]: Set<string> };
workflowsById: IWorkflowsMap;
chatMessages: string[];
isInDebugMode?: boolean;
}

Expand Down
27 changes: 23 additions & 4 deletions packages/editor-ui/src/components/WorkflowLMChat.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
</div>
<MessageTyping v-if="isLoading" ref="messageContainer" />
</div>
<div v-if="node" class="logs-wrapper" data-test-id="lm-chat-logs">
<div v-if="node && messages.length" class="logs-wrapper" data-test-id="lm-chat-logs">
<n8n-text class="logs-title" tag="p" size="large">{{
$locale.baseText('chat.window.logs')
}}</n8n-text>
Expand Down Expand Up @@ -149,8 +149,8 @@ import { useExternalHooks } from '@/composables/useExternalHooks';
// eslint-disable-next-line import/no-unresolved
import MessageTyping from '@n8n/chat/components/MessageTyping.vue';
import { useRouter } from 'vue-router';
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
import { useRouter } from 'vue-router';
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
const RunDataAi = defineAsyncComponent(
Expand Down Expand Up @@ -183,8 +183,8 @@ export default defineComponent({
},
mixins: [workflowRun],
setup(props, ctx) {
const externalHooks = useExternalHooks();
const router = useRouter();
const externalHooks = useExternalHooks();
const workflowHelpers = useWorkflowHelpers(router);
return {
Expand All @@ -203,6 +203,7 @@ export default defineComponent({
modalBus: createEventBus(),
node: null as INodeUi | null,
WORKFLOW_LM_CHAT_MODAL_KEY,
previousMessageIndex: 0,
};
},
Expand All @@ -216,6 +217,8 @@ export default defineComponent({
this.setConnectedNode();
this.messages = this.getChatMessages();
this.setNode();
setTimeout(() => this.$refs.inputField?.focus(), 0);
},
methods: {
displayExecution(executionId: string) {
Expand All @@ -235,6 +238,20 @@ export default defineComponent({
inputField.focus();
},
updated(event: KeyboardEvent) {
const pastMessages = this.workflowsStore.getPastChatMessages;
if (
(this.currentMessage.length === 0 || pastMessages.includes(this.currentMessage)) &&
event.key === 'ArrowUp'
) {
const inputField = this.$refs.inputField as HTMLInputElement;
inputField?.blur();
this.currentMessage =
pastMessages[pastMessages.length - 1 - this.previousMessageIndex] ?? '';
this.previousMessageIndex = (this.previousMessageIndex + 1) % pastMessages.length;
// Refocus to move the cursor to the end of the input
setTimeout(() => inputField?.focus(), 0);
}
if (event.key === 'Enter' && !event.shiftKey && this.currentMessage) {
void this.sendChatMessage(this.currentMessage);
event.stopPropagation();
Expand All @@ -255,6 +272,7 @@ export default defineComponent({
} as ChatMessage);
this.currentMessage = '';
this.previousMessageIndex = 0;
await this.$nextTick();
this.scrollToLatestMessage();
await this.startWorkflowWithMessage(message);
Expand All @@ -272,7 +290,7 @@ export default defineComponent({
}
const workflow = this.workflowHelpers.getCurrentWorkflow();
const chatNode = this.workflowHelpers.getNodes().find((node: INodeUi): boolean => {
const chatNode = this.workflowsStore.getNodes().find((node: INodeUi): boolean => {
const nodeType = this.nodeTypesStore.getNodeType(node.type, node.typeVersion);
if (!nodeType) return false;
Expand Down Expand Up @@ -454,6 +472,7 @@ export default defineComponent({
source: 'RunData.ManualChatMessage',
});
this.workflowsStore.appendChatMessage(message);
if (!response) {
this.showError(
new Error('It was not possible to start workflow!'),
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ui/src/plugins/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
"chat.window.logs": "Log (for last message)",
"chat.window.noChatNode": "No Chat Node",
"chat.window.noExecution": "Nothing got executed yet",
"chat.window.chat.placeholder": "Type in message",
"chat.window.chat.placeholder": "Type a message, or press ‘up’ arrow for previous one",
"chat.window.chat.sendButtonText": "Send",
"chat.window.chat.provideMessage": "Please provide a message",
"chat.window.chat.emptyChatMessage": "Empty chat message",
Expand Down
12 changes: 12 additions & 0 deletions packages/editor-ui/src/stores/workflows.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
executionWaitingForWebhook: false,
nodeMetadata: {},
isInDebugMode: false,
chatMessages: [],
}),
getters: {
// Workflow getters
Expand Down Expand Up @@ -277,6 +278,9 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
getTotalFinishedExecutionsCount(): number {
return this.finishedExecutionsCount;
},
getPastChatMessages(): string[] {
return Array.from(new Set(this.chatMessages));
},
},
actions: {
getPinDataSize(pinData: Record<string, string | INodeExecutionData[]> = {}): number {
Expand Down Expand Up @@ -1436,5 +1440,13 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, {
},
};
},

resetChatMessages(): void {
this.chatMessages = [];
},

appendChatMessage(message: string): void {
this.chatMessages.push(message);
},
},
});
1 change: 1 addition & 0 deletions packages/editor-ui/src/views/NodeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,7 @@ export default defineComponent({
this.instance.unbind();
this.instance.destroy();
this.uiStore.stateIsDirty = false;
this.workflowsStore.resetChatMessages();
window.removeEventListener('message', this.onPostMessageReceived);
nodeViewEventBus.off('newWorkflow', this.newWorkflow);
nodeViewEventBus.off('importWorkflowData', this.onImportWorkflowDataEvent);
Expand Down

0 comments on commit 246f8cf

Please sign in to comment.