fix: Prevent overflow when rendering expression hints (#6214)

* fix: Prevent whitespace overflow

* fix: show overflow ellipsis

* chore: add comment

* chore: clean up other approach

* test: update tests, fix test

* test: uncomment test
This commit is contained in:
Mutasem Aldmour 2023-05-10 10:32:09 +02:00 committed by GitHub
parent 9e7b9fb443
commit c7177719e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 14 deletions

View file

@ -156,7 +156,7 @@ describe('Data mapping', () => {
ndv.getters
.inlineExpressionEditorInput()
.should('have.text', '{{ $json.input[0].count }} {{ $json.input }}');
ndv.getters.parameterExpressionPreview('value').should('include.text', '0 [object Object]');
ndv.actions.validateExpressionPreview('value', '0 [object Object]');
});
it('maps expressions from schema view', () => {
@ -172,7 +172,7 @@ describe('Data mapping', () => {
ndv.actions.mapToParameter('value');
ndv.getters.inlineExpressionEditorInput().should('have.text', '{{ $json.input[0].count }}');
ndv.getters.parameterExpressionPreview('value').should('include.text', '0');
ndv.actions.validateExpressionPreview('value', '0');
ndv.getters.inputDataContainer().find('span').contains('input').realMouseDown();
@ -180,7 +180,7 @@ describe('Data mapping', () => {
ndv.getters
.inlineExpressionEditorInput()
.should('have.text', '{{ $json.input[0].count }} {{ $json.input }}');
ndv.getters.parameterExpressionPreview('value').should('include.text', '0 [object Object]');
ndv.actions.validateExpressionPreview('value', '0 [object Object]');
});
it('maps expressions from previous nodes', () => {
@ -205,17 +205,17 @@ describe('Data mapping', () => {
'have.text',
`{{ $node['${SCHEDULE_TRIGGER_NODE_NAME}'].json.input[0].count }} {{ $node['${SCHEDULE_TRIGGER_NODE_NAME}'].json.input }}`,
);
ndv.getters.parameterExpressionPreview('value').should('have.text', ' ');
ndv.actions.validateExpressionPreview('value', ' ');
ndv.actions.selectInputNode('Set');
ndv.actions.executePrevious();
ndv.getters.executingLoader().should('not.exist');
ndv.getters.inputDataContainer().should('exist');
ndv.getters.parameterExpressionPreview('value').should('include.text', '0 [object Object]');
ndv.actions.validateExpressionPreview('value', '0 [object Object]');
ndv.getters.inputTbodyCell(2, 0).realHover();
ndv.getters.parameterExpressionPreview('value').should('include.text', '1 [object Object]');
ndv.actions.validateExpressionPreview('value', '1 [object Object]');
});
it('maps keys to path', () => {
@ -282,7 +282,7 @@ describe('Data mapping', () => {
ndv.actions.mapToParameter('value');
ndv.getters.inlineExpressionEditorInput().should('have.text', '{{ $json.input[0].count }}');
ndv.getters.parameterExpressionPreview('value').should('include.text', '0');
ndv.actions.validateExpressionPreview('value', '0');
ndv.getters.inputDataContainer().find('span').contains('input').realMouseDown();
@ -290,7 +290,7 @@ describe('Data mapping', () => {
ndv.getters
.inlineExpressionEditorInput()
.should('have.text', '{{ $json.input[0].count }} {{ $json.input }}');
ndv.getters.parameterExpressionPreview('value').should('include.text', '0 [object Object]');
ndv.actions.validateExpressionPreview('value', '0 [object Object]');
});
it('shows you can drop to inputs, including booleans', () => {

View file

@ -227,4 +227,42 @@ describe('NDV', () => {
.find('input')
.should('include.value', '2 of 2 (6 items)');
});
it('should display parameter hints correctly', () => {
workflowPage.actions.visit();
cy.createFixtureWorkflow('Test_workflow_3.json', `My test workflow`);
workflowPage.actions.openNode('Set1');
ndv.actions.typeIntoParameterInput('value', '='); // switch to expressions
[
{
input: 'hello',
},
{
input: '',
output: '[empty]',
},
{
input: ' test',
},
{
input: ' '
},
{
input: '<div></div>'
},
].forEach(({ input, output }) => {
if (input) {
ndv.actions.typeIntoParameterInput('value', input);
}
ndv.getters.parameterInput('name').click(); // remove focus from input, hide expression preview
ndv.actions.validateExpressionPreview('value', output || input);
ndv.getters.parameterInput('value').clear();
});
});
});

View file

@ -157,6 +157,19 @@ export class NDV extends BasePage {
this.getters.resourceLocatorModeSelector(paramName).click();
this.getters.resourceLocatorModeSelector(paramName).find('li').last().click();
this.getters.resourceLocatorInput(paramName).type(value);
}
},
validateExpressionPreview: (paramName: string, value: string) => {
this.getters.parameterExpressionPreview(paramName).find('span').should('include.html', asEncodedHTML(value));
},
};
}
function asEncodedHTML(str: string): string {
return String(str)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/ /g, '&nbsp;');
}

View file

@ -1,6 +1,6 @@
<template>
<n8n-text size="small" color="text-base" tag="div" v-if="hint">
<div v-if="!renderHTML" :class="classes">{{ hint }}</div>
<div v-if="!renderHTML" :class="classes"><span v-html="simplyText"></span></div>
<div
v-else
ref="hint"
@ -39,9 +39,20 @@ export default defineComponent({
return {
[this.$style.singleline]: this.singleLine,
[this.$style.highlight]: this.highlight,
[this.$style['preserve-whitespace']]: true,
};
},
simplyText(): string {
if (this.hint) {
return String(this.hint)
.replace(/&/g, '&amp;') // allows us to keep spaces at the beginning of an expression
.replace(/</g, '&lt;') // prevent XSS exploits since we are rendering HTML
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/ /g, '&nbsp;');
}
return '';
},
},
mounted() {
if (this.$refs.hint) {
@ -60,7 +71,4 @@ export default defineComponent({
.highlight {
color: var(--color-secondary);
}
.preserve-whitespace {
white-space: pre;
}
</style>