feat(Switch Node): Overhaul (#7855)

Github issue / Community forum post (link here to close automatically):
https://community.n8n.io/t/switch-node-to-more-than-one-path/32791/2

https://community.n8n.io/t/switch-node-routing-same-value-multiple-output/29424

---------

Co-authored-by: Elias Meire <elias@meire.dev>
Co-authored-by: Giulio Andreini <andreini@netseven.it>
This commit is contained in:
Michael Kret
2024-01-04 11:03:03 +02:00
committed by GitHub
parent cd3f5b5b1f
commit f4092a9e49
11 changed files with 860 additions and 8 deletions

View File

@@ -288,7 +288,6 @@ const onBlur = (): void => {
display: flex;
align-items: flex-end;
gap: var(--spacing-4xs);
padding-left: var(--spacing-l);
&.hasIssues {
--input-border-color: var(--color-danger);
@@ -354,7 +353,6 @@ const onBlur = (): void => {
}
.remove {
--button-font-color: var(--color-text-light);
position: absolute;
left: 0;
top: var(--spacing-l);

View File

@@ -61,6 +61,8 @@ const maxConditions = computed(
() => props.parameter.typeOptions?.filter?.maxConditions ?? DEFAULT_MAX_CONDITIONS,
);
const singleCondition = computed(() => props.parameter.typeOptions?.multipleValues === false);
const maxConditionsReached = computed(
() => maxConditions.value <= state.paramValue.conditions.length,
);
@@ -125,8 +127,12 @@ function getIssues(index: number): string[] {
</script>
<template>
<div :class="$style.filter" :data-test-id="`filter-${parameter.name}`">
<div
:class="{ [$style.filter]: true, [$style.single]: singleCondition }"
:data-test-id="`filter-${parameter.name}`"
>
<n8n-input-label
v-if="!singleCondition"
:label="parameter.displayName"
:underline="true"
:show-options="true"
@@ -154,12 +160,13 @@ function getIssues(index: number): string[] {
:can-remove="index !== 0 || state.paramValue.conditions.length > 1"
:path="`${path}.${index}`"
:issues="getIssues(index)"
:class="$style.condition"
@update="(value) => onConditionUpdate(index, value)"
@remove="() => onConditionRemove(index)"
></Condition>
</div>
</div>
<div :class="$style.addConditionWrapper">
<div v-if="!singleCondition" :class="$style.addConditionWrapper">
<n8n-button
type="tertiary"
block
@@ -195,6 +202,20 @@ function getIssues(index: number): string[] {
margin-left: var(--spacing-l);
}
.condition {
padding-left: var(--spacing-l);
}
.single {
.condition {
padding-left: 0;
}
.content {
margin-top: calc(var(--spacing-xs) * -1);
}
}
.addConditionWrapper {
margin-top: var(--spacing-l);
margin-left: var(--spacing-l);

View File

@@ -167,6 +167,10 @@ export default defineComponent({
size: 'small',
}),
},
entryIndex: {
type: Number,
default: undefined,
},
},
setup() {
const eventBus = createEventBus();

View File

@@ -217,6 +217,10 @@ export default defineComponent({
type: Array as PropType<string[]>,
default: () => [],
},
entryIndex: {
type: Number,
default: undefined,
},
},
setup() {
const nodeHelpers = useNodeHelpers();

View File

@@ -157,7 +157,24 @@ describe('Filter.vue', () => {
expect(getByTestId('parameter-issues')).toBeInTheDocument();
});
it('renders correctly with typeOptions.leftValue', async () => {
it('renders correctly with typeOptions.multipleValues = false (single mode)', async () => {
const { getByTestId, queryByTestId, findAllByTestId } = renderComponent({
props: {
...DEFAULT_SETUP.props,
parameter: {
...DEFAULT_SETUP.props.parameter,
typeOptions: {
multipleValues: false,
},
},
},
});
expect((await findAllByTestId('filter-condition')).length).toEqual(1);
expect(getByTestId('filter-conditions')).toHaveClass('single');
expect(queryByTestId('filter-add-condition')).not.toBeInTheDocument();
});
it('renders correctly with typeOptions.filter.leftValue', async () => {
const { findAllByTestId } = renderComponent({
props: {
...DEFAULT_SETUP.props,
@@ -173,7 +190,7 @@ describe('Filter.vue', () => {
expect(conditions[0].querySelector('[data-test-id="filter-condition-left"]')).toBeNull();
});
it('renders correctly with typeOptions.allowedCombinators', async () => {
it('renders correctly with typeOptions.filter.allowedCombinators', async () => {
const { getByTestId } = renderComponent({
props: {
...DEFAULT_SETUP.props,
@@ -202,7 +219,7 @@ describe('Filter.vue', () => {
expect(getByTestId('filter-combinator-select')).toHaveTextContent('OR');
});
it('renders correctly with typeOptions.maxConditions', async () => {
it('renders correctly with typeOptions.filter.maxConditions', async () => {
const { getByTestId } = renderComponent({
props: {
...DEFAULT_SETUP.props,