fix(editor): Align parameter input sizes (backport to release-candidate/2.28.x) (#33448)

Co-authored-by: Rob Hough <robhough180@gmail.com>
This commit is contained in:
n8n-assistant[bot] 2026-07-02 11:40:00 +00:00 committed by GitHub
parent 0a45419fc5
commit 2d0da0bb2a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 53 additions and 13 deletions

View File

@ -285,6 +285,8 @@ watch(internalOpen, (isOpen, _oldValue, onCleanup) => {
defineExpose({ open, close });
</script>
<!-- TODO DS-580: Let consumers bind trigger props/listeners directly in the slot so their
element can be the actual trigger. For now this wrapper owns hover events and test ids. -->
<template>
<DropdownMenuRoot :modal="modal" :open="internalOpen" @update:open="handleOpenChange">
<DropdownMenuTrigger as-child :disabled="disabled">

View File

@ -104,6 +104,11 @@ const onSelect = (operatorId: string): void => {
.wrapper {
width: 100%;
height: 100%;
/* TODO DS-580: Remove when child consumers of DropdownMenu trigger aren't wrapped in containing span */
> [aria-haspopup='menu'] {
width: 100%;
}
}
.trigger {
@ -112,7 +117,7 @@ const onSelect = (operatorId: string): void => {
gap: var(--spacing--3xs);
width: 100%;
height: 100%;
min-height: 30px;
min-height: var(--height--md);
padding: 0 var(--spacing--2xs);
border: var(--border-width) var(--border-style) var(--input--border-color, var(--border-color));
border-top-left-radius: var(--input--radius--top-left, var(--input--radius, 0));

View File

@ -166,7 +166,7 @@ const valueChanged = (parameterData: IUpdateInformation) => {
:display-options="true"
:hide-label="true"
:path="getPath(index)"
input-size="medium"
input-size="small"
:is-read-only="isReadOnly"
@update="valueChanged"
/>

View File

@ -277,6 +277,13 @@ describe('ParameterInput.vue', () => {
);
});
/**
* TODO DS-579:
* N8nInput and N8nSelect don't have aligned size tokens.
* What is 'medium' for one isn't the same the other.
* This has caused a few bugs where coding models have mixed the sizes up and they've slipped through the review.
* For now, we'll use these tests to prevent further regression mixing the two up.
*/
test('uses medium input size by default', () => {
const { getByTestId } = renderComponent({
props: {
@ -301,6 +308,23 @@ describe('ParameterInput.vue', () => {
expect(getByTestId('parameter-input-field')).toHaveAttribute('data-size', 'medium');
});
test('uses small select size by default', () => {
const { container } = renderComponent({
props: {
path: 'operation',
parameter: createTestNodeProperties({
displayName: 'Operation',
name: 'operation',
type: 'options',
options: [{ name: 'Append Row', value: 'append' }],
}),
modelValue: 'append',
},
});
expect(container.querySelector('.el-select')).toHaveClass('el-select--small');
});
test('should render a string parameter', async () => {
const { container, emitted } = renderComponent({
props: {

View File

@ -146,7 +146,7 @@ type Props = {
const props = withDefaults(defineProps<Props>(), {
rows: 5,
hint: undefined,
inputSize: 'medium',
inputSize: 'small',
eventSource: undefined,
documentationUrl: undefined,
isReadOnly: false,
@ -376,6 +376,14 @@ const editorIsReadOnly = computed<boolean>(() => {
return getTypeOption('editorIsReadOnly') ?? false;
});
/**
* Custom mapping needed until DS-579 is complete.
* This aligns the height sizes of N8nInput with those of N8nSelect.
*/
const parameterInputSize = computed<InputSize>(() => {
return props.inputSize === 'small' ? 'medium' : props.inputSize;
});
const editorLanguage = computed<CodeNodeLanguageOption>(() => {
if (editorType.value === 'json' || props.parameter.type === 'json') return 'json';
@ -1774,7 +1782,7 @@ onUpdated(async () => {
ref="inputField"
v-model="tempValue"
:class="{ 'input-with-opener': true, 'ph-no-capture': shouldRedactValue }"
:size="inputSize"
:size="parameterInputSize"
:type="getStringInputType"
:rows="editorRows"
:disabled="
@ -1831,7 +1839,7 @@ onUpdated(async () => {
/>
<N8nInput
v-model="tempValue"
:size="inputSize"
:size="parameterInputSize"
type="text"
:disabled="isReadOnly"
:title="displayTitle"
@ -1986,7 +1994,7 @@ onUpdated(async () => {
<N8nInput
v-else-if="parameter.type === 'boolean' && isCollectionOverhaulEnabled && droppable"
:size="inputSize"
:size="parameterInputSize"
:disabled="isReadOnly"
:title="displayTitle"
class="switch-droppable-input"
@ -2003,7 +2011,7 @@ onUpdated(async () => {
<N8nInput
v-else-if="parameter.type === 'boolean' && droppable"
:size="inputSize"
:size="parameterInputSize"
:model-value="JSON.stringify(displayValue)"
:disabled="isReadOnly"
:title="displayTitle"

View File

@ -380,7 +380,7 @@ function removeOverride(clearField = false) {
:hide-issues="hideIssues"
:label="label"
:event-bus="eventBus"
input-size="medium"
input-size="small"
@update="valueChanged"
@text-input="onTextInput"
@focus="onFocus"
@ -496,7 +496,7 @@ function removeOverride(clearField = false) {
:event-bus="eventBus"
:can-be-overridden="canCreateContentOverride"
:hide-label="hideLabel"
input-size="medium"
input-size="small"
@update="valueChanged"
@text-input="onTextInput"
@focus="onFocus"

View File

@ -898,7 +898,7 @@ watch(
:dependent-parameters-values="item.dependentParametersValues"
:is-read-only="isReadOnly"
:allow-empty-strings="item.parameter.typeOptions?.resourceMapper?.allowEmptyValues"
input-size="medium"
input-size="small"
label-size="small"
@value-changed="valueChanged"
/>

View File

@ -69,7 +69,7 @@ function onExtraPropValueRemove(name: string) {
:is-read-only="isReadOnly"
:value="parameterOverride?.extraPropValues[name]"
:path="`${path}.${name}`"
input-size="medium"
input-size="small"
@update="
(x: IUpdateInformation) => {
parameterOverride.extraPropValues[name] = x.value;

View File

@ -119,7 +119,7 @@ type Props = {
const props = withDefaults(defineProps<Props>(), {
node: undefined,
loadOptionsMethod: undefined,
inputSize: 'medium',
inputSize: 'small',
parameterIssues: () => [],
dependentParametersValues: null,
displayTitle: '',

View File

@ -112,6 +112,7 @@ $--mode-selector-width: 92px;
.selectInput input {
overflow: hidden;
text-overflow: ellipsis;
min-height: 30px;
}
.selectIcon {

View File

@ -58,7 +58,7 @@ export interface Props {
const props = withDefaults(defineProps<Props>(), {
eventBus: () => createEventBus(),
inputSize: 'medium',
inputSize: 'small',
isValueExpression: false,
isReadOnly: false,
forceShowExpression: false,