fix(editor): Fix directives breaking reactivity (no-changelog) (#14665)

Co-authored-by: Csaba Tuncsik <csaba.tuncsik@gmail.com>
This commit is contained in:
Raúl Gómez Morales
2025-04-17 14:23:12 +02:00
committed by GitHub
parent 08e73d3aed
commit acf2453ea7
5 changed files with 83 additions and 27 deletions

View File

@@ -11,7 +11,7 @@ describe('Directive n8n-truncate', () => {
type: String,
},
},
template: '<p v-n8n-smart-decimal>{{text}}</p>',
template: '<p v-n8n-smart-decimal="text" />',
},
{
props: {
@@ -35,7 +35,7 @@ describe('Directive n8n-truncate', () => {
type: String,
},
},
template: '<p v-n8n-smart-decimal:3>{{text}}</p>',
template: '<p v-n8n-smart-decimal:3="text" />',
},
{
props: {
@@ -59,7 +59,7 @@ describe('Directive n8n-truncate', () => {
type: String,
},
},
template: '<p v-n8n-smart-decimal>{{text}}</p>',
template: '<p v-n8n-smart-decimal="text" />',
},
{
props: {
@@ -83,7 +83,7 @@ describe('Directive n8n-truncate', () => {
type: String,
},
},
template: '<p v-n8n-smart-decimal>{{text}}</p>',
template: '<p v-n8n-smart-decimal="text">',
},
{
props: {
@@ -107,7 +107,7 @@ describe('Directive n8n-truncate', () => {
type: String,
},
},
template: '<p v-n8n-smart-decimal:1>{{text}}</p>',
template: '<p v-n8n-smart-decimal:1="text">',
},
{
props: {
@@ -131,7 +131,7 @@ describe('Directive n8n-truncate', () => {
type: String,
},
},
template: '<p v-n8n-smart-decimal:3>{{text}}</p>',
template: '<p v-n8n-smart-decimal:3="text" />',
},
{
props: {
@@ -155,7 +155,7 @@ describe('Directive n8n-truncate', () => {
type: String,
},
},
template: '<p v-n8n-smart-decimal>{{text}}</p>',
template: '<p v-n8n-smart-decimal="text" />',
},
{
props: {
@@ -179,7 +179,7 @@ describe('Directive n8n-truncate', () => {
type: String,
},
},
template: '<p v-n8n-smart-decimal>{{text}}</p>',
template: '<p v-n8n-smart-decimal="text" />',
},
{
props: {
@@ -203,7 +203,7 @@ describe('Directive n8n-truncate', () => {
type: String,
},
},
template: '<p v-n8n-smart-decimal:5>{{text}}</p>',
template: '<p v-n8n-smart-decimal:5="text" />',
},
{
props: {
@@ -227,7 +227,7 @@ describe('Directive n8n-truncate', () => {
type: String,
},
},
template: '<p v-n8n-smart-decimal:3>{{text}}</p>',
template: '<p v-n8n-smart-decimal:3="text" />',
},
{
props: {
@@ -242,4 +242,32 @@ describe('Directive n8n-truncate', () => {
);
expect(html()).toBe('<p>42.12</p>');
});
it('rendered html should update when the value changes', async () => {
const { html, rerender } = render(
{
props: {
text: {
type: String,
},
},
template: '<p v-n8n-smart-decimal:3="text" />',
},
{
props: {
text: '42.12',
},
global: {
directives: {
n8nSmartDecimal,
},
},
},
);
expect(html()).toBe('<p>42.12</p>');
await rerender({ text: '12.42' });
expect(html()).toBe('<p>12.42</p>');
});
});

View File

@@ -8,12 +8,12 @@ import type { DirectiveBinding, FunctionDirective } from 'vue';
* In your Vue template, use the directive `v-n8n-smart-decimal` passing the number and optionally the decimal places.
*
* Example:
* <p v-n8n-smart-decimal>42.567</p>
* <p v-n8n-smart-decimal="42.567" />
*
* Compiles to: <p>42.57</p>
*
* Example with specified decimal places:
* <p v-n8n-smart-decimal:4>42.56789</p>
* <p v-n8n-smart-decimal:4="42.56789" />
*
* Compiles to: <p>42.5679</p>
*
@@ -28,7 +28,7 @@ export const n8nSmartDecimal: FunctionDirective = (
el: HTMLElement,
binding: DirectiveBinding<number | undefined>,
) => {
const value = parseFloat(el.textContent ?? '');
const value = parseFloat(binding.value?.toString() ?? '');
if (!isNaN(value)) {
const decimals = isNaN(Number(binding.arg)) ? undefined : Number(binding.arg);
const formattedValue = smartDecimal(value, decimals);

View File

@@ -11,7 +11,7 @@ describe('Directive n8n-truncate', () => {
type: String,
},
},
template: '<div v-n8n-truncate>{{text}}</div>',
template: '<div v-n8n-truncate="text" />',
},
{
props: {
@@ -35,7 +35,7 @@ describe('Directive n8n-truncate', () => {
type: String,
},
},
template: '<div v-n8n-truncate:ab>{{text}}</div>',
template: '<div v-n8n-truncate:ab="text" />',
},
{
props: {
@@ -59,7 +59,7 @@ describe('Directive n8n-truncate', () => {
type: String,
},
},
template: '<div v-n8n-truncate:25>{{text}}</div>',
template: '<div v-n8n-truncate:25="text" />',
},
{
props: {
@@ -74,4 +74,32 @@ describe('Directive n8n-truncate', () => {
);
expect(html()).toBe('<div>This is a very long text ...</div>');
});
it('rendered html should update when the value changes', async () => {
const { html, rerender } = render(
{
props: {
text: {
type: String,
},
},
template: '<div v-n8n-truncate:25="text" />',
},
{
props: {
text: 'This is a very long text that should be truncated',
},
global: {
directives: {
n8nTruncate,
},
},
},
);
expect(html()).toBe('<div>This is a very long text ...</div>');
await rerender({ text: 'new text to truncate that should be truncated' });
expect(html()).toBe('<div>new text to truncate that...</div>');
});
});

View File

@@ -1,5 +1,5 @@
import { truncate } from '@n8n/utils/string/truncate';
import type { DirectiveBinding, ObjectDirective } from 'vue';
import type { DirectiveBinding, FunctionDirective } from 'vue';
/**
* Custom directive `n8nTruncate` to truncate text content of an HTML element.
@@ -8,7 +8,7 @@ import type { DirectiveBinding, ObjectDirective } from 'vue';
* In your Vue template, use the directive `v-n8n-truncate` with an argument to specify the length to truncate to.
*
* Example:
* <p v-n8n-truncate:10>Some long text that will be truncated</p>
* <p v-n8n-truncate:10="'Some long text that will be truncated'" />
*
* This will truncate the text content of the paragraph to 10 characters.
*
@@ -16,11 +16,11 @@ import type { DirectiveBinding, ObjectDirective } from 'vue';
* https://vuejs.org/guide/reusability/custom-directives#usage-on-components
*/
export const n8nTruncate: ObjectDirective = {
mounted(el: HTMLElement, binding: DirectiveBinding) {
el.textContent = truncate(el.textContent ?? '', Number(binding.arg) || undefined);
},
updated(el: HTMLElement, binding: DirectiveBinding) {
el.textContent = truncate(el.textContent ?? '', Number(binding.arg) || undefined);
},
export const n8nTruncate: FunctionDirective<HTMLElement, string> = (
el: HTMLElement,
binding: DirectiveBinding<string>,
) => {
if (binding.value !== binding.oldValue) {
el.textContent = truncate(binding.value ?? '', Number(binding.arg) || undefined);
}
};

View File

@@ -161,9 +161,9 @@ const projectLocation = computed(() => {
>
<ProjectIcon :icon="badgeIcon" :border-less="true" size="mini" />
<router-link v-if="projectLocation" :to="projectLocation">
<span v-n8n-truncate:20>{{ badgeText }}</span>
<span v-n8n-truncate:20="badgeText" />
</router-link>
<span v-else v-n8n-truncate:20>{{ badgeText }}</span>
<span v-else v-n8n-truncate:20="badgeText" />
</N8nBadge>
<template #content>
{{ badgeTooltip }}