mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-17 05:29:44 +02:00
fix(editor): Cleanup legacy button variants (#41175)
This commit is contained in:
parent
4cb7a6ee3d
commit
ba97e46afc
|
|
@ -7,11 +7,6 @@ const stubs = ['N8nSpinner', 'N8nIcon'];
|
|||
|
||||
describe('components', () => {
|
||||
describe('N8nButton', () => {
|
||||
it('maps the legacy subtle variant to brand', () => {
|
||||
const wrapper = render(N8nButton, { props: { variant: 'subtle' }, global: { stubs } });
|
||||
expect(wrapper.getByRole('button').className).toContain('brand');
|
||||
});
|
||||
|
||||
describe('rendering', () => {
|
||||
it('should render correctly with default props', () => {
|
||||
const wrapper = render(N8nButton, {
|
||||
|
|
|
|||
|
|
@ -27,14 +27,6 @@ const effectiveSize = computed(() => {
|
|||
return props.size;
|
||||
});
|
||||
|
||||
// Map legacy variant values to current ones
|
||||
const effectiveVariant = computed(() => {
|
||||
if (props.variant === 'subtle') return 'brand';
|
||||
if (props.variant === 'highlight') return 'ghost';
|
||||
if (props.variant === 'highlight-fill') return 'ghost';
|
||||
return props.variant;
|
||||
});
|
||||
|
||||
const computedIconSize = computed((): IconSize | undefined => {
|
||||
if (props.iconSize) return props.iconSize;
|
||||
if (effectiveSize.value === 'xsmall') return 'xsmall';
|
||||
|
|
@ -57,7 +49,7 @@ const classes = computed(() =>
|
|||
cn(
|
||||
'button',
|
||||
$style.button,
|
||||
$style[effectiveVariant.value],
|
||||
$style[props.variant],
|
||||
$style[effectiveSize.value],
|
||||
props.loading && $style.loading,
|
||||
props.iconOnly && $style.iconOnly,
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ onBeforeUnmount(() => {
|
|||
<span>{{ emptyText }}</span>
|
||||
<N8nButton
|
||||
v-if="isFilteredByTab"
|
||||
variant="subtle"
|
||||
variant="outline"
|
||||
size="small"
|
||||
data-test-id="command-bar-search-all"
|
||||
@mousedown.prevent
|
||||
|
|
|
|||
|
|
@ -38,12 +38,6 @@ const effectiveSize = computed(() => {
|
|||
return props.size;
|
||||
});
|
||||
|
||||
const effectiveVariant = computed(() => {
|
||||
if (props.variant === 'highlight') return 'ghost';
|
||||
if (props.variant === 'highlight-fill') return 'ghost';
|
||||
return props.variant;
|
||||
});
|
||||
|
||||
const computedIconSize = computed((): IconSize => {
|
||||
if (effectiveSize.value === 'xsmall') return 'xsmall';
|
||||
return effectiveSize.value;
|
||||
|
|
@ -53,7 +47,7 @@ const classes = computed(() =>
|
|||
cn(
|
||||
'button',
|
||||
$style.toggle,
|
||||
$style[effectiveVariant.value],
|
||||
$style[props.variant],
|
||||
$style[effectiveSize.value],
|
||||
$style.iconOnly,
|
||||
props.disabled && $style.disabled,
|
||||
|
|
|
|||
|
|
@ -6,15 +6,12 @@ import { type IconName } from '../components/N8nIcon/icons';
|
|||
const BUTTON_VARIANT = ['solid', 'brand', 'ghost', 'outline', 'destructive', 'success'] as const;
|
||||
export type ButtonVariant = (typeof BUTTON_VARIANT)[number];
|
||||
|
||||
/** @deprecated Use 'brand' for 'subtle'. Use 'ghost' for 'highlight' or 'highlight-fill'. */
|
||||
export type LegacyButtonVariant = 'highlight' | 'highlight-fill' | 'subtle';
|
||||
|
||||
const BUTTON_SIZE = ['mini', 'xmini', 'small', 'medium', 'large', 'xlarge', 'xsmall'] as const;
|
||||
export type ButtonSize = (typeof BUTTON_SIZE)[number];
|
||||
|
||||
export interface ButtonProps {
|
||||
/** Determines the visual style of the button */
|
||||
variant?: ButtonVariant | LegacyButtonVariant;
|
||||
variant?: ButtonVariant;
|
||||
/** Determines the size of the button */
|
||||
size?: ButtonSize;
|
||||
/** If passed, the button will be rendered as a link */
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ describe('AgentChatMessageList', () => {
|
|||
});
|
||||
const callout = wrapper.get('[data-testid="agent-chat-retry-error"]');
|
||||
const retry = callout.get('[data-testid="agent-chat-retry"]');
|
||||
expect(wrapper.findComponent({ name: 'N8nButton' }).props('variant')).toBe('subtle');
|
||||
expect(wrapper.findComponent({ name: 'N8nButton' }).props('variant')).toBe('outline');
|
||||
await retry.trigger('click');
|
||||
expect(wrapper.emitted('retry')).toBeUndefined();
|
||||
await wrapper.setProps({ retryDisabled: false });
|
||||
|
|
|
|||
|
|
@ -443,6 +443,28 @@ describe('AgentEvalChecksPanel', () => {
|
|||
expect(getAllByTestId(/agent-eval-check-/)).toHaveLength(4);
|
||||
});
|
||||
|
||||
it('marks the selected status filter', async () => {
|
||||
const user = userEvent.setup();
|
||||
const { getByTestId } = renderFour();
|
||||
|
||||
const all = getByTestId('agent-eval-checks-filter-all');
|
||||
const pass = getByTestId('agent-eval-checks-filter-pass');
|
||||
|
||||
expect(all).toHaveAttribute('aria-pressed', 'true');
|
||||
expect(all.className).toContain('brand');
|
||||
expect(pass).toHaveAttribute('aria-pressed', 'false');
|
||||
expect(pass.className).toContain('outline');
|
||||
expect(pass.className).not.toContain('brand');
|
||||
|
||||
await user.click(pass);
|
||||
|
||||
expect(pass).toHaveAttribute('aria-pressed', 'true');
|
||||
expect(pass.className).toContain('brand');
|
||||
expect(all).toHaveAttribute('aria-pressed', 'false');
|
||||
expect(all.className).toContain('outline');
|
||||
expect(all.className).not.toContain('brand');
|
||||
});
|
||||
|
||||
it('filters down to only passing rows', async () => {
|
||||
const user = userEvent.setup();
|
||||
const { getAllByTestId, getByTestId } = renderFour();
|
||||
|
|
@ -1447,6 +1469,7 @@ describe('AgentEvalChecksPanel', () => {
|
|||
await vi.waitFor(() =>
|
||||
expect(queryByTestId('agent-eval-checks-filter-needs-work')).not.toBeInTheDocument(),
|
||||
);
|
||||
expect(getByTestId('agent-eval-checks-filter-all')).toHaveAttribute('aria-pressed', 'true');
|
||||
expect(getAllByTestId(/agent-eval-check-/)).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ const i18n = useI18n();
|
|||
<template v-if="retryMessageId" #trailingContent>
|
||||
<N8nButton
|
||||
size="small"
|
||||
variant="subtle"
|
||||
variant="outline"
|
||||
:class="$style.retryButton"
|
||||
:disabled="retryDisabled"
|
||||
data-testid="agent-chat-retry"
|
||||
|
|
|
|||
|
|
@ -454,7 +454,8 @@ onBeforeUnmount(store.stopPollingRun);
|
|||
:key="option.key"
|
||||
type="button"
|
||||
size="small"
|
||||
:variant="statusFilter === option.key ? 'outline' : 'subtle'"
|
||||
:variant="statusFilter === option.key ? 'brand' : 'outline'"
|
||||
:aria-pressed="statusFilter === option.key"
|
||||
:data-testid="`agent-eval-checks-filter-${option.key}`"
|
||||
@click="setStatusFilter(option.key)"
|
||||
>
|
||||
|
|
@ -482,7 +483,7 @@ onBeforeUnmount(store.stopPollingRun);
|
|||
{{ i18n.baseText('agents.builder.agentEvals.suggestion.applyAll') }}
|
||||
</N8nButton>
|
||||
<N8nButton
|
||||
variant="subtle"
|
||||
variant="outline"
|
||||
size="small"
|
||||
:disabled="disabled || rerunning"
|
||||
:loading="rerunning || inFlight"
|
||||
|
|
@ -553,7 +554,7 @@ onBeforeUnmount(store.stopPollingRun);
|
|||
</N8nButton>
|
||||
|
||||
<div v-if="hasMore" :class="$style.loadMore">
|
||||
<N8nButton variant="subtle" size="small" :loading="review.loadingMore" @click="onLoadMore">
|
||||
<N8nButton variant="outline" size="small" :loading="review.loadingMore" @click="onLoadMore">
|
||||
{{ i18n.baseText('agents.builder.agentEvals.review.loadMore') }}
|
||||
</N8nButton>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ watch(
|
|||
<!-- Only the rule is editable; a case with no criteria column can still be deleted. -->
|
||||
<N8nButton
|
||||
v-if="whatToCheck"
|
||||
variant="subtle"
|
||||
variant="outline"
|
||||
size="small"
|
||||
icon-only
|
||||
:disabled="disabled || runningCheck"
|
||||
|
|
@ -292,7 +292,7 @@ watch(
|
|||
</template>
|
||||
</N8nButton>
|
||||
<N8nButton
|
||||
variant="subtle"
|
||||
variant="outline"
|
||||
size="small"
|
||||
icon-only
|
||||
:disabled="disabled"
|
||||
|
|
@ -330,7 +330,7 @@ watch(
|
|||
{{ i18n.baseText('generic.save') }}
|
||||
</N8nButton>
|
||||
<N8nButton
|
||||
variant="subtle"
|
||||
variant="outline"
|
||||
size="small"
|
||||
:data-test-id="testId && `${testId}-rule-cancel`"
|
||||
@click="onCancelEditWhatToCheck"
|
||||
|
|
@ -421,7 +421,7 @@ watch(
|
|||
<div :class="$style.correctionActions">
|
||||
<N8nButton
|
||||
size="small"
|
||||
variant="subtle"
|
||||
variant="outline"
|
||||
:disabled="disabled"
|
||||
:loading="runningCheck"
|
||||
:data-test-id="testId && `${testId}-run-check`"
|
||||
|
|
|
|||
|
|
@ -218,6 +218,23 @@ describe('TrialBanner', () => {
|
|||
expect(button?.getAttribute('style')).toBeNull();
|
||||
});
|
||||
|
||||
it('should map the subtle variant to outline without legacy style overrides', () => {
|
||||
cloudPlanStore.state.data = {
|
||||
bannerConfig: {
|
||||
cta: {
|
||||
text: 'Upgrade',
|
||||
style: 'success',
|
||||
variant: 'subtle',
|
||||
},
|
||||
},
|
||||
} as never;
|
||||
|
||||
const { container } = renderComponent();
|
||||
const button = container.querySelector('button');
|
||||
expect(button?.className).toContain('outline');
|
||||
expect(button?.getAttribute('style')).toBeNull();
|
||||
});
|
||||
|
||||
it('should apply legacy style overrides when backend sends style without variant', () => {
|
||||
cloudPlanStore.state.data = {
|
||||
bannerConfig: {
|
||||
|
|
|
|||
|
|
@ -106,14 +106,18 @@ const shouldHideTrialBanner = computed(
|
|||
// Banner config from backend
|
||||
const bannerTimeLeft = computed(() => cloudPlanStore.bannerTimeLeft);
|
||||
const showExecutions = computed(() => cloudPlanStore.showExecutions);
|
||||
const bannerCta = computed(() => ({
|
||||
text: cloudPlanStore.bannerCta.text,
|
||||
icon: cloudPlanStore.bannerCta.icon as IconName | undefined,
|
||||
size: cloudPlanStore.bannerCta.size as 'small' | 'medium',
|
||||
style: cloudPlanStore.bannerCta.style,
|
||||
variant: cloudPlanStore.bannerCta.variant as ButtonVariant | undefined,
|
||||
href: cloudPlanStore.bannerCta.href,
|
||||
}));
|
||||
const bannerCta = computed(() => {
|
||||
const variant = cloudPlanStore.bannerCta.variant;
|
||||
return {
|
||||
text: cloudPlanStore.bannerCta.text,
|
||||
icon: cloudPlanStore.bannerCta.icon as IconName | undefined,
|
||||
size: cloudPlanStore.bannerCta.size as 'small' | 'medium',
|
||||
style: cloudPlanStore.bannerCta.style,
|
||||
// BannerConfig.cta.variant still lists the old button value 'subtle'.
|
||||
variant: variant === 'subtle' ? 'outline' : variant,
|
||||
href: cloudPlanStore.bannerCta.href,
|
||||
};
|
||||
});
|
||||
const bannerIcon = computed(() => cloudPlanStore.bannerIcon as IconName | undefined);
|
||||
|
||||
// If backend sends variant, use it directly. Otherwise, map legacy style to variant.
|
||||
|
|
|
|||
|
|
@ -375,7 +375,7 @@ onBeforeUnmount(() => {
|
|||
<N8nLoading v-if="isLoadingMore" :rows="1" />
|
||||
<N8nButton
|
||||
v-if="hasLoadError"
|
||||
variant="subtle"
|
||||
variant="outline"
|
||||
size="small"
|
||||
:disabled="isLoading || isLoadingMore"
|
||||
@click="retry"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user