mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
fix(editor): fix performance issues when opening node or editing code node with a lot of data (#4388)
* debounce clicks * debounce correctly * debounce resize * if initialized avoid * set watcher fixes * add deboucne for setting values * increase debounce * reset workspace for memory issues * address comment * decrease debounce time * decrease debounce time * clean up * revert back to trailing * support dbl
This commit is contained in:
@@ -12,7 +12,7 @@
|
|||||||
:width="relativeWidthToPx(mainPanelDimensions.relativeWidth)"
|
:width="relativeWidthToPx(mainPanelDimensions.relativeWidth)"
|
||||||
:minWidth="MIN_PANEL_WIDTH"
|
:minWidth="MIN_PANEL_WIDTH"
|
||||||
:gridSize="20"
|
:gridSize="20"
|
||||||
@resize="onResize"
|
@resize="onResizeDebounced"
|
||||||
@resizestart="onResizeStart"
|
@resizestart="onResizeStart"
|
||||||
@resizeend="onResizeEnd"
|
@resizeend="onResizeEnd"
|
||||||
:supportedDirections="supportedResizeDirections"
|
:supportedDirections="supportedResizeDirections"
|
||||||
@@ -47,6 +47,8 @@ import {
|
|||||||
LOCAL_STORAGE_MAIN_PANEL_RELATIVE_WIDTH,
|
LOCAL_STORAGE_MAIN_PANEL_RELATIVE_WIDTH,
|
||||||
MAIN_NODE_PANEL_WIDTH,
|
MAIN_NODE_PANEL_WIDTH,
|
||||||
} from '@/constants';
|
} from '@/constants';
|
||||||
|
import mixins from 'vue-typed-mixins';
|
||||||
|
import { debounceHelper } from './mixins/debounce';
|
||||||
|
|
||||||
|
|
||||||
const SIDE_MARGIN = 24;
|
const SIDE_MARGIN = 24;
|
||||||
@@ -63,7 +65,7 @@ const initialMainPanelWidth:{ [key: string]: number } = {
|
|||||||
wide: MAIN_NODE_PANEL_WIDTH * 2,
|
wide: MAIN_NODE_PANEL_WIDTH * 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Vue.extend({
|
export default mixins(debounceHelper).extend({
|
||||||
name: 'NDVDraggablePanels',
|
name: 'NDVDraggablePanels',
|
||||||
components: {
|
components: {
|
||||||
PanelDragButton,
|
PanelDragButton,
|
||||||
@@ -83,11 +85,12 @@ export default Vue.extend({
|
|||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data(): { windowWidth: number, isDragging: boolean, MIN_PANEL_WIDTH: number} {
|
data(): { windowWidth: number, isDragging: boolean, MIN_PANEL_WIDTH: number, initialized: boolean} {
|
||||||
return {
|
return {
|
||||||
windowWidth: 1,
|
windowWidth: 1,
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
MIN_PANEL_WIDTH,
|
MIN_PANEL_WIDTH,
|
||||||
|
initialized: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -105,6 +108,9 @@ export default Vue.extend({
|
|||||||
|
|
||||||
window.addEventListener('resize', this.setTotalWidth);
|
window.addEventListener('resize', this.setTotalWidth);
|
||||||
this.$emit('init', { position: this.mainPanelDimensions.relativeLeft });
|
this.$emit('init', { position: this.mainPanelDimensions.relativeLeft });
|
||||||
|
setTimeout(() => {
|
||||||
|
this.initialized = true;
|
||||||
|
}, 0);
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
window.removeEventListener('resize', this.setTotalWidth);
|
window.removeEventListener('resize', this.setTotalWidth);
|
||||||
@@ -295,6 +301,11 @@ export default Vue.extend({
|
|||||||
onResizeEnd() {
|
onResizeEnd() {
|
||||||
this.storePositionData();
|
this.storePositionData();
|
||||||
},
|
},
|
||||||
|
onResizeDebounced(data: { direction: string, x: number, width: number}) {
|
||||||
|
if (this.initialized) {
|
||||||
|
this.callDebounced('onResize', { debounceTime: 10, trailing: true }, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
onResize({ direction, x, width }: { direction: string, x: number, width: number}) {
|
onResize({ direction, x, width }: { direction: string, x: number, width: number}) {
|
||||||
const relativeDistance = this.pxToRelativeWidth(x);
|
const relativeDistance = this.pxToRelativeWidth(x);
|
||||||
const relativeWidth = this.pxToRelativeWidth(width);
|
const relativeWidth = this.pxToRelativeWidth(width);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="node-wrapper" :style="nodePosition" :id="nodeId">
|
<div class="node-wrapper" :style="nodePosition" :id="nodeId">
|
||||||
<div class="select-background" v-show="isSelected"></div>
|
<div class="select-background" v-show="isSelected"></div>
|
||||||
<div :class="{'node-default': true, 'touch-active': isTouchActive, 'is-touch-device': isTouchDevice}" :data-name="data.name" :ref="data.name">
|
<div :class="{'node-default': true, 'touch-active': isTouchActive, 'is-touch-device': isTouchDevice}" :data-name="data.name" :ref="data.name">
|
||||||
<div :class="nodeClass" :style="nodeStyle" @dblclick="setNodeActive" @click.left="mouseLeftClick" v-touch:start="touchStart" v-touch:end="touchEnd">
|
<div :class="nodeClass" :style="nodeStyle" @click.left="onClick" v-touch:start="touchStart" v-touch:end="touchEnd">
|
||||||
<div v-if="!data.disabled" :class="{'node-info-icon': true, 'shift-icon': shiftOutputCount}">
|
<div v-if="!data.disabled" :class="{'node-info-icon': true, 'shift-icon': shiftOutputCount}">
|
||||||
<div v-if="hasIssues" class="node-issues">
|
<div v-if="hasIssues" class="node-issues">
|
||||||
<n8n-tooltip placement="bottom" >
|
<n8n-tooltip placement="bottom" >
|
||||||
@@ -112,6 +112,7 @@ import mixins from 'vue-typed-mixins';
|
|||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import { getStyleTokenValue, getTriggerNodeServiceName } from './helpers';
|
import { getStyleTokenValue, getTriggerNodeServiceName } from './helpers';
|
||||||
import { INodeUi, XYPosition } from '@/Interface';
|
import { INodeUi, XYPosition } from '@/Interface';
|
||||||
|
import { debounceHelper } from './mixins/debounce';
|
||||||
|
|
||||||
export default mixins(
|
export default mixins(
|
||||||
externalHooks,
|
externalHooks,
|
||||||
@@ -119,6 +120,7 @@ export default mixins(
|
|||||||
nodeHelpers,
|
nodeHelpers,
|
||||||
workflowHelpers,
|
workflowHelpers,
|
||||||
pinData,
|
pinData,
|
||||||
|
debounceHelper,
|
||||||
).extend({
|
).extend({
|
||||||
name: 'Node',
|
name: 'Node',
|
||||||
components: {
|
components: {
|
||||||
@@ -426,6 +428,19 @@ export default mixins(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onClick(event: MouseEvent) {
|
||||||
|
this.callDebounced('onClickDebounced', { debounceTime: 300, trailing: true }, event);
|
||||||
|
},
|
||||||
|
|
||||||
|
onClickDebounced(event: MouseEvent) {
|
||||||
|
const isDoubleClick = event.detail >= 2;
|
||||||
|
if (isDoubleClick) {
|
||||||
|
this.setNodeActive();
|
||||||
|
} else {
|
||||||
|
this.mouseLeftClick(event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
setNodeActive () {
|
setNodeActive () {
|
||||||
this.$store.commit('setActiveNode', this.data.name);
|
this.$store.commit('setActiveNode', this.data.name);
|
||||||
this.pinDataDiscoveryTooltipVisible = false;
|
this.pinDataDiscoveryTooltipVisible = false;
|
||||||
|
|||||||
@@ -352,7 +352,9 @@ export default mixins(
|
|||||||
this.avgOutputRowHeight = 0;
|
this.avgOutputRowHeight = 0;
|
||||||
this.avgInputRowHeight = 0;
|
this.avgInputRowHeight = 0;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
this.$store.commit('ui/setNDVSessionId');
|
this.$store.commit('ui/setNDVSessionId');
|
||||||
|
}, 0);
|
||||||
this.$externalHooks().run('dataDisplay.nodeTypeChanged', {
|
this.$externalHooks().run('dataDisplay.nodeTypeChanged', {
|
||||||
nodeSubtitle: this.getNodeSubtitle(node, this.activeNodeType, this.getCurrentWorkflow()),
|
nodeSubtitle: this.getNodeSubtitle(node, this.activeNodeType, this.getCurrentWorkflow()),
|
||||||
});
|
});
|
||||||
@@ -397,10 +399,14 @@ export default mixins(
|
|||||||
this.runInputIndex = -1;
|
this.runInputIndex = -1;
|
||||||
},
|
},
|
||||||
inputNodeName(nodeName: string | undefined) {
|
inputNodeName(nodeName: string | undefined) {
|
||||||
|
setTimeout(() => {
|
||||||
this.$store.commit('ui/setInputNodeName', nodeName);
|
this.$store.commit('ui/setInputNodeName', nodeName);
|
||||||
|
}, 0);
|
||||||
},
|
},
|
||||||
inputRun() {
|
inputRun() {
|
||||||
|
setTimeout(() => {
|
||||||
this.$store.commit('ui/setInputRunIndex', this.inputRun);
|
this.$store.commit('ui/setInputRunIndex', this.inputRun);
|
||||||
|
}, 0);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
:mode="node.parameters.mode"
|
:mode="node.parameters.mode"
|
||||||
:jsCode="node.parameters.jsCode"
|
:jsCode="node.parameters.jsCode"
|
||||||
:isReadOnly="isReadOnly"
|
:isReadOnly="isReadOnly"
|
||||||
@valueChanged="valueChanged"
|
@valueChanged="valueChangedDebounced"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div v-else-if="isEditor === true" class="code-edit clickable ph-no-capture" @click="displayEditDialog()">
|
<div v-else-if="isEditor === true" class="code-edit clickable ph-no-capture" @click="displayEditDialog()">
|
||||||
@@ -336,12 +336,14 @@ import { CUSTOM_API_CALL_KEY } from '@/constants';
|
|||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { CODE_NODE_TYPE } from '@/constants';
|
import { CODE_NODE_TYPE } from '@/constants';
|
||||||
import { PropType } from 'vue';
|
import { PropType } from 'vue';
|
||||||
|
import { debounceHelper } from './mixins/debounce';
|
||||||
|
|
||||||
export default mixins(
|
export default mixins(
|
||||||
externalHooks,
|
externalHooks,
|
||||||
nodeHelpers,
|
nodeHelpers,
|
||||||
showMessage,
|
showMessage,
|
||||||
workflowHelpers,
|
workflowHelpers,
|
||||||
|
debounceHelper,
|
||||||
)
|
)
|
||||||
.extend({
|
.extend({
|
||||||
name: 'parameter-input',
|
name: 'parameter-input',
|
||||||
@@ -922,6 +924,9 @@ export default mixins(
|
|||||||
|
|
||||||
this.$emit('textInput', parameterData);
|
this.$emit('textInput', parameterData);
|
||||||
},
|
},
|
||||||
|
valueChangedDebounced (value: NodeParameterValueType | {} | Date) {
|
||||||
|
this.callDebounced('valueChanged', { debounceTime: 100 }, value);
|
||||||
|
},
|
||||||
valueChanged (value: NodeParameterValueType | {} | Date) {
|
valueChanged (value: NodeParameterValueType | {} | Date) {
|
||||||
if (this.parameter.name === 'nodeCredentialType') {
|
if (this.parameter.name === 'nodeCredentialType') {
|
||||||
this.activeCredentialType = value as string;
|
this.activeCredentialType = value as string;
|
||||||
|
|||||||
Reference in New Issue
Block a user