feat(editor): Improve feedback buttons behavior (#18247)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Mutasem Aldmour
2025-08-14 10:05:36 +02:00
committed by GitHub
parent 59a08eed72
commit 83c3a98cf4
8 changed files with 925 additions and 75 deletions

View File

@@ -17,6 +17,13 @@ import type { Telemetry } from '@/plugins/telemetry';
import type { ChatUI } from '@n8n/design-system/types/assistant';
import { DEFAULT_CHAT_WIDTH, MAX_CHAT_WIDTH, MIN_CHAT_WIDTH } from './assistant.store';
// Mock useI18n to return the keys instead of translations
vi.mock('@n8n/i18n', () => ({
useI18n: () => ({
baseText: (key: string) => key,
}),
}));
let settingsStore: ReturnType<typeof useSettingsStore>;
let posthogStore: ReturnType<typeof usePostHog>;
@@ -195,8 +202,8 @@ describe('AI Builder store', () => {
builderStore.sendChatMessage({ text: 'Add nodes and connect them' });
// Initially shows "Thinking..." from prepareForStreaming
expect(builderStore.assistantThinkingMessage).toBe('Thinking...');
// Initially shows "aiAssistant.thinkingSteps.thinking" from prepareForStreaming
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.thinking');
// First tool starts
onMessageCallback({
@@ -212,8 +219,8 @@ describe('AI Builder store', () => {
],
});
// Should show "Running tools..."
expect(builderStore.assistantThinkingMessage).toBe('Running tools...');
// Should show "aiAssistant.thinkingSteps.runningTools"
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.runningTools');
// Second tool starts (different toolCallId)
onMessageCallback({
@@ -229,8 +236,8 @@ describe('AI Builder store', () => {
],
});
// Still showing "Running tools..." with multiple tools
expect(builderStore.assistantThinkingMessage).toBe('Running tools...');
// Still showing "aiAssistant.thinkingSteps.runningTools" with multiple tools
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.runningTools');
// First tool completes
onMessageCallback({
@@ -246,8 +253,8 @@ describe('AI Builder store', () => {
],
});
// Still "Running tools..." because second tool is still running
expect(builderStore.assistantThinkingMessage).toBe('Running tools...');
// Still "aiAssistant.thinkingSteps.runningTools" because second tool is still running
expect(builderStore.assistantThinkingMessage).toBe('aiAssistant.thinkingSteps.runningTools');
// Second tool completes
onMessageCallback({
@@ -263,15 +270,19 @@ describe('AI Builder store', () => {
],
});
// Now should show "Processing results..." because all tools completed
expect(builderStore.assistantThinkingMessage).toBe('Processing results...');
// Now should show "aiAssistant.thinkingSteps.processingResults" because all tools completed
expect(builderStore.assistantThinkingMessage).toBe(
'aiAssistant.thinkingSteps.processingResults',
);
// Call onDone to stop streaming
onDoneCallback();
// Message should persist after streaming ends
expect(builderStore.streaming).toBe(false);
expect(builderStore.assistantThinkingMessage).toBe('Processing results...');
expect(builderStore.assistantThinkingMessage).toBe(
'aiAssistant.thinkingSteps.processingResults',
);
vi.useRealTimers();
});
@@ -311,14 +322,18 @@ describe('AI Builder store', () => {
builderStore.sendChatMessage({ text: 'Add a node' });
// Should show "Processing results..." when tool completes
// Should show "aiAssistant.thinkingSteps.processingResults" when tool completes
await vi.waitFor(() =>
expect(builderStore.assistantThinkingMessage).toBe('Processing results...'),
expect(builderStore.assistantThinkingMessage).toBe(
'aiAssistant.thinkingSteps.processingResults',
),
);
// Should still show "Processing results..." after workflow-updated
// Should still show "aiAssistant.thinkingSteps.processingResults" after workflow-updated
await vi.waitFor(() => expect(builderStore.chatMessages).toHaveLength(3)); // user + tool + workflow
expect(builderStore.assistantThinkingMessage).toBe('Processing results...');
expect(builderStore.assistantThinkingMessage).toBe(
'aiAssistant.thinkingSteps.processingResults',
);
// Verify streaming has ended
expect(builderStore.streaming).toBe(false);
@@ -709,4 +724,58 @@ describe('AI Builder store', () => {
expect((assistantMessages[0] as ChatUI.TextMessage).content).toBe('[Task aborted]');
});
});
describe('Rating logic integration', () => {
it('should clear ratings from existing messages when preparing for streaming', () => {
const builderStore = useBuilderStore();
// Setup initial messages with ratings
builderStore.chatMessages = [
{
id: 'msg-1',
role: 'assistant',
type: 'text',
content: 'Previous message',
showRating: true,
ratingStyle: 'regular',
read: false,
} satisfies ChatUI.AssistantMessage,
{
id: 'msg-2',
role: 'assistant',
type: 'text',
content: 'Another message',
showRating: true,
ratingStyle: 'minimal',
read: false,
} satisfies ChatUI.AssistantMessage,
];
// Mock API to prevent actual network calls
apiSpy.mockImplementationOnce(() => {});
// Send new message which calls prepareForStreaming
builderStore.sendChatMessage({ text: 'New message' });
// Verify that existing messages no longer have rating properties
expect(builderStore.chatMessages).toHaveLength(3); // 2 existing + 1 new user message
const firstMessage = builderStore.chatMessages[0] as ChatUI.TextMessage;
expect(firstMessage).not.toHaveProperty('showRating');
expect(firstMessage).not.toHaveProperty('ratingStyle');
expect(firstMessage.content).toBe('Previous message');
const secondMessage = builderStore.chatMessages[1] as ChatUI.TextMessage;
expect(secondMessage).not.toHaveProperty('showRating');
expect(secondMessage).not.toHaveProperty('ratingStyle');
expect(secondMessage.content).toBe('Another message');
// New user message should not have rating properties
const userMessage = builderStore.chatMessages[2] as ChatUI.TextMessage;
expect(userMessage.role).toBe('user');
expect(userMessage.content).toBe('New message');
expect(userMessage).not.toHaveProperty('showRating');
expect(userMessage).not.toHaveProperty('ratingStyle');
});
});
});