fix(editor): Replace wrong button variant in AIWB mode selector (no-changelog) (#26670)

Co-authored-by: Claude Haiku 4.5 <[email protected]>
This commit is contained in:
Tuukka Kantola
2026-03-06 15:26:24 +00:00
committed by GitHub
co-authored by Claude Haiku 4.5
parent ec0cf13141
commit 136a678b1f
2 changed files with 56 additions and 44 deletions
@@ -17,19 +17,19 @@ describe('PlanModeSelector', () => {
it('shows "Build" label when modelValue is build', () => {
const { getByTestId } = render('build');
const button = getByTestId('plan-mode-selector').querySelector('button');
expect(button?.textContent).toContain('Build');
const trigger = getByTestId('plan-mode-selector').querySelector('[role="combobox"]');
expect(trigger?.textContent).toContain('Build');
});
it('shows "Plan" label when modelValue is plan', () => {
const { getByTestId } = render('plan');
const button = getByTestId('plan-mode-selector').querySelector('button');
expect(button?.textContent).toContain('Plan');
const trigger = getByTestId('plan-mode-selector').querySelector('[role="combobox"]');
expect(trigger?.textContent).toContain('Plan');
});
it('button is never disabled', () => {
it('trigger is never disabled', () => {
const { getByTestId } = render('build');
const button = getByTestId('plan-mode-selector').querySelector('button');
expect(button?.hasAttribute('disabled')).toBe(false);
const trigger = getByTestId('plan-mode-selector').querySelector('[role="combobox"]');
expect(trigger?.hasAttribute('data-disabled')).toBe(false);
});
});
@@ -1,12 +1,19 @@
<script setup lang="ts">
import { computed } from 'vue';
import { N8nActionDropdown, N8nButton, N8nIcon } from '@n8n/design-system';
import type { ActionDropdownItem } from '@n8n/design-system/types';
import { N8nSelect2 } from '@n8n/design-system';
import type {
SelectItemProps,
SelectValue,
} from '@n8n/design-system/v2/components/Select/Select.types';
import { useI18n, type BaseTextKey } from '@n8n/i18n';
type BuilderMode = 'build' | 'plan';
interface ModeSelectItem extends SelectItemProps {
description: string;
}
const props = defineProps<{
modelValue: BuilderMode;
}>();
@@ -17,53 +24,62 @@ const emit = defineEmits<{
const i18n = useI18n();
const modeOptions = computed<Array<ActionDropdownItem<BuilderMode>>>(() => [
const modeOptions = computed<ModeSelectItem[]>(() => [
{
id: 'build',
value: 'build',
label: i18n.baseText('aiAssistant.builder.planMode.selector.build'),
description: i18n.baseText(
'aiAssistant.builder.planMode.selector.build.description' as BaseTextKey,
),
icon: 'box',
checked: props.modelValue === 'build',
},
{
id: 'plan',
value: 'plan',
label: i18n.baseText('aiAssistant.builder.planMode.selector.plan'),
description: i18n.baseText(
'aiAssistant.builder.planMode.selector.plan.description' as BaseTextKey,
),
icon: 'scroll-text',
checked: props.modelValue === 'plan',
},
]);
const currentMode = computed(() => {
return modeOptions.value.find((opt) => opt.id === props.modelValue) ?? modeOptions.value[0];
return modeOptions.value.find((opt) => opt.value === props.modelValue) ?? modeOptions.value[0];
});
function onSelect(value: BuilderMode) {
emit('update:modelValue', value);
function onSelect(value: SelectValue | undefined) {
if (value) {
emit('update:modelValue', value as BuilderMode);
}
}
</script>
<template>
<div :class="$style.container" data-test-id="plan-mode-selector">
<N8nActionDropdown :items="modeOptions" placement="bottom-end" hide-arrow @select="onSelect">
<template #activator>
<N8nButton type="secondary" size="small" :class="$style.trigger">
<N8nIcon v-if="currentMode.icon" :icon="currentMode.icon" size="small" />
<span :class="$style.triggerLabel">{{ currentMode.label }}</span>
<N8nIcon icon="chevron-down" size="xsmall" />
</N8nButton>
<N8nSelect2
:class="$style.select"
:items="modeOptions"
:model-value="props.modelValue"
:icon="currentMode.icon"
variant="ghost"
size="small"
position="popper"
side="top"
@update:model-value="onSelect"
:content-class="$style.content"
>
<template #default>
{{ currentMode.label }}
</template>
<template #menuItem="item">
<div :class="$style.menuItem">
<span :class="$style.label">{{ item.label }}</span>
<span :class="$style.description">{{ item.description }}</span>
<template #item-label="{ item }">
<div :class="$style.itemContent">
<span>{{ item.label }}</span>
<span :class="$style.description">
{{ (item as ModeSelectItem).description }}
</span>
</div>
</template>
</N8nActionDropdown>
</N8nSelect2>
</div>
</template>
@@ -73,29 +89,25 @@ function onSelect(value: BuilderMode) {
align-items: center;
}
.trigger {
display: flex;
align-items: center;
gap: var(--spacing--4xs);
.select {
background-color: transparent;
&:not([data-disabled]):hover {
background-color: transparent;
}
}
.content [role='option'] {
height: auto;
padding: var(--spacing--3xs) var(--spacing--2xs);
}
.triggerLabel {
font-size: var(--font-size--2xs);
}
.menuItem {
.itemContent {
display: flex;
flex-direction: column;
gap: var(--spacing--5xs);
}
.label {
font-weight: var(--font-weight--bold);
font-size: var(--font-size--2xs);
line-height: var(--line-height--sm);
}
.description {
font-size: var(--font-size--3xs);
color: var(--color--text--tint-1);