diff --git a/packages/frontend/@n8n/design-system/src/components/CanvasThinkingPill/CanvasThinkingPill.test.ts b/packages/frontend/@n8n/design-system/src/components/CanvasThinkingPill/CanvasThinkingPill.test.ts
new file mode 100644
index 0000000000..130dc4eef6
--- /dev/null
+++ b/packages/frontend/@n8n/design-system/src/components/CanvasThinkingPill/CanvasThinkingPill.test.ts
@@ -0,0 +1,10 @@
+import { render } from '@testing-library/vue';
+
+import CanvasThinkingPill from './CanvasThinkingPill.vue';
+
+describe('CanvasThinkingPill', () => {
+ it('renders canvas thinking pill correctly', () => {
+ const { container } = render(CanvasThinkingPill, {});
+ expect(container).toMatchSnapshot();
+ });
+});
diff --git a/packages/frontend/@n8n/design-system/src/components/CanvasThinkingPill/CanvasThinkingPill.vue b/packages/frontend/@n8n/design-system/src/components/CanvasThinkingPill/CanvasThinkingPill.vue
new file mode 100644
index 0000000000..2ca854014f
--- /dev/null
+++ b/packages/frontend/@n8n/design-system/src/components/CanvasThinkingPill/CanvasThinkingPill.vue
@@ -0,0 +1,60 @@
+
+
+
+
+
+
{{ t('aiAssistant.builder.canvas.thinking') }}
+
+
+
+
diff --git a/packages/frontend/@n8n/design-system/src/components/CanvasThinkingPill/__snapshots__/CanvasThinkingPill.test.ts.snap b/packages/frontend/@n8n/design-system/src/components/CanvasThinkingPill/__snapshots__/CanvasThinkingPill.test.ts.snap
new file mode 100644
index 0000000000..b7b3bae710
--- /dev/null
+++ b/packages/frontend/@n8n/design-system/src/components/CanvasThinkingPill/__snapshots__/CanvasThinkingPill.test.ts.snap
@@ -0,0 +1,53 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`CanvasThinkingPill > renders canvas thinking pill correctly 1`] = `
+
+`;
diff --git a/packages/frontend/@n8n/design-system/src/locale/lang/en.ts b/packages/frontend/@n8n/design-system/src/locale/lang/en.ts
index 571bcc0c2c..8c999be0ee 100644
--- a/packages/frontend/@n8n/design-system/src/locale/lang/en.ts
+++ b/packages/frontend/@n8n/design-system/src/locale/lang/en.ts
@@ -65,6 +65,7 @@ export default {
'assistantChat.inputPlaceholder': 'Enter your response...',
'assistantChat.copy': 'Copy',
'assistantChat.copied': 'Copied',
+ 'aiAssistant.builder.canvas.thinking': 'Working...',
'inlineAskAssistantButton.asked': 'Asked',
'iconPicker.button.defaultToolTip': 'Choose icon',
'iconPicker.tabs.icons': 'Icons',
diff --git a/packages/frontend/editor-ui/src/components/canvas/elements/nodes/render-types/CanvasNodeAIPrompt.test.ts b/packages/frontend/editor-ui/src/components/canvas/elements/nodes/render-types/CanvasNodeAIPrompt.test.ts
index 7b5fd1f1e5..88198a343f 100644
--- a/packages/frontend/editor-ui/src/components/canvas/elements/nodes/render-types/CanvasNodeAIPrompt.test.ts
+++ b/packages/frontend/editor-ui/src/components/canvas/elements/nodes/render-types/CanvasNodeAIPrompt.test.ts
@@ -214,6 +214,16 @@ describe('CanvasNodeAIPrompt', () => {
});
});
+ it('should disable suggestion pills when builder is streaming', () => {
+ streaming.value = true;
+ const { container } = renderComponent();
+ const pills = container.querySelectorAll('[role="group"] button');
+
+ pills.forEach((pill) => {
+ expect(pill).toHaveAttribute('disabled');
+ });
+ });
+
it('should replace prompt when suggestion is clicked', async () => {
const { container } = renderComponent();
const firstPill = container.querySelector('[role="group"] button');
@@ -311,6 +321,26 @@ describe('CanvasNodeAIPrompt', () => {
NODE_CREATOR_OPEN_SOURCES.TRIGGER_PLACEHOLDER_BUTTON,
);
});
+
+ it('should disable "Add node manually" button when builder is streaming', () => {
+ streaming.value = true;
+ const { container } = renderComponent();
+ const addButton = container.querySelector('[aria-label="Add node manually"]');
+
+ expect(addButton).toHaveAttribute('disabled');
+ });
+
+ it('should not open node creator when streaming', async () => {
+ streaming.value = true;
+ const { container } = renderComponent();
+ const addButton = container.querySelector('[aria-label="Add node manually"]');
+
+ if (!addButton) throw new Error('Add button not found');
+
+ await fireEvent.click(addButton);
+
+ expect(openNodeCreatorForTriggerNodes).not.toHaveBeenCalled();
+ });
});
describe('event propagation', () => {
diff --git a/packages/frontend/editor-ui/src/components/canvas/elements/nodes/render-types/CanvasNodeAIPrompt.vue b/packages/frontend/editor-ui/src/components/canvas/elements/nodes/render-types/CanvasNodeAIPrompt.vue
index 6014ec3d87..424eaff1d5 100644
--- a/packages/frontend/editor-ui/src/components/canvas/elements/nodes/render-types/CanvasNodeAIPrompt.vue
+++ b/packages/frontend/editor-ui/src/components/canvas/elements/nodes/render-types/CanvasNodeAIPrompt.vue
@@ -91,6 +91,8 @@ async function onSuggestionClick(suggestion: WorkflowSuggestion) {
* Opens the node creator for adding trigger nodes manually
*/
function onAddNodeClick() {
+ if (builderStore.streaming) return;
+
nodeCreatorStore.openNodeCreatorForTriggerNodes(
NODE_CREATOR_OPEN_SOURCES.TRIGGER_PLACEHOLDER_BUTTON,
);
@@ -145,6 +147,7 @@ function onAddNodeClick() {
v-for="suggestion in suggestions"
:key="suggestion.id"
:class="$style.suggestionPill"
+ :disabled="builderStore.streaming"
type="button"
@click="onSuggestionClick(suggestion)"
>
@@ -159,7 +162,12 @@ function onAddNodeClick() {
-