feat(editor): Update ActionBox component (no-changelog) (#22606)

This commit is contained in:
Milorad FIlipović
2025-12-03 13:41:39 +01:00
committed by GitHub
parent bda75d49ce
commit f1439c0b9b
6 changed files with 107 additions and 13 deletions
@@ -2,6 +2,8 @@ import type { StoryFn } from '@storybook/vue3-vite';
import { action } from 'storybook/actions';
import N8nActionBox from './ActionBox.vue';
import N8nLink from '../N8nLink';
import N8nText from '../N8nText';
export default {
title: 'Atoms/ActionBox',
@@ -23,7 +25,7 @@ const methods = {
onClick: action('click'),
};
const Template: StoryFn = (args, { argTypes }) => ({
const DefaultTemplate: StoryFn = (args, { argTypes }) => ({
setup: () => ({ args }),
props: Object.keys(argTypes),
components: {
@@ -33,11 +35,49 @@ const Template: StoryFn = (args, { argTypes }) => ({
methods,
});
export const ActionBox = Template.bind({});
export const ActionBox = DefaultTemplate.bind({});
ActionBox.args = {
emoji: '😿',
icon: { type: 'emoji', value: '😿' },
heading: 'Headline you need to know',
description:
'Long description that you should know something is the way it is because of how it is. ',
buttonText: 'Do something',
};
export const ActionBoxWithIcon = DefaultTemplate.bind({});
ActionBoxWithIcon.args = {
icon: { type: 'icon', value: 'tree-pine' },
heading: 'Create your first workflow',
description: 'Get started by creating a new workflow to automate your tasks.',
buttonText: 'Create Workflow',
};
const WithAdditionalContentTemplate: StoryFn = (args, { argTypes }) => ({
setup: () => ({ args }),
props: Object.keys(argTypes),
components: {
N8nActionBox,
N8nText,
N8nLink,
},
template: `
<n8n-action-box v-bind="args" @click="onClick">
<template #additionalContent>
<N8nText color="text-base">
Read more on
</N8nText>
<N8nLink class="ml-4xs" href="https://n8n.io" target="_blank">our docs</N8nLink>
</template>
</n8n-action-box>
`,
methods,
});
export const ActionBoxWithAdditionalContent = WithAdditionalContentTemplate.bind({});
ActionBoxWithAdditionalContent.args = {
icon: { type: 'emoji', value: '🚀' },
heading: 'Launch your project',
description:
'Get started with your project by clicking the button below. Additional content is included.',
buttonText: 'Get Started',
};
@@ -3,10 +3,10 @@ import { render } from '@testing-library/vue';
import N8NActionBox from './ActionBox.vue';
describe('N8NActionBox', () => {
it('should render correctly', () => {
it('should render correctly with emoji', () => {
const wrapper = render(N8NActionBox, {
props: {
emoji: '😿',
icon: { type: 'emoji', value: '😿' },
heading: 'Headline you need to know',
description:
'Long description that you should know something is the way it is because of how it is. ',
@@ -19,4 +19,20 @@ describe('N8NActionBox', () => {
});
expect(wrapper.html()).toMatchSnapshot();
});
it('should render correctly with icon', () => {
const wrapper = render(N8NActionBox, {
props: {
icon: { type: 'icon', value: 'plus' },
heading: 'Add something new',
description: 'Click the button to add a new item.',
buttonText: 'Add Item',
buttonType: 'primary',
},
global: {
stubs: ['N8nHeading', 'N8nText', 'N8nButton', 'N8nCallout', 'N8nIcon'],
},
});
expect(wrapper.html()).toMatchSnapshot();
});
});
@@ -3,12 +3,14 @@ import type { ButtonType } from '../../types/button';
import N8nButton from '../N8nButton';
import N8nCallout, { type CalloutTheme } from '../N8nCallout';
import N8nHeading from '../N8nHeading';
import N8nIcon from '../N8nIcon';
import { type IconName } from '../N8nIcon/icons';
import type { IconOrEmoji } from '../N8nIconPicker/types';
import N8nText from '../N8nText';
import N8nTooltip from '../N8nTooltip/Tooltip.vue';
interface ActionBoxProps {
emoji?: string;
icon?: IconOrEmoji;
heading?: string;
buttonText?: string;
buttonType?: ButtonType;
@@ -29,8 +31,15 @@ withDefaults(defineProps<ActionBoxProps>(), {
<template>
<div :class="['n8n-action-box', $style.container]" data-test-id="action-box">
<div v-if="emoji" :class="$style.emoji">
{{ emoji }}
<div v-if="icon" :class="$style.icon">
<N8nIcon
v-if="icon.type === 'icon'"
:icon="icon.value"
:size="40"
:stroke-width="1.5"
color="foreground-xdark"
/>
<span v-else>{{ icon.value }}</span>
</div>
<div v-if="heading || $slots.heading" :class="$style.heading">
<N8nHeading size="xlarge" align="center">
@@ -59,6 +68,9 @@ withDefaults(defineProps<ActionBoxProps>(), {
@click="$emit('click:button', $event)"
/>
</N8nTooltip>
<div v-if="$slots.additionalContent" :class="$style['additional-content']">
<slot name="additionalContent"></slot>
</div>
<N8nCallout
v-if="calloutText"
:theme="calloutTheme"
@@ -90,7 +102,7 @@ withDefaults(defineProps<ActionBoxProps>(), {
}
}
.emoji {
.icon {
font-size: 40px;
}
@@ -109,4 +121,10 @@ withDefaults(defineProps<ActionBoxProps>(), {
width: 100%;
text-align: left;
}
.additional-content {
display: flex;
margin-top: 0;
justify-content: center;
}
</style>
@@ -1,8 +1,8 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`N8NActionBox > should render correctly 1`] = `
exports[`N8NActionBox > should render correctly with emoji 1`] = `
"<div class="n8n-action-box container" data-test-id="action-box">
<div class="emoji">😿</div>
<div class="icon"><span>😿</span></div>
<div class="heading">
<n8n-heading-stub align="center" tag="span" bold="false" size="xlarge"></n8n-heading-stub>
</div>
@@ -13,5 +13,25 @@ exports[`N8NActionBox > should render correctly 1`] = `
<!--teleport start-->
<!--teleport end-->
<!--v-if-->
<!--v-if-->
</div>"
`;
exports[`N8NActionBox > should render correctly with icon 1`] = `
"<div class="n8n-action-box container" data-test-id="action-box">
<div class="icon">
<n8n-icon-stub icon="plus" strokewidth="1.5" size="40" spin="false" color="foreground-xdark"></n8n-icon-stub>
</div>
<div class="heading">
<n8n-heading-stub align="center" tag="span" bold="false" size="xlarge"></n8n-heading-stub>
</div>
<div class="description">
<n8n-text-stub color="text-base" bold="false" size="medium" compact="false" tag="span"></n8n-text-stub>
</div>
<n8n-button-stub block="false" element="button" label="Add Item" square="false" active="false" disabled="false" loading="false" outline="false" size="large" text="false" type="primary" role="button" class="el-tooltip__trigger"></n8n-button-stub>
<!--teleport start-->
<!--teleport end-->
<!--v-if-->
<!--v-if-->
</div>"
`;
@@ -595,7 +595,7 @@ defineExpose({
<slot name="empty">
<N8nActionBox
data-test-id="empty-resources-list"
emoji="👋"
:icon="{ type: 'emoji', value: '👋' }"
:heading="
getResourceText(
usersStore.currentUser?.firstName ? 'empty.heading' : 'empty.heading.userNotSetup',
@@ -334,7 +334,7 @@ onMounted(() => {
<N8nActionBox
v-else
data-test-id="empty-resources-list"
emoji="👋"
:icon="{ type: 'icon', value: 'lock' }"
:heading="
i18n.baseText(
usersStore.currentUser?.firstName