fix: Align From AI button with parameter inputs (#40152)

Co-authored-by: n8n-cat-bot[bot] <n8n-cat-bot[bot]@users.noreply.github.com>
This commit is contained in:
n8n-cat-bot[bot] 2026-10-02 12:50:51 +00:00 committed by GitHub
parent 1adc57b97b
commit 9675fc97fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 92 additions and 6 deletions

View File

@ -522,7 +522,14 @@ function removeOverride(clearField = false) {
@drop="onDrop"
>
<template v-if="showOverrideButton && isSingleLineInput" #overrideButton>
<FromAiOverrideButton @click="applyOverride" />
<FromAiOverrideButton
:size="
!isExpression && ['number', 'multiOptions'].includes(parameter.type)
? 'small'
: 'medium'
"
@click="applyOverride"
/>
</template>
</ParameterInputWrapper>
</div>

View File

@ -8,8 +8,9 @@ const i18n = useI18n();
withDefaults(
defineProps<{
position?: 'inline' | 'standalone';
size?: 'small' | 'medium';
}>(),
{ position: 'inline' },
{ position: 'inline', size: 'medium' },
);
const emit = defineEmits<{
@ -24,7 +25,7 @@ const emit = defineEmits<{
</template>
<div
:class="[$style.overrideButton, $style[position]]"
:class="[$style.overrideButton, $style[position], $style[size]]"
data-test-id="from-ai-override-button"
@click="emit('click')"
>
@ -38,8 +39,8 @@ const emit = defineEmits<{
display: flex;
align-items: center;
justify-content: center;
height: 30px;
width: 30px;
height: var(--from-ai-button-size);
width: var(--from-ai-button-size);
background-color: var(--color--foreground);
color: var(--color--foreground--shade-2);
cursor: pointer;
@ -55,6 +56,14 @@ const emit = defineEmits<{
}
}
.small {
--from-ai-button-size: var(--height--sm);
}
.medium {
--from-ai-button-size: var(--height--md);
}
.inline {
border-left: 0;
border-top-right-radius: var(--radius);

View File

@ -1278,7 +1278,10 @@ function removeOverride() {
</template>
</N8nInput>
<div v-if="showOverrideButton" :class="$style.overrideButtonInline">
<FromAiOverrideButton @click="applyOverride" />
<FromAiOverrideButton
:size="isValueExpression || forceShowExpression ? 'medium' : 'small'"
@click="applyOverride"
/>
</div>
</div>
</template>

View File

@ -244,6 +244,22 @@ export class NodeDetailsViewPage extends BasePage {
return locatorByIndex(this.container.getByTestId(`parameter-input-${parameterName}`), index);
}
getParameterInputBorder(parameterName: string) {
return this.getParameterInput(parameterName).locator('.n8n-input__wrapper');
}
getParameterNumberBorder(parameterName: string) {
return this.getParameterInput(parameterName).getByTestId('input-number');
}
getParameterExpressionBorder(parameterName: string) {
return this.getParameterInput(parameterName).locator('.el-input-group__prepend').locator('..');
}
getFromAiOverrideButton(parameterName: string) {
return this.getParameterInput(parameterName).getByTestId('from-ai-override-button');
}
getParameterInputTextbox(parameterName: string, index?: number) {
return this.getParameterInput(parameterName, index).getByRole('textbox');
}

View File

@ -0,0 +1,51 @@
import { test, expect } from '../../../fixtures/base';
import type { Locator } from '@playwright/test';
async function expectButtonAligned(inputBorder: Locator, fromAiButton: Locator) {
await expect(inputBorder).toBeVisible();
await expect(fromAiButton).toBeVisible();
const inputBounds = await inputBorder.boundingBox();
const buttonBounds = await fromAiButton.boundingBox();
expect(inputBounds).not.toBeNull();
expect(buttonBounds).not.toBeNull();
expect(buttonBounds).toMatchObject({
y: inputBounds!.y,
height: inputBounds!.height,
});
}
test.describe(
'ADO-5599: From AI button alignment',
{ annotation: [{ type: 'owner', description: 'Adore' }] },
() => {
test('aligns the From AI button outline with the tool parameter input border', async ({
n8n,
}) => {
await n8n.start.fromBlankCanvas();
await n8n.canvas.addNode('AI Agent', { closeNDV: true });
await n8n.canvas.getInputPlusEndpointByType('AI Agent', 'ai_tool').click();
await n8n.canvas.nodeCreator.searchFor('SearXNG');
await n8n.canvas.nodeCreator.selectItem('SearXNG');
await n8n.ndv.addParameterOptionByName('Language');
await expectButtonAligned(
n8n.ndv.getParameterInputBorder('language'),
n8n.ndv.getFromAiOverrideButton('language'),
);
await n8n.ndv.addParameterOptionByName('Number of Results');
await expectButtonAligned(
n8n.ndv.getParameterNumberBorder('numResults'),
n8n.ndv.getFromAiOverrideButton('numResults'),
);
await n8n.ndv.setParameterInput('language', '={{ $json.language }}');
await expectButtonAligned(
n8n.ndv.getParameterExpressionBorder('language'),
n8n.ndv.getFromAiOverrideButton('language'),
);
});
},
);