mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 21:07:28 -08:00
feat(editor): Adjust HTML editor component for use in params (#5285)
* ✨ Adjust HTML editor component * ♻️ Apply feedback * ♻️ Apply feedback * 🔥 Remove unused ndv store refs
This commit is contained in:
parent
3b5e1d127f
commit
8b09e98654
|
@ -36,11 +36,20 @@ export default mixins(expressionManager).extend({
|
|||
props: {
|
||||
html: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
rows: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
},
|
||||
disableExpressionColoring: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -72,8 +81,8 @@ export default mixins(expressionManager).extend({
|
|||
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
||||
if (!viewUpdate.docChanged) return;
|
||||
|
||||
highlighter.removeColor(this.editor, this.htmlSegments);
|
||||
highlighter.addColor(this.editor, this.resolvableSegments);
|
||||
this.getHighlighter()?.removeColor(this.editor, this.htmlSegments);
|
||||
this.getHighlighter()?.addColor(this.editor, this.resolvableSegments);
|
||||
|
||||
this.$emit('valueChanged', this.doc);
|
||||
}),
|
||||
|
@ -144,7 +153,31 @@ export default mixins(expressionManager).extend({
|
|||
return root;
|
||||
},
|
||||
|
||||
isMissingHtmlTags() {
|
||||
const zerothSection = this.sections.at(0);
|
||||
|
||||
return (
|
||||
!zerothSection?.content.trim().startsWith('<html') &&
|
||||
!zerothSection?.content.trim().endsWith('</html>')
|
||||
);
|
||||
},
|
||||
|
||||
format() {
|
||||
if (this.sections.length === 1 && this.isMissingHtmlTags()) {
|
||||
const zerothSection = this.sections.at(0) as Section;
|
||||
|
||||
const formatted = prettier
|
||||
.format(zerothSection.content, {
|
||||
parser: 'html',
|
||||
plugins: [htmlParser],
|
||||
})
|
||||
.trim();
|
||||
|
||||
return this.editor.dispatch({
|
||||
changes: { from: 0, to: this.doc.length, insert: formatted },
|
||||
});
|
||||
}
|
||||
|
||||
const formatted = [];
|
||||
|
||||
for (const { kind, content } of this.sections) {
|
||||
|
@ -185,20 +218,34 @@ export default mixins(expressionManager).extend({
|
|||
}
|
||||
}
|
||||
|
||||
if (formatted.length === 0) return;
|
||||
|
||||
this.editor.dispatch({
|
||||
changes: { from: 0, to: this.doc.length, insert: formatted.join('\n\n') },
|
||||
});
|
||||
},
|
||||
|
||||
getHighlighter() {
|
||||
if (this.disableExpressionColoring) return;
|
||||
|
||||
return highlighter;
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
htmlEditorEventBus.$on('format-html', this.format);
|
||||
|
||||
const state = EditorState.create({ doc: this.html, extensions: this.extensions });
|
||||
let doc = this.html;
|
||||
|
||||
if (this.html === '' && this.rows > 0) {
|
||||
doc = '\n'.repeat(this.rows - 1);
|
||||
}
|
||||
|
||||
const state = EditorState.create({ doc, extensions: this.extensions });
|
||||
|
||||
this.editor = new EditorView({ parent: this.root(), state });
|
||||
|
||||
highlighter.addColor(this.editor, this.resolvableSegments);
|
||||
this.getHighlighter()?.addColor(this.editor, this.resolvableSegments);
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
|
|
|
@ -18,6 +18,9 @@ export const theme = [
|
|||
'.cm-cursor, .cm-dropCursor': {
|
||||
borderLeftColor: 'var(--color-code-caret)',
|
||||
},
|
||||
'&.cm-editor.cm-focused': {
|
||||
outline: '0',
|
||||
},
|
||||
'&.cm-focused .cm-selectionBackgroundm .cm-selectionBackground, .cm-content ::selection': {
|
||||
backgroundColor: 'var(--color-code-selection)',
|
||||
},
|
||||
|
@ -30,6 +33,8 @@ export const theme = [
|
|||
'.cm-gutters': {
|
||||
backgroundColor: 'var(--color-code-gutterBackground)',
|
||||
color: 'var(--color-code-gutterForeground)',
|
||||
borderTopLeftRadius: 'var(--border-radius-base)',
|
||||
borderBottomLeftRadius: 'var(--border-radius-base)',
|
||||
},
|
||||
'.cm-scroller': {
|
||||
overflow: 'auto',
|
||||
|
|
|
@ -81,9 +81,11 @@
|
|||
/>
|
||||
|
||||
<html-editor
|
||||
v-else-if="getArgument('editor') === 'htmlEditor' && isHtmlNode(node)"
|
||||
v-else-if="getArgument('editor') === 'htmlEditor'"
|
||||
:html="node.parameters.html"
|
||||
:isReadOnly="isReadOnly"
|
||||
:rows="getArgument('rows')"
|
||||
:disableExpressionColoring="!isHtmlNode(node)"
|
||||
@valueChanged="valueChangedDebounced"
|
||||
/>
|
||||
|
||||
|
@ -353,8 +355,8 @@ import { workflowHelpers } from '@/mixins/workflowHelpers';
|
|||
import { hasExpressionMapping, isValueExpression, isResourceLocatorValue } from '@/utils';
|
||||
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { CUSTOM_API_CALL_KEY } from '@/constants';
|
||||
import { CODE_NODE_TYPE, HTML_NODE_TYPE } from '@/constants';
|
||||
import { CUSTOM_API_CALL_KEY, HTML_NODE_TYPE } from '@/constants';
|
||||
import { CODE_NODE_TYPE } from '@/constants';
|
||||
import { PropType } from 'vue';
|
||||
import { debounceHelper } from '@/mixins/debounce';
|
||||
import { mapStores } from 'pinia';
|
||||
|
|
|
@ -28,9 +28,6 @@
|
|||
import { NodeParameterValueType } from 'n8n-workflow';
|
||||
import Vue, { PropType } from 'vue';
|
||||
import { isValueExpression, isResourceLocatorValue } from '@/utils';
|
||||
import { useNDVStore } from '@/stores/ndv';
|
||||
import { mapStores } from 'pinia';
|
||||
import { HTML_NODE_TYPE } from '@/constants';
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'parameter-options',
|
||||
|
@ -54,13 +51,15 @@ export default Vue.extend({
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
...mapStores(useNDVStore),
|
||||
isDefault(): boolean {
|
||||
return this.parameter.default === this.value;
|
||||
},
|
||||
isValueExpression(): boolean {
|
||||
return isValueExpression(this.parameter, this.value);
|
||||
},
|
||||
isHtmlEditor(): boolean {
|
||||
return this.getArgument('editor') === 'htmlEditor';
|
||||
},
|
||||
shouldShowOptions(): boolean {
|
||||
if (this.isReadOnly === true) {
|
||||
return false;
|
||||
|
@ -95,13 +94,10 @@ export default Vue.extend({
|
|||
return !!this.getArgument('loadOptionsMethod') || !!this.getArgument('loadOptions');
|
||||
},
|
||||
actions(): Array<{ label: string; value: string; disabled?: boolean }> {
|
||||
if (
|
||||
this.ndvStore.activeNode?.type === HTML_NODE_TYPE &&
|
||||
this.ndvStore.activeNode?.parameters.operation === 'generateHtmlTemplate'
|
||||
) {
|
||||
if (this.isHtmlEditor && !this.isValueExpression) {
|
||||
return [
|
||||
{
|
||||
label: 'Format HTML',
|
||||
label: this.$locale.baseText('parameterInput.formatHtml'),
|
||||
value: 'formatHtml',
|
||||
},
|
||||
];
|
||||
|
|
|
@ -878,6 +878,7 @@
|
|||
"parameterInput.error": "ERROR",
|
||||
"parameterInput.expression": "Expression",
|
||||
"parameterInput.fixed": "Fixed",
|
||||
"parameterInput.formatHtml": "Format HTML",
|
||||
"parameterInput.issues": "Issues",
|
||||
"parameterInput.loadingOptions": "Loading options...",
|
||||
"parameterInput.openEditWindow": "Open Edit Window",
|
||||
|
|
|
@ -85,6 +85,7 @@ export class Mailgun implements INodeType {
|
|||
type: 'string',
|
||||
typeOptions: {
|
||||
rows: 5,
|
||||
editor: 'htmlEditor',
|
||||
},
|
||||
default: '',
|
||||
description: 'HTML text message of email',
|
||||
|
|
Loading…
Reference in a new issue