mirror of
https://github.com/n8n-io/n8n.git
synced 2024-09-20 14:57:31 -07:00
feat(editor): Migrate debounce mixin to useDebounce composable (no-changelog) (#8244)
This commit is contained in:
parent
8affdf680d
commit
8c8caac4e8
|
@ -17,14 +17,17 @@ import { BREAKPOINT_SM, BREAKPOINT_MD, BREAKPOINT_LG, BREAKPOINT_XL } from '@/co
|
||||||
* xl >= 1920
|
* xl >= 1920
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { debounceHelper } from '@/mixins/debounce';
|
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
import { getBannerRowHeight } from '@/utils/htmlUtils';
|
import { getBannerRowHeight } from '@/utils/htmlUtils';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'BreakpointsObserver',
|
name: 'BreakpointsObserver',
|
||||||
mixins: [debounceHelper],
|
|
||||||
props: ['valueXS', 'valueXL', 'valueLG', 'valueMD', 'valueSM', 'valueDefault'],
|
props: ['valueXS', 'valueXL', 'valueLG', 'valueMD', 'valueSM', 'valueDefault'],
|
||||||
|
setup() {
|
||||||
|
const { callDebounced } = useDebounce();
|
||||||
|
return { callDebounced };
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
|
@ -83,7 +86,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onResize() {
|
onResize() {
|
||||||
void this.callDebounced('onResizeEnd', { debounceTime: 50 });
|
void this.callDebounced(this.onResizeEnd, { debounceTime: 50 });
|
||||||
},
|
},
|
||||||
async onResizeEnd() {
|
async onResizeEnd() {
|
||||||
this.width = window.innerWidth;
|
this.width = window.innerWidth;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, reactive, onBeforeMount, ref } from 'vue';
|
import { computed, reactive, onBeforeMount, ref } from 'vue';
|
||||||
import debounce from 'lodash/debounce';
|
|
||||||
import type {
|
import type {
|
||||||
ExecutionFilterType,
|
ExecutionFilterType,
|
||||||
ExecutionFilterMetadata,
|
ExecutionFilterMetadata,
|
||||||
|
@ -11,10 +10,10 @@ import TagsDropdown from '@/components/TagsDropdown.vue';
|
||||||
import { getObjectKeys, isEmpty } from '@/utils/typesUtils';
|
import { getObjectKeys, isEmpty } from '@/utils/typesUtils';
|
||||||
import { EnterpriseEditionFeature } from '@/constants';
|
import { EnterpriseEditionFeature } from '@/constants';
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
import { useUsageStore } from '@/stores/usage.store';
|
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
import type { Placement } from '@floating-ui/core';
|
import type { Placement } from '@floating-ui/core';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
export type ExecutionFilterProps = {
|
export type ExecutionFilterProps = {
|
||||||
workflows?: IWorkflowShortResponse[];
|
workflows?: IWorkflowShortResponse[];
|
||||||
|
@ -25,8 +24,8 @@ export type ExecutionFilterProps = {
|
||||||
const DATE_TIME_MASK = 'YYYY-MM-DD HH:mm';
|
const DATE_TIME_MASK = 'YYYY-MM-DD HH:mm';
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const usageStore = useUsageStore();
|
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
|
const { debounce } = useDebounce();
|
||||||
|
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
|
|
||||||
|
@ -37,7 +36,9 @@ const props = withDefaults(defineProps<ExecutionFilterProps>(), {
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(event: 'filterChanged', value: ExecutionFilterType): void;
|
(event: 'filterChanged', value: ExecutionFilterType): void;
|
||||||
}>();
|
}>();
|
||||||
const debouncedEmit = debounce(emit, 500);
|
const debouncedEmit = debounce(emit, {
|
||||||
|
debounceTime: 500,
|
||||||
|
});
|
||||||
|
|
||||||
const isCustomDataFilterTracked = ref(false);
|
const isCustomDataFilterTracked = ref(false);
|
||||||
const isAdvancedExecutionFilterEnabled = computed(() =>
|
const isAdvancedExecutionFilterEnabled = computed(() =>
|
||||||
|
|
|
@ -58,7 +58,6 @@ import { v4 as uuid } from 'uuid';
|
||||||
import type { Route } from 'vue-router';
|
import type { Route } from 'vue-router';
|
||||||
import { executionHelpers } from '@/mixins/executionsHelpers';
|
import { executionHelpers } from '@/mixins/executionsHelpers';
|
||||||
import { range as _range } from 'lodash-es';
|
import { range as _range } from 'lodash-es';
|
||||||
import { debounceHelper } from '@/mixins/debounce';
|
|
||||||
import { NO_NETWORK_ERROR_CODE } from '@/utils/apiUtils';
|
import { NO_NETWORK_ERROR_CODE } from '@/utils/apiUtils';
|
||||||
import { getNodeViewTab } from '@/utils/canvasUtils';
|
import { getNodeViewTab } from '@/utils/canvasUtils';
|
||||||
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
||||||
|
@ -69,6 +68,7 @@ import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||||
import { useTagsStore } from '@/stores/tags.store';
|
import { useTagsStore } from '@/stores/tags.store';
|
||||||
import { executionFilterToQueryFilter } from '@/utils/executionUtils';
|
import { executionFilterToQueryFilter } from '@/utils/executionUtils';
|
||||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
// Number of execution pages that are fetched before temporary execution card is shown
|
// Number of execution pages that are fetched before temporary execution card is shown
|
||||||
const MAX_LOADING_ATTEMPTS = 5;
|
const MAX_LOADING_ATTEMPTS = 5;
|
||||||
|
@ -80,12 +80,14 @@ export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
ExecutionsSidebar,
|
ExecutionsSidebar,
|
||||||
},
|
},
|
||||||
mixins: [executionHelpers, debounceHelper, workflowHelpers],
|
mixins: [executionHelpers, workflowHelpers],
|
||||||
setup() {
|
setup() {
|
||||||
const externalHooks = useExternalHooks();
|
const externalHooks = useExternalHooks();
|
||||||
|
const { callDebounced } = useDebounce();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
externalHooks,
|
externalHooks,
|
||||||
|
callDebounced,
|
||||||
...useToast(),
|
...useToast(),
|
||||||
...useMessage(),
|
...useMessage(),
|
||||||
};
|
};
|
||||||
|
@ -231,7 +233,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
async onLoadMore(): Promise<void> {
|
async onLoadMore(): Promise<void> {
|
||||||
if (!this.loadingMore) {
|
if (!this.loadingMore) {
|
||||||
await this.callDebounced('loadMore', { debounceTime: 1000 });
|
await this.callDebounced(this.loadMore, { debounceTime: 1000 });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async loadMore(limit = 20): Promise<void> {
|
async loadMore(limit = 20): Promise<void> {
|
||||||
|
|
|
@ -89,11 +89,11 @@ import type { IVariableItemSelected } from '@/Interface';
|
||||||
|
|
||||||
import { EXPRESSIONS_DOCS_URL } from '@/constants';
|
import { EXPRESSIONS_DOCS_URL } from '@/constants';
|
||||||
|
|
||||||
import { debounceHelper } from '@/mixins/debounce';
|
|
||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { useNDVStore } from '@/stores/ndv.store';
|
import { useNDVStore } from '@/stores/ndv.store';
|
||||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||||
import { createExpressionTelemetryPayload } from '@/utils/telemetryUtils';
|
import { createExpressionTelemetryPayload } from '@/utils/telemetryUtils';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
import type { Segment } from '@/types/expressions';
|
import type { Segment } from '@/types/expressions';
|
||||||
|
|
||||||
|
@ -104,7 +104,6 @@ export default defineComponent({
|
||||||
ExpressionEditorModalOutput,
|
ExpressionEditorModalOutput,
|
||||||
VariableSelector,
|
VariableSelector,
|
||||||
},
|
},
|
||||||
mixins: [debounceHelper],
|
|
||||||
props: {
|
props: {
|
||||||
dialogVisible: {
|
dialogVisible: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -137,8 +136,10 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const externalHooks = useExternalHooks();
|
const externalHooks = useExternalHooks();
|
||||||
|
const { callDebounced } = useDebounce();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
callDebounced,
|
||||||
externalHooks,
|
externalHooks,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -194,7 +195,9 @@ export default defineComponent({
|
||||||
this.updateDisplayValue();
|
this.updateDisplayValue();
|
||||||
this.$emit('update:modelValue', this.latestValue);
|
this.$emit('update:modelValue', this.latestValue);
|
||||||
} else {
|
} else {
|
||||||
void this.callDebounced('updateDisplayValue', { debounceTime: 500 });
|
void this.callDebounced(this.updateDisplayValue, {
|
||||||
|
debounceTime: 500,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {
|
||||||
DEFAULT_OPERATOR_VALUE,
|
DEFAULT_OPERATOR_VALUE,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { useDebounceHelper } from '@/composables/useDebounce';
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
import Condition from './Condition.vue';
|
import Condition from './Condition.vue';
|
||||||
import CombinatorSelect from './CombinatorSelect.vue';
|
import CombinatorSelect from './CombinatorSelect.vue';
|
||||||
import { resolveParameter } from '@/mixins/workflowHelpers';
|
import { resolveParameter } from '@/mixins/workflowHelpers';
|
||||||
|
@ -39,7 +39,7 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const ndvStore = useNDVStore();
|
const ndvStore = useNDVStore();
|
||||||
const { callDebounced } = useDebounceHelper();
|
const { callDebounced } = useDebounce();
|
||||||
|
|
||||||
function createCondition(): FilterConditionValue {
|
function createCondition(): FilterConditionValue {
|
||||||
return { id: uuid(), leftValue: '', rightValue: '', operator: DEFAULT_OPERATOR_VALUE };
|
return { id: uuid(), leftValue: '', rightValue: '', operator: DEFAULT_OPERATOR_VALUE };
|
||||||
|
|
|
@ -107,7 +107,6 @@ import GiftNotificationIcon from './GiftNotificationIcon.vue';
|
||||||
import { useMessage } from '@/composables/useMessage';
|
import { useMessage } from '@/composables/useMessage';
|
||||||
import { ABOUT_MODAL_KEY, VERSIONS_MODAL_KEY, VIEWS } from '@/constants';
|
import { ABOUT_MODAL_KEY, VERSIONS_MODAL_KEY, VIEWS } from '@/constants';
|
||||||
import { userHelpers } from '@/mixins/userHelpers';
|
import { userHelpers } from '@/mixins/userHelpers';
|
||||||
import { debounceHelper } from '@/mixins/debounce';
|
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
import { useCloudPlanStore } from '@/stores/cloudPlan.store';
|
import { useCloudPlanStore } from '@/stores/cloudPlan.store';
|
||||||
|
@ -123,6 +122,7 @@ import ExecutionsUsage from '@/components/ExecutionsUsage.vue';
|
||||||
import MainSidebarSourceControl from '@/components/MainSidebarSourceControl.vue';
|
import MainSidebarSourceControl from '@/components/MainSidebarSourceControl.vue';
|
||||||
import { hasPermission } from '@/rbac/permissions';
|
import { hasPermission } from '@/rbac/permissions';
|
||||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'MainSidebar',
|
name: 'MainSidebar',
|
||||||
|
@ -131,12 +131,14 @@ export default defineComponent({
|
||||||
ExecutionsUsage,
|
ExecutionsUsage,
|
||||||
MainSidebarSourceControl,
|
MainSidebarSourceControl,
|
||||||
},
|
},
|
||||||
mixins: [userHelpers, debounceHelper],
|
mixins: [userHelpers],
|
||||||
setup(props, ctx) {
|
setup(props, ctx) {
|
||||||
const externalHooks = useExternalHooks();
|
const externalHooks = useExternalHooks();
|
||||||
|
const { callDebounced } = useDebounce();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
externalHooks,
|
externalHooks,
|
||||||
|
callDebounced,
|
||||||
...useMessage(),
|
...useMessage(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -497,7 +499,7 @@ export default defineComponent({
|
||||||
return defaultSettingsRoute;
|
return defaultSettingsRoute;
|
||||||
},
|
},
|
||||||
onResize(event: UIEvent) {
|
onResize(event: UIEvent) {
|
||||||
void this.callDebounced('onResizeEnd', { debounceTime: 100 }, event);
|
void this.callDebounced(this.onResizeEnd, { debounceTime: 100 }, event);
|
||||||
},
|
},
|
||||||
async onResizeEnd(event: UIEvent) {
|
async onResizeEnd(event: UIEvent) {
|
||||||
const browserWidth = (event.target as Window).outerWidth;
|
const browserWidth = (event.target as Window).outerWidth;
|
||||||
|
|
|
@ -53,10 +53,10 @@ import type { INodeTypeDescription } from 'n8n-workflow';
|
||||||
import PanelDragButton from './PanelDragButton.vue';
|
import PanelDragButton from './PanelDragButton.vue';
|
||||||
|
|
||||||
import { LOCAL_STORAGE_MAIN_PANEL_RELATIVE_WIDTH, MAIN_NODE_PANEL_WIDTH } from '@/constants';
|
import { LOCAL_STORAGE_MAIN_PANEL_RELATIVE_WIDTH, MAIN_NODE_PANEL_WIDTH } from '@/constants';
|
||||||
import { debounceHelper } from '@/mixins/debounce';
|
|
||||||
import { useNDVStore } from '@/stores/ndv.store';
|
import { useNDVStore } from '@/stores/ndv.store';
|
||||||
import { ndvEventBus } from '@/event-bus';
|
import { ndvEventBus } from '@/event-bus';
|
||||||
import NDVFloatingNodes from '@/components/NDVFloatingNodes.vue';
|
import NDVFloatingNodes from '@/components/NDVFloatingNodes.vue';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
const SIDE_MARGIN = 24;
|
const SIDE_MARGIN = 24;
|
||||||
const SIDE_PANELS_MARGIN = 80;
|
const SIDE_PANELS_MARGIN = 80;
|
||||||
|
@ -78,7 +78,6 @@ export default defineComponent({
|
||||||
PanelDragButton,
|
PanelDragButton,
|
||||||
NDVFloatingNodes,
|
NDVFloatingNodes,
|
||||||
},
|
},
|
||||||
mixins: [debounceHelper],
|
|
||||||
props: {
|
props: {
|
||||||
isDraggable: {
|
isDraggable: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -94,6 +93,11 @@ export default defineComponent({
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { callDebounced } = useDebounce();
|
||||||
|
|
||||||
|
return { callDebounced };
|
||||||
|
},
|
||||||
data(): {
|
data(): {
|
||||||
windowWidth: number;
|
windowWidth: number;
|
||||||
isDragging: boolean;
|
isDragging: boolean;
|
||||||
|
@ -343,7 +347,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
onResizeDebounced(data: { direction: string; x: number; width: number }) {
|
onResizeDebounced(data: { direction: string; x: number; width: number }) {
|
||||||
if (this.initialized) {
|
if (this.initialized) {
|
||||||
void this.callDebounced('onResize', { debounceTime: 10, trailing: true }, data);
|
void this.callDebounced(this.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 }) {
|
||||||
|
|
|
@ -176,7 +176,6 @@ import TitledList from '@/components/TitledList.vue';
|
||||||
import { get } from 'lodash-es';
|
import { get } from 'lodash-es';
|
||||||
import { getTriggerNodeServiceName } from '@/utils/nodeTypesUtils';
|
import { getTriggerNodeServiceName } from '@/utils/nodeTypesUtils';
|
||||||
import type { INodeUi, XYPosition } from '@/Interface';
|
import type { INodeUi, XYPosition } from '@/Interface';
|
||||||
import { debounceHelper } from '@/mixins/debounce';
|
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { useNDVStore } from '@/stores/ndv.store';
|
import { useNDVStore } from '@/stores/ndv.store';
|
||||||
|
@ -187,6 +186,7 @@ import { type ContextMenuTarget, useContextMenu } from '@/composables/useContext
|
||||||
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
||||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||||
import { usePinnedData } from '@/composables/usePinnedData';
|
import { usePinnedData } from '@/composables/usePinnedData';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Node',
|
name: 'Node',
|
||||||
|
@ -195,7 +195,7 @@ export default defineComponent({
|
||||||
FontAwesomeIcon,
|
FontAwesomeIcon,
|
||||||
NodeIcon,
|
NodeIcon,
|
||||||
},
|
},
|
||||||
mixins: [nodeBase, workflowHelpers, debounceHelper],
|
mixins: [nodeBase, workflowHelpers],
|
||||||
props: {
|
props: {
|
||||||
isProductionExecutionPreview: {
|
isProductionExecutionPreview: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -217,8 +217,9 @@ export default defineComponent({
|
||||||
const nodeHelpers = useNodeHelpers();
|
const nodeHelpers = useNodeHelpers();
|
||||||
const node = workflowsStore.getNodeByName(props.name);
|
const node = workflowsStore.getNodeByName(props.name);
|
||||||
const pinnedData = usePinnedData(node);
|
const pinnedData = usePinnedData(node);
|
||||||
|
const { callDebounced } = useDebounce();
|
||||||
|
|
||||||
return { contextMenu, externalHooks, nodeHelpers, pinnedData };
|
return { contextMenu, externalHooks, nodeHelpers, pinnedData, callDebounced };
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapStores(useNodeTypesStore, useNDVStore, useUIStore, useWorkflowsStore),
|
...mapStores(useNodeTypesStore, useNDVStore, useUIStore, useWorkflowsStore),
|
||||||
|
@ -679,7 +680,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
|
|
||||||
onClick(event: MouseEvent) {
|
onClick(event: MouseEvent) {
|
||||||
void this.callDebounced('onClickDebounced', { debounceTime: 50, trailing: true }, event);
|
void this.callDebounced(this.onClickDebounced, { debounceTime: 50, trailing: true }, event);
|
||||||
},
|
},
|
||||||
|
|
||||||
onClickDebounced(event: MouseEvent) {
|
onClickDebounced(event: MouseEvent) {
|
||||||
|
|
|
@ -508,7 +508,6 @@ import { isResourceLocatorValue } from '@/utils/typeGuards';
|
||||||
import { CUSTOM_API_CALL_KEY, HTML_NODE_TYPE, NODES_USING_CODE_NODE_EDITOR } from '@/constants';
|
import { CUSTOM_API_CALL_KEY, HTML_NODE_TYPE, NODES_USING_CODE_NODE_EDITOR } from '@/constants';
|
||||||
|
|
||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import { debounceHelper } from '@/mixins/debounce';
|
|
||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { useNDVStore } from '@/stores/ndv.store';
|
import { useNDVStore } from '@/stores/ndv.store';
|
||||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||||
|
@ -522,6 +521,7 @@ import { useI18n } from '@/composables/useI18n';
|
||||||
import type { N8nInput } from 'n8n-design-system';
|
import type { N8nInput } from 'n8n-design-system';
|
||||||
import { isCredentialOnlyNodeType } from '@/utils/credentialOnlyNodes';
|
import { isCredentialOnlyNodeType } from '@/utils/credentialOnlyNodes';
|
||||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
type Picker = { $emit: (arg0: string, arg1: Date) => void };
|
type Picker = { $emit: (arg0: string, arg1: Date) => void };
|
||||||
|
|
||||||
|
@ -540,7 +540,7 @@ export default defineComponent({
|
||||||
ResourceLocator,
|
ResourceLocator,
|
||||||
TextEdit,
|
TextEdit,
|
||||||
},
|
},
|
||||||
mixins: [workflowHelpers, debounceHelper],
|
mixins: [workflowHelpers],
|
||||||
props: {
|
props: {
|
||||||
additionalExpressionData: {
|
additionalExpressionData: {
|
||||||
type: Object as PropType<IDataObject>,
|
type: Object as PropType<IDataObject>,
|
||||||
|
@ -612,11 +612,13 @@ export default defineComponent({
|
||||||
const externalHooks = useExternalHooks();
|
const externalHooks = useExternalHooks();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const nodeHelpers = useNodeHelpers();
|
const nodeHelpers = useNodeHelpers();
|
||||||
|
const { callDebounced } = useDebounce();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
externalHooks,
|
externalHooks,
|
||||||
i18n,
|
i18n,
|
||||||
nodeHelpers,
|
nodeHelpers,
|
||||||
|
callDebounced,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -1243,7 +1245,7 @@ export default defineComponent({
|
||||||
this.$emit('textInput', parameterData);
|
this.$emit('textInput', parameterData);
|
||||||
},
|
},
|
||||||
valueChangedDebounced(value: NodeParameterValueType | {} | Date) {
|
valueChangedDebounced(value: NodeParameterValueType | {} | Date) {
|
||||||
void this.callDebounced('valueChanged', { debounceTime: 100 }, value);
|
void this.callDebounced(this.valueChanged, { debounceTime: 100 }, value);
|
||||||
},
|
},
|
||||||
onUpdateTextInput(value: string) {
|
onUpdateTextInput(value: string) {
|
||||||
this.valueChanged(value);
|
this.valueChanged(value);
|
||||||
|
|
|
@ -148,7 +148,6 @@ import type { IResourceLocatorReqParams, IResourceLocatorResultExpanded } from '
|
||||||
import DraggableTarget from '@/components/DraggableTarget.vue';
|
import DraggableTarget from '@/components/DraggableTarget.vue';
|
||||||
import ExpressionParameterInput from '@/components/ExpressionParameterInput.vue';
|
import ExpressionParameterInput from '@/components/ExpressionParameterInput.vue';
|
||||||
import ParameterIssues from '@/components/ParameterIssues.vue';
|
import ParameterIssues from '@/components/ParameterIssues.vue';
|
||||||
import { debounceHelper } from '@/mixins/debounce';
|
|
||||||
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
||||||
import { useRootStore } from '@/stores/n8nRoot.store';
|
import { useRootStore } from '@/stores/n8nRoot.store';
|
||||||
import { useNDVStore } from '@/stores/ndv.store';
|
import { useNDVStore } from '@/stores/ndv.store';
|
||||||
|
@ -174,6 +173,7 @@ import { mapStores } from 'pinia';
|
||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import ResourceLocatorDropdown from './ResourceLocatorDropdown.vue';
|
import ResourceLocatorDropdown from './ResourceLocatorDropdown.vue';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
interface IResourceLocatorQuery {
|
interface IResourceLocatorQuery {
|
||||||
results: INodeListSearchItems[];
|
results: INodeListSearchItems[];
|
||||||
|
@ -190,7 +190,7 @@ export default defineComponent({
|
||||||
ParameterIssues,
|
ParameterIssues,
|
||||||
ResourceLocatorDropdown,
|
ResourceLocatorDropdown,
|
||||||
},
|
},
|
||||||
mixins: [debounceHelper, workflowHelpers],
|
mixins: [workflowHelpers],
|
||||||
props: {
|
props: {
|
||||||
parameter: {
|
parameter: {
|
||||||
type: Object as PropType<INodeProperties>,
|
type: Object as PropType<INodeProperties>,
|
||||||
|
@ -267,6 +267,11 @@ export default defineComponent({
|
||||||
width: 0,
|
width: 0,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
setup() {
|
||||||
|
const { callDebounced } = useDebounce();
|
||||||
|
|
||||||
|
return { callDebounced };
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapStores(useNodeTypesStore, useNDVStore, useRootStore, useUIStore, useWorkflowsStore),
|
...mapStores(useNodeTypesStore, useNDVStore, useRootStore, useUIStore, useWorkflowsStore),
|
||||||
appName(): string {
|
appName(): string {
|
||||||
|
@ -636,7 +641,10 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
loadResourcesDebounced() {
|
loadResourcesDebounced() {
|
||||||
void this.callDebounced('loadResources', { debounceTime: 1000, trailing: true });
|
void this.callDebounced(this.loadResources, {
|
||||||
|
debounceTime: 1000,
|
||||||
|
trailing: true,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
setResponse(paramsKey: string, props: Partial<IResourceLocatorQuery>) {
|
setResponse(paramsKey: string, props: Partial<IResourceLocatorQuery>) {
|
||||||
this.cachedResponses = {
|
this.cachedResponses = {
|
||||||
|
|
|
@ -191,13 +191,13 @@ import type { IUser } from '@/Interface';
|
||||||
import PageViewLayout from '@/components/layouts/PageViewLayout.vue';
|
import PageViewLayout from '@/components/layouts/PageViewLayout.vue';
|
||||||
import PageViewLayoutList from '@/components/layouts/PageViewLayoutList.vue';
|
import PageViewLayoutList from '@/components/layouts/PageViewLayoutList.vue';
|
||||||
import { EnterpriseEditionFeature } from '@/constants';
|
import { EnterpriseEditionFeature } from '@/constants';
|
||||||
import { debounceHelper } from '@/mixins/debounce';
|
|
||||||
import ResourceOwnershipSelect from '@/components/forms/ResourceOwnershipSelect.ee.vue';
|
import ResourceOwnershipSelect from '@/components/forms/ResourceOwnershipSelect.ee.vue';
|
||||||
import ResourceFiltersDropdown from '@/components/forms/ResourceFiltersDropdown.vue';
|
import ResourceFiltersDropdown from '@/components/forms/ResourceFiltersDropdown.vue';
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
import { useUsersStore } from '@/stores/users.store';
|
import { useUsersStore } from '@/stores/users.store';
|
||||||
import type { N8nInput, DatatableColumn } from 'n8n-design-system';
|
import type { N8nInput, DatatableColumn } from 'n8n-design-system';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
export interface IResource {
|
export interface IResource {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -227,7 +227,6 @@ export default defineComponent({
|
||||||
ResourceOwnershipSelect,
|
ResourceOwnershipSelect,
|
||||||
ResourceFiltersDropdown,
|
ResourceFiltersDropdown,
|
||||||
},
|
},
|
||||||
mixins: [debounceHelper],
|
|
||||||
props: {
|
props: {
|
||||||
resourceKey: {
|
resourceKey: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -289,9 +288,11 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
const { callDebounced } = useDebounce();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
i18n,
|
i18n,
|
||||||
|
callDebounced,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -406,7 +407,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
'filtersModel.search'() {
|
'filtersModel.search'() {
|
||||||
void this.callDebounced(
|
void this.callDebounced(
|
||||||
'sendFiltersTelemetry',
|
this.sendFiltersTelemetry,
|
||||||
{ debounceTime: 1000, trailing: true },
|
{ debounceTime: 1000, trailing: true },
|
||||||
'search',
|
'search',
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { vi, describe, it, expect } from 'vitest';
|
import { vi, describe, it, expect } from 'vitest';
|
||||||
import { useDebounceHelper } from '../useDebounce';
|
import { useDebounce } from '../useDebounce';
|
||||||
import { render, screen } from '@testing-library/vue';
|
import { render, screen } from '@testing-library/vue';
|
||||||
|
|
||||||
describe('useDebounceHelper', () => {
|
describe('useDebounce()', () => {
|
||||||
const debounceTime = 500;
|
const debounceTime = 500;
|
||||||
|
|
||||||
const TestComponent = {
|
const TestComponent = {
|
||||||
|
@ -24,7 +24,7 @@ describe('useDebounceHelper', () => {
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
vitest.useFakeTimers();
|
vitest.useFakeTimers();
|
||||||
const { callDebounced } = useDebounceHelper();
|
const { callDebounced } = useDebounce();
|
||||||
return {
|
return {
|
||||||
callDebounced,
|
callDebounced,
|
||||||
debounceTime,
|
debounceTime,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { onBeforeUnmount, onMounted, ref } from 'vue';
|
import { onBeforeUnmount, onMounted, ref } from 'vue';
|
||||||
import { debounce } from 'lodash-es';
|
|
||||||
import { useClipboard as useClipboardCore } from '@vueuse/core';
|
import { useClipboard as useClipboardCore } from '@vueuse/core';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
type ClipboardEventFn = (data: string, event?: ClipboardEvent) => void;
|
type ClipboardEventFn = (data: string, event?: ClipboardEvent) => void;
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ export function useClipboard(
|
||||||
onPaste() {},
|
onPaste() {},
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
const { debounce } = useDebounce();
|
||||||
const { copy, copied, isSupported, text } = useClipboardCore();
|
const { copy, copied, isSupported, text } = useClipboardCore();
|
||||||
|
|
||||||
const ignoreClasses = ['el-messsage-box', 'ignore-key-press'];
|
const ignoreClasses = ['el-messsage-box', 'ignore-key-press'];
|
||||||
|
@ -46,7 +47,9 @@ export function useClipboard(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const debouncedOnPaste = debounce(onPaste, 1000, { leading: true });
|
const debouncedOnPaste = debounce(onPaste, {
|
||||||
|
debounceTime: 1000,
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize copy/paste elements and events
|
* Initialize copy/paste elements and events
|
||||||
|
|
|
@ -1,38 +1,54 @@
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { debounce } from 'lodash-es';
|
import { debounce as _debounce } from 'lodash-es';
|
||||||
|
|
||||||
type DebouncedFunction = (...args: unknown[]) => Promise<void> | void;
|
export interface DebounceOptions {
|
||||||
|
debounceTime: number;
|
||||||
|
trailing?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export function useDebounceHelper() {
|
export type DebouncedFunction<R = void> = (...args: unknown[]) => R;
|
||||||
|
|
||||||
|
export function useDebounce() {
|
||||||
// Create a ref for the WeakMap to store debounced functions.
|
// Create a ref for the WeakMap to store debounced functions.
|
||||||
const debouncedFunctions = ref(new WeakMap<DebouncedFunction, DebouncedFunction>());
|
const debounceCache = ref(new WeakMap<DebouncedFunction<unknown>, DebouncedFunction<unknown>>());
|
||||||
|
|
||||||
const callDebounced = async (
|
const debounce = <T extends DebouncedFunction<ReturnType<T>>>(
|
||||||
func: DebouncedFunction,
|
fn: T,
|
||||||
options: { debounceTime: number; trailing?: boolean },
|
options: DebounceOptions,
|
||||||
...inputParameters: unknown[]
|
): T => {
|
||||||
): Promise<void> => {
|
|
||||||
const { trailing, debounceTime } = options;
|
const { trailing, debounceTime } = options;
|
||||||
|
|
||||||
// Check if a debounced version of the function is already stored in the WeakMap.
|
// Check if a debounced version of the function is already stored in the WeakMap.
|
||||||
let debouncedFunc = debouncedFunctions.value.get(func);
|
let debouncedFn = debounceCache.value.get(fn);
|
||||||
|
|
||||||
// If a debounced version is not found, create one and store it in the WeakMap.
|
// If a debounced version is not found, create one and store it in the WeakMap.
|
||||||
if (debouncedFunc === undefined) {
|
if (debouncedFn === undefined) {
|
||||||
debouncedFunc = debounce(
|
debouncedFn = _debounce(
|
||||||
async (...args: unknown[]) => {
|
async (...args: unknown[]) => {
|
||||||
await func(...args);
|
return fn(...args);
|
||||||
},
|
},
|
||||||
debounceTime,
|
debounceTime,
|
||||||
trailing ? { trailing } : { leading: true },
|
trailing ? { trailing } : { leading: true },
|
||||||
);
|
);
|
||||||
debouncedFunctions.value.set(func, debouncedFunc);
|
|
||||||
|
debounceCache.value.set(fn, debouncedFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
await debouncedFunc(...inputParameters);
|
return debouncedFn as T;
|
||||||
|
};
|
||||||
|
|
||||||
|
const callDebounced = <T extends DebouncedFunction<ReturnType<T>>>(
|
||||||
|
fn: T,
|
||||||
|
options: DebounceOptions,
|
||||||
|
...inputParameters: Parameters<T>
|
||||||
|
): ReturnType<T> => {
|
||||||
|
const debouncedFn = debounce(fn, options);
|
||||||
|
|
||||||
|
return debouncedFn(...inputParameters) as ReturnType<T>;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
debounce,
|
||||||
callDebounced,
|
callDebounced,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@ import { useHistoryStore } from '@/stores/history.store';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
|
|
||||||
import { onMounted, onUnmounted, nextTick } from 'vue';
|
import { onMounted, onUnmounted, nextTick } from 'vue';
|
||||||
import { useDebounceHelper } from './useDebounce';
|
|
||||||
import { useDeviceSupport } from 'n8n-design-system/composables/useDeviceSupport';
|
import { useDeviceSupport } from 'n8n-design-system/composables/useDeviceSupport';
|
||||||
import { getNodeViewTab } from '@/utils/canvasUtils';
|
import { getNodeViewTab } from '@/utils/canvasUtils';
|
||||||
import type { Route } from 'vue-router';
|
import type { Route } from 'vue-router';
|
||||||
import { useTelemetry } from './useTelemetry';
|
import { useTelemetry } from './useTelemetry';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
const UNDO_REDO_DEBOUNCE_INTERVAL = 100;
|
const UNDO_REDO_DEBOUNCE_INTERVAL = 100;
|
||||||
const ELEMENT_UI_OVERLAY_SELECTOR = '.el-overlay';
|
const ELEMENT_UI_OVERLAY_SELECTOR = '.el-overlay';
|
||||||
|
@ -22,7 +22,7 @@ export function useHistoryHelper(activeRoute: Route) {
|
||||||
const historyStore = useHistoryStore();
|
const historyStore = useHistoryStore();
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
|
|
||||||
const { callDebounced } = useDebounceHelper();
|
const { callDebounced } = useDebounce();
|
||||||
const { isCtrlKeyPressed } = useDeviceSupport();
|
const { isCtrlKeyPressed } = useDeviceSupport();
|
||||||
|
|
||||||
const undo = async () =>
|
const undo = async () =>
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
import { debounce } from 'lodash-es';
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
|
|
||||||
export const debounceHelper = defineComponent({
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
debouncedFunctions: {} as Record<string, (...args: unknown[]) => Promise<void> | void>,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async callDebounced(
|
|
||||||
functionName: string,
|
|
||||||
options: { debounceTime: number; trailing?: boolean },
|
|
||||||
...inputParameters: unknown[]
|
|
||||||
): Promise<void> {
|
|
||||||
const { trailing, debounceTime } = options;
|
|
||||||
if (this.debouncedFunctions[functionName] === undefined) {
|
|
||||||
this.debouncedFunctions[functionName] = debounce(
|
|
||||||
async (...args: unknown[]) => {
|
|
||||||
// @ts-ignore
|
|
||||||
await this[functionName](...args);
|
|
||||||
},
|
|
||||||
debounceTime,
|
|
||||||
trailing ? { trailing } : { leading: true },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await this.debouncedFunctions[functionName](...inputParameters);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -8,7 +8,7 @@ import { useSettingsStore } from '@/stores/settings.store';
|
||||||
import type { FeatureFlags, IDataObject } from 'n8n-workflow';
|
import type { FeatureFlags, IDataObject } from 'n8n-workflow';
|
||||||
import { EXPERIMENTS_TO_TRACK, LOCAL_STORAGE_EXPERIMENT_OVERRIDES } from '@/constants';
|
import { EXPERIMENTS_TO_TRACK, LOCAL_STORAGE_EXPERIMENT_OVERRIDES } from '@/constants';
|
||||||
import { useTelemetryStore } from './telemetry.store';
|
import { useTelemetryStore } from './telemetry.store';
|
||||||
import { debounce } from 'lodash-es';
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
const EVENTS = {
|
const EVENTS = {
|
||||||
IS_PART_OF_EXPERIMENT: 'User is part of experiment',
|
IS_PART_OF_EXPERIMENT: 'User is part of experiment',
|
||||||
|
@ -21,6 +21,7 @@ export const usePostHog = defineStore('posthog', () => {
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const telemetryStore = useTelemetryStore();
|
const telemetryStore = useTelemetryStore();
|
||||||
const rootStore = useRootStore();
|
const rootStore = useRootStore();
|
||||||
|
const { debounce } = useDebounce();
|
||||||
|
|
||||||
const featureFlags: Ref<FeatureFlags | null> = ref(null);
|
const featureFlags: Ref<FeatureFlags | null> = ref(null);
|
||||||
const trackedDemoExp: Ref<FeatureFlags> = ref({});
|
const trackedDemoExp: Ref<FeatureFlags> = ref({});
|
||||||
|
@ -116,7 +117,9 @@ export const usePostHog = defineStore('posthog', () => {
|
||||||
const trackExperiments = (featFlags: FeatureFlags) => {
|
const trackExperiments = (featFlags: FeatureFlags) => {
|
||||||
EXPERIMENTS_TO_TRACK.forEach((name) => trackExperiment(featFlags, name));
|
EXPERIMENTS_TO_TRACK.forEach((name) => trackExperiment(featFlags, name));
|
||||||
};
|
};
|
||||||
const trackExperimentsDebounced = debounce(trackExperiments, 2000);
|
const trackExperimentsDebounced = debounce(trackExperiments, {
|
||||||
|
debounceTime: 2000,
|
||||||
|
});
|
||||||
|
|
||||||
const init = (evaluatedFeatureFlags?: FeatureFlags) => {
|
const init = (evaluatedFeatureFlags?: FeatureFlags) => {
|
||||||
if (!window.posthog) {
|
if (!window.posthog) {
|
||||||
|
|
|
@ -315,7 +315,6 @@ import type {
|
||||||
ToggleNodeCreatorOptions,
|
ToggleNodeCreatorOptions,
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
|
|
||||||
import { debounceHelper } from '@/mixins/debounce';
|
|
||||||
import type { Route, RawLocation } from 'vue-router';
|
import type { Route, RawLocation } from 'vue-router';
|
||||||
import { dataPinningEventBus, nodeViewEventBus } from '@/event-bus';
|
import { dataPinningEventBus, nodeViewEventBus } from '@/event-bus';
|
||||||
import { useCanvasStore } from '@/stores/canvas.store';
|
import { useCanvasStore } from '@/stores/canvas.store';
|
||||||
|
@ -377,6 +376,7 @@ import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||||
import { useClipboard } from '@/composables/useClipboard';
|
import { useClipboard } from '@/composables/useClipboard';
|
||||||
import { usePinnedData } from '@/composables/usePinnedData';
|
import { usePinnedData } from '@/composables/usePinnedData';
|
||||||
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
interface AddNodeOptions {
|
interface AddNodeOptions {
|
||||||
position?: XYPosition;
|
position?: XYPosition;
|
||||||
|
@ -404,7 +404,7 @@ export default defineComponent({
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
SetupWorkflowCredentialsButton,
|
SetupWorkflowCredentialsButton,
|
||||||
},
|
},
|
||||||
mixins: [moveNodeWorkflow, workflowHelpers, workflowRun, debounceHelper],
|
mixins: [moveNodeWorkflow, workflowHelpers, workflowRun],
|
||||||
async beforeRouteLeave(to, from, next) {
|
async beforeRouteLeave(to, from, next) {
|
||||||
if (
|
if (
|
||||||
getNodeViewTab(to) === MAIN_HEADER_TABS.EXECUTIONS ||
|
getNodeViewTab(to) === MAIN_HEADER_TABS.EXECUTIONS ||
|
||||||
|
@ -475,6 +475,7 @@ export default defineComponent({
|
||||||
const clipboard = useClipboard();
|
const clipboard = useClipboard();
|
||||||
const { activeNode } = storeToRefs(ndvStore);
|
const { activeNode } = storeToRefs(ndvStore);
|
||||||
const pinnedData = usePinnedData(activeNode);
|
const pinnedData = usePinnedData(activeNode);
|
||||||
|
const { callDebounced } = useDebounce();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
locale,
|
locale,
|
||||||
|
@ -484,6 +485,7 @@ export default defineComponent({
|
||||||
externalHooks,
|
externalHooks,
|
||||||
clipboard,
|
clipboard,
|
||||||
pinnedData,
|
pinnedData,
|
||||||
|
callDebounced,
|
||||||
...useCanvasMouseSelect(),
|
...useCanvasMouseSelect(),
|
||||||
...useGlobalLinkActions(),
|
...useGlobalLinkActions(),
|
||||||
...useTitleChange(),
|
...useTitleChange(),
|
||||||
|
@ -1422,7 +1424,7 @@ export default defineComponent({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void this.callDebounced('onSaveKeyboardShortcut', { debounceTime: 1000 }, e);
|
void this.callDebounced(this.onSaveKeyboardShortcut, { debounceTime: 1000 }, e);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1467,7 +1469,7 @@ export default defineComponent({
|
||||||
.filter((node) => !!node) as INode[];
|
.filter((node) => !!node) as INode[];
|
||||||
|
|
||||||
if (e.key === 'd' && noModifierKeys && !readOnly) {
|
if (e.key === 'd' && noModifierKeys && !readOnly) {
|
||||||
void this.callDebounced('toggleActivationNodes', { debounceTime: 350 }, selectedNodes);
|
void this.callDebounced(this.toggleActivationNodes, { debounceTime: 350 }, selectedNodes);
|
||||||
} else if (e.key === 'd' && ctrlModifier && !readOnly) {
|
} else if (e.key === 'd' && ctrlModifier && !readOnly) {
|
||||||
if (selectedNodes.length > 0) {
|
if (selectedNodes.length > 0) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -1482,7 +1484,7 @@ export default defineComponent({
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
void this.callDebounced('deleteNodes', { debounceTime: 500 }, selectedNodes);
|
void this.callDebounced(this.deleteNodes, { debounceTime: 500 }, selectedNodes);
|
||||||
} else if (e.key === 'Tab' && noModifierKeys && !readOnly) {
|
} else if (e.key === 'Tab' && noModifierKeys && !readOnly) {
|
||||||
this.onToggleNodeCreator({
|
this.onToggleNodeCreator({
|
||||||
source: NODE_CREATOR_OPEN_SOURCES.TAB,
|
source: NODE_CREATOR_OPEN_SOURCES.TAB,
|
||||||
|
@ -1500,7 +1502,7 @@ export default defineComponent({
|
||||||
const lastSelectedNode = this.lastSelectedNode;
|
const lastSelectedNode = this.lastSelectedNode;
|
||||||
if (lastSelectedNode !== null && lastSelectedNode.type !== STICKY_NODE_TYPE) {
|
if (lastSelectedNode !== null && lastSelectedNode.type !== STICKY_NODE_TYPE) {
|
||||||
void this.callDebounced(
|
void this.callDebounced(
|
||||||
'renameNodePrompt',
|
this.renameNodePrompt,
|
||||||
{ debounceTime: 1500 },
|
{ debounceTime: 1500 },
|
||||||
lastSelectedNode.name,
|
lastSelectedNode.name,
|
||||||
);
|
);
|
||||||
|
@ -1510,15 +1512,15 @@ export default defineComponent({
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
void this.callDebounced('selectAllNodes', { debounceTime: 1000 });
|
void this.callDebounced(this.selectAllNodes, { debounceTime: 1000 });
|
||||||
} else if (e.key === 'c' && ctrlModifier) {
|
} else if (e.key === 'c' && ctrlModifier) {
|
||||||
void this.callDebounced('copyNodes', { debounceTime: 1000 }, selectedNodes);
|
void this.callDebounced(this.copyNodes, { debounceTime: 1000 }, selectedNodes);
|
||||||
} else if (e.key === 'x' && ctrlModifier && !readOnly) {
|
} else if (e.key === 'x' && ctrlModifier && !readOnly) {
|
||||||
// Cut nodes
|
// Cut nodes
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
void this.callDebounced('cutNodes', { debounceTime: 1000 }, selectedNodes);
|
void this.callDebounced(this.cutNodes, { debounceTime: 1000 }, selectedNodes);
|
||||||
} else if (e.key === 'n' && ctrlAltModifier) {
|
} else if (e.key === 'n' && ctrlAltModifier) {
|
||||||
// Create a new workflow
|
// Create a new workflow
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
@ -1555,7 +1557,9 @@ export default defineComponent({
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
void this.callDebounced('selectDownstreamNodes', { debounceTime: 1000 });
|
void this.callDebounced(this.selectDownstreamNodes, {
|
||||||
|
debounceTime: 1000,
|
||||||
|
});
|
||||||
} else if (e.key === 'ArrowRight' && noModifierKeys) {
|
} else if (e.key === 'ArrowRight' && noModifierKeys) {
|
||||||
// Set child node active
|
// Set child node active
|
||||||
const lastSelectedNode = this.lastSelectedNode;
|
const lastSelectedNode = this.lastSelectedNode;
|
||||||
|
@ -1572,7 +1576,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
void this.callDebounced(
|
void this.callDebounced(
|
||||||
'nodeSelectedByName',
|
this.nodeSelectedByName,
|
||||||
{ debounceTime: 100 },
|
{ debounceTime: 100 },
|
||||||
connections.main[0][0].node,
|
connections.main[0][0].node,
|
||||||
false,
|
false,
|
||||||
|
@ -1583,7 +1587,9 @@ export default defineComponent({
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
void this.callDebounced('selectUpstreamNodes', { debounceTime: 1000 });
|
void this.callDebounced(this.selectUpstreamNodes, {
|
||||||
|
debounceTime: 1000,
|
||||||
|
});
|
||||||
} else if (e.key === 'ArrowLeft' && noModifierKeys) {
|
} else if (e.key === 'ArrowLeft' && noModifierKeys) {
|
||||||
// Set parent node active
|
// Set parent node active
|
||||||
const lastSelectedNode = this.lastSelectedNode;
|
const lastSelectedNode = this.lastSelectedNode;
|
||||||
|
@ -1604,7 +1610,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
void this.callDebounced(
|
void this.callDebounced(
|
||||||
'nodeSelectedByName',
|
this.nodeSelectedByName,
|
||||||
{ debounceTime: 100 },
|
{ debounceTime: 100 },
|
||||||
connections.main[0][0].node,
|
connections.main[0][0].node,
|
||||||
false,
|
false,
|
||||||
|
@ -1676,7 +1682,7 @@ export default defineComponent({
|
||||||
|
|
||||||
if (nextSelectNode !== null) {
|
if (nextSelectNode !== null) {
|
||||||
void this.callDebounced(
|
void this.callDebounced(
|
||||||
'nodeSelectedByName',
|
this.nodeSelectedByName,
|
||||||
{ debounceTime: 100 },
|
{ debounceTime: 100 },
|
||||||
nextSelectNode,
|
nextSelectNode,
|
||||||
false,
|
false,
|
||||||
|
@ -3033,7 +3039,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
onDragMove() {
|
onDragMove() {
|
||||||
const totalNodes = this.nodes.length;
|
const totalNodes = this.nodes.length;
|
||||||
void this.callDebounced('updateConnectionsOverlays', {
|
void this.callDebounced(this.updateConnectionsOverlays, {
|
||||||
debounceTime: totalNodes > 20 ? 200 : 0,
|
debounceTime: totalNodes > 20 ? 200 : 0,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -93,13 +93,13 @@ import type {
|
||||||
import type { IDataObject } from 'n8n-workflow';
|
import type { IDataObject } from 'n8n-workflow';
|
||||||
import { setPageTitle } from '@/utils/htmlUtils';
|
import { setPageTitle } from '@/utils/htmlUtils';
|
||||||
import { CREATOR_HUB_URL, VIEWS } from '@/constants';
|
import { CREATOR_HUB_URL, VIEWS } from '@/constants';
|
||||||
import { debounceHelper } from '@/mixins/debounce';
|
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
import { useUsersStore } from '@/stores/users.store';
|
import { useUsersStore } from '@/stores/users.store';
|
||||||
import { useTemplatesStore } from '@/stores/templates.store';
|
import { useTemplatesStore } from '@/stores/templates.store';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
import { usePostHog } from '@/stores/posthog.store';
|
import { usePostHog } from '@/stores/posthog.store';
|
||||||
|
import { useDebounce } from '@/composables/useDebounce';
|
||||||
|
|
||||||
interface ISearchEvent {
|
interface ISearchEvent {
|
||||||
search_string: string;
|
search_string: string;
|
||||||
|
@ -117,9 +117,11 @@ export default defineComponent({
|
||||||
TemplateList,
|
TemplateList,
|
||||||
TemplatesView,
|
TemplatesView,
|
||||||
},
|
},
|
||||||
mixins: [debounceHelper],
|
|
||||||
setup() {
|
setup() {
|
||||||
|
const { callDebounced } = useDebounce();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
callDebounced,
|
||||||
...useToast(),
|
...useToast(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -263,7 +265,10 @@ export default defineComponent({
|
||||||
this.loadingWorkflows = true;
|
this.loadingWorkflows = true;
|
||||||
this.loadingCollections = true;
|
this.loadingCollections = true;
|
||||||
this.search = search;
|
this.search = search;
|
||||||
void this.callDebounced('updateSearch', { debounceTime: 500, trailing: true });
|
void this.callDebounced(this.updateSearch, {
|
||||||
|
debounceTime: 500,
|
||||||
|
trailing: true,
|
||||||
|
});
|
||||||
|
|
||||||
if (search.length === 0) {
|
if (search.length === 0) {
|
||||||
this.trackSearch();
|
this.trackSearch();
|
||||||
|
|
Loading…
Reference in a new issue