mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-12 05:17:28 -08:00
fix(editor): Add read only mode to filter component (#8285)
This commit is contained in:
parent
d877d3ce92
commit
dcc76f3480
|
@ -32,6 +32,7 @@ interface Props {
|
||||||
issues?: string[];
|
issues?: string[];
|
||||||
fixedLeftValue?: boolean;
|
fixedLeftValue?: boolean;
|
||||||
canRemove?: boolean;
|
canRemove?: boolean;
|
||||||
|
readOnly?: boolean;
|
||||||
index?: number;
|
index?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +40,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
issues: () => [],
|
issues: () => [],
|
||||||
canRemove: true,
|
canRemove: true,
|
||||||
fixedLeftValue: false,
|
fixedLeftValue: false,
|
||||||
|
readOnly: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -190,7 +192,7 @@ const onBlur = (): void => {
|
||||||
data-test-id="filter-condition"
|
data-test-id="filter-condition"
|
||||||
>
|
>
|
||||||
<n8n-icon-button
|
<n8n-icon-button
|
||||||
v-if="canRemove"
|
v-if="canRemove && !readOnly"
|
||||||
type="tertiary"
|
type="tertiary"
|
||||||
text
|
text
|
||||||
size="mini"
|
size="mini"
|
||||||
|
@ -227,6 +229,7 @@ const onBlur = (): void => {
|
||||||
:value="condition.leftValue"
|
:value="condition.leftValue"
|
||||||
:path="`${path}.left`"
|
:path="`${path}.left`"
|
||||||
:class="[$style.input, $style.inputLeft]"
|
:class="[$style.input, $style.inputLeft]"
|
||||||
|
:is-read-only="readOnly"
|
||||||
data-test-id="filter-condition-left"
|
data-test-id="filter-condition-left"
|
||||||
@update="onLeftValueChange"
|
@update="onLeftValueChange"
|
||||||
@blur="onBlur"
|
@blur="onBlur"
|
||||||
|
@ -234,6 +237,7 @@ const onBlur = (): void => {
|
||||||
<OperatorSelect
|
<OperatorSelect
|
||||||
:class="$style.select"
|
:class="$style.select"
|
||||||
:selected="`${operator.type}:${operator.operation}`"
|
:selected="`${operator.type}:${operator.operation}`"
|
||||||
|
:read-only="readOnly"
|
||||||
@operatorChange="onOperatorChange"
|
@operatorChange="onOperatorChange"
|
||||||
></OperatorSelect>
|
></OperatorSelect>
|
||||||
<ParameterInputFull
|
<ParameterInputFull
|
||||||
|
@ -248,6 +252,7 @@ const onBlur = (): void => {
|
||||||
:value="condition.rightValue"
|
:value="condition.rightValue"
|
||||||
:path="`${path}.right`"
|
:path="`${path}.right`"
|
||||||
:class="[$style.input, $style.inputRight]"
|
:class="[$style.input, $style.inputRight]"
|
||||||
|
:is-read-only="readOnly"
|
||||||
data-test-id="filter-condition-right"
|
data-test-id="filter-condition-right"
|
||||||
@update="onRightValueChange"
|
@update="onRightValueChange"
|
||||||
@blur="onBlur"
|
@blur="onBlur"
|
||||||
|
|
|
@ -29,9 +29,10 @@ interface Props {
|
||||||
value: FilterValue;
|
value: FilterValue;
|
||||||
path: string;
|
path: string;
|
||||||
node: INode | null;
|
node: INode | null;
|
||||||
|
readOnly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
const props = withDefaults(defineProps<Props>(), { readOnly: false });
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(event: 'valueChanged', value: { name: string; node: string; value: FilterValue }): void;
|
(event: 'valueChanged', value: { name: string; node: string; value: FilterValue }): void;
|
||||||
|
@ -145,7 +146,7 @@ function getIssues(index: number): string[] {
|
||||||
<div v-for="(condition, index) of state.paramValue.conditions" :key="condition.id">
|
<div v-for="(condition, index) of state.paramValue.conditions" :key="condition.id">
|
||||||
<CombinatorSelect
|
<CombinatorSelect
|
||||||
v-if="index !== 0"
|
v-if="index !== 0"
|
||||||
:read-only="index !== 1"
|
:read-only="index !== 1 || readOnly"
|
||||||
:options="allowedCombinators"
|
:options="allowedCombinators"
|
||||||
:selected="state.paramValue.combinator"
|
:selected="state.paramValue.combinator"
|
||||||
:class="$style.combinator"
|
:class="$style.combinator"
|
||||||
|
@ -157,6 +158,7 @@ function getIssues(index: number): string[] {
|
||||||
:index="index"
|
:index="index"
|
||||||
:options="state.paramValue.options"
|
:options="state.paramValue.options"
|
||||||
:fixed-left-value="!!parameter.typeOptions?.filter?.leftValue"
|
:fixed-left-value="!!parameter.typeOptions?.filter?.leftValue"
|
||||||
|
:read-only="readOnly"
|
||||||
:can-remove="index !== 0 || state.paramValue.conditions.length > 1"
|
:can-remove="index !== 0 || state.paramValue.conditions.length > 1"
|
||||||
:path="`${path}.${index}`"
|
:path="`${path}.${index}`"
|
||||||
:issues="getIssues(index)"
|
:issues="getIssues(index)"
|
||||||
|
@ -166,7 +168,7 @@ function getIssues(index: number): string[] {
|
||||||
></Condition>
|
></Condition>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!singleCondition" :class="$style.addConditionWrapper">
|
<div v-if="!singleCondition && !readOnly" :class="$style.addConditionWrapper">
|
||||||
<n8n-button
|
<n8n-button
|
||||||
type="tertiary"
|
type="tertiary"
|
||||||
block
|
block
|
||||||
|
|
|
@ -6,9 +6,10 @@ import type { FilterOperator } from './types';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
selected: string;
|
selected: string;
|
||||||
|
readOnly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
const props = withDefaults(defineProps<Props>(), { readOnly: false });
|
||||||
|
|
||||||
const selected = ref(props.selected);
|
const selected = ref(props.selected);
|
||||||
const menuOpen = ref(false);
|
const menuOpen = ref(false);
|
||||||
|
@ -57,6 +58,7 @@ function onGroupSelect(group: string) {
|
||||||
data-test-id="filter-operator-select"
|
data-test-id="filter-operator-select"
|
||||||
size="small"
|
size="small"
|
||||||
:model-value="selected"
|
:model-value="selected"
|
||||||
|
:disabled="readOnly"
|
||||||
@update:modelValue="onOperatorChange"
|
@update:modelValue="onOperatorChange"
|
||||||
@visible-change="onSelectVisibleChange"
|
@visible-change="onSelectVisibleChange"
|
||||||
@mouseenter="shouldRenderItems = true"
|
@mouseenter="shouldRenderItems = true"
|
||||||
|
|
|
@ -102,6 +102,7 @@
|
||||||
:value="nodeHelpers.getParameterValue(nodeValues, parameter.name, path)"
|
:value="nodeHelpers.getParameterValue(nodeValues, parameter.name, path)"
|
||||||
:path="getPath(parameter.name)"
|
:path="getPath(parameter.name)"
|
||||||
:node="node"
|
:node="node"
|
||||||
|
:read-only="isReadOnly"
|
||||||
@valueChanged="valueChanged"
|
@valueChanged="valueChanged"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { STORES } from '@/constants';
|
||||||
import { useNDVStore } from '@/stores/ndv.store';
|
import { useNDVStore } from '@/stores/ndv.store';
|
||||||
import { createTestingPinia } from '@pinia/testing';
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { within } from '@testing-library/vue';
|
||||||
|
|
||||||
const DEFAULT_SETUP = {
|
const DEFAULT_SETUP = {
|
||||||
pinia: createTestingPinia({
|
pinia: createTestingPinia({
|
||||||
|
@ -31,7 +32,7 @@ const DEFAULT_SETUP = {
|
||||||
|
|
||||||
const renderComponent = createComponentRenderer(FilterConditions, DEFAULT_SETUP);
|
const renderComponent = createComponentRenderer(FilterConditions, DEFAULT_SETUP);
|
||||||
|
|
||||||
describe('Filter.vue', () => {
|
describe('FilterConditions.vue', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
@ -264,4 +265,45 @@ describe('Filter.vue', () => {
|
||||||
expect(conditions.length).toEqual(1);
|
expect(conditions.length).toEqual(1);
|
||||||
expect(conditions[0].querySelector('[data-test-id="filter-remove-condition"]')).toBeNull();
|
expect(conditions[0].querySelector('[data-test-id="filter-remove-condition"]')).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders correctly in read only mode', async () => {
|
||||||
|
const { findAllByTestId, queryByTestId } = renderComponent({
|
||||||
|
props: {
|
||||||
|
...DEFAULT_SETUP.props,
|
||||||
|
value: {
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
leftValue: 'foo',
|
||||||
|
operator: { type: 'string', operation: 'equals' },
|
||||||
|
rightValue: 'bar',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
leftValue: 'foo',
|
||||||
|
operator: { type: 'string', operation: 'equals' },
|
||||||
|
rightValue: 'bar',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
readOnly: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(queryByTestId('filter-add-condition')).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
const conditions = await findAllByTestId('filter-condition');
|
||||||
|
|
||||||
|
for (const condition of conditions) {
|
||||||
|
const removeButton = within(condition).queryByTestId('filter-remove-condition');
|
||||||
|
expect(removeButton).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
const left = within(condition).getByTestId('filter-condition-left');
|
||||||
|
expect(left.querySelector('input')).toBeDisabled();
|
||||||
|
|
||||||
|
const right = within(condition).getByTestId('filter-condition-right');
|
||||||
|
expect(right.querySelector('input')).toBeDisabled();
|
||||||
|
|
||||||
|
const operatorSelect = within(condition).getByTestId('filter-operator-select');
|
||||||
|
expect(operatorSelect.querySelector('input')).toBeDisabled();
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue