fix(editor): Prevent unnecessary updates on model value change in InlineTextEdit component (#17553)

This commit is contained in:
Csaba Tuncsik
2025-07-23 13:19:56 +02:00
committed by GitHub
parent f11ec538dc
commit 832b7fda3b
2 changed files with 39 additions and 10 deletions

View File

@@ -23,14 +23,21 @@ describe('N8nInlineTextEdit', () => {
modelValue: 'Test Value', modelValue: 'Test Value',
}, },
}); });
const input = wrapper.getByTestId('inline-edit-input');
const preview = wrapper.getByTestId('inline-edit-preview'); const preview = wrapper.getByTestId('inline-edit-preview');
await wrapper.rerender({ modelValue: 'New Value' }); await userEvent.click(preview);
const input = wrapper.getByTestId('inline-edit-input');
await userEvent.clear(input);
await userEvent.type(input, 'Updated Value'); await userEvent.type(input, 'Updated Value');
await userEvent.keyboard('{Enter}'); await userEvent.keyboard('{Enter}');
expect(preview).toHaveTextContent('Updated Value'); expect(preview).toHaveTextContent('Updated Value');
const emittedEvents = wrapper.emitted('update:model-value');
expect(emittedEvents).toBeDefined();
expect(emittedEvents?.[0]).toEqual(['Updated Value']);
}); });
it('should not update value on blur if input is empty', async () => { it('should not update value on blur if input is empty', async () => {
@@ -39,9 +46,11 @@ describe('N8nInlineTextEdit', () => {
modelValue: 'Test Value', modelValue: 'Test Value',
}, },
}); });
const input = wrapper.getByTestId('inline-edit-input');
const preview = wrapper.getByTestId('inline-edit-preview'); const preview = wrapper.getByTestId('inline-edit-preview');
await userEvent.click(preview);
const input = wrapper.getByTestId('inline-edit-input');
await userEvent.clear(input); await userEvent.clear(input);
await userEvent.tab(); // Simulate blur await userEvent.tab(); // Simulate blur
@@ -54,12 +63,31 @@ describe('N8nInlineTextEdit', () => {
modelValue: 'Test Value', modelValue: 'Test Value',
}, },
}); });
const input = wrapper.getByTestId('inline-edit-input');
const preview = wrapper.getByTestId('inline-edit-preview'); const preview = wrapper.getByTestId('inline-edit-preview');
await userEvent.click(preview);
const input = wrapper.getByTestId('inline-edit-input');
await userEvent.clear(input);
await userEvent.type(input, 'Updated Value'); await userEvent.type(input, 'Updated Value');
await userEvent.keyboard('{Escape}'); await userEvent.keyboard('{Escape}');
expect(preview).toHaveTextContent('Test Value'); expect(preview).toHaveTextContent('Test Value');
}); });
it('should not emit update:model-value on blur when value unchanged', async () => {
const wrapper = renderComponent({
props: {
modelValue: 'Test Value',
},
});
const preview = wrapper.getByTestId('inline-edit-preview');
await userEvent.click(preview);
await userEvent.tab();
const emittedEvents = wrapper.emitted('update:model-value');
expect(emittedEvents).toBeUndefined();
});
}); });

View File

@@ -25,6 +25,8 @@ const emit = defineEmits<{
'update:model-value': [value: string]; 'update:model-value': [value: string];
}>(); }>();
const newValue = ref(props.modelValue);
const temp = ref(props.modelValue || props.placeholder);
const editableRoot = useTemplateRef('editableRoot'); const editableRoot = useTemplateRef('editableRoot');
function forceFocus() { function forceFocus() {
@@ -40,15 +42,15 @@ function forceCancel() {
} }
} }
defineExpose({ forceFocus, forceCancel });
function onSubmit() { function onSubmit() {
if (newValue.value === '') { if (newValue.value === '') {
newValue.value = props.modelValue; newValue.value = props.modelValue;
temp.value = props.modelValue; temp.value = props.modelValue;
return; return;
} }
emit('update:model-value', newValue.value); if (newValue.value !== props.modelValue) {
emit('update:model-value', newValue.value);
}
} }
function onInput(value: string) { function onInput(value: string) {
@@ -62,9 +64,6 @@ function onStateChange(state: string) {
} }
// Resize logic // Resize logic
const newValue = ref(props.modelValue);
const temp = ref(props.modelValue || props.placeholder);
const measureSpan = useTemplateRef('measureSpan'); const measureSpan = useTemplateRef('measureSpan');
const { width: measuredWidth } = useElementSize(measureSpan); const { width: measuredWidth } = useElementSize(measureSpan);
@@ -85,6 +84,8 @@ const computedInlineStyles = computed(() => {
zIndex: 1, zIndex: 1,
}; };
}); });
defineExpose({ forceFocus, forceCancel });
</script> </script>
<template> <template>