feat: Replace this.$refs.refName as Vue with InstanceType<T> (no-changelog) (#6050)

* refactor: use InstanceType<T> for all this.$refs types

* refactor: update refs type in N8nSelect

* fix: remove inputRef non-null assertion

Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>

* fix: remove non-null assertion

---------

Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>
This commit is contained in:
Alex Grozav 2023-04-21 16:59:04 +03:00 committed by GitHub
parent 19f540ecf9
commit 54f99a7d0d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 427 additions and 318 deletions

View file

@ -13,6 +13,8 @@ const classToTypeMap = {
'el-picker-panel__link-btn': 'secondary',
};
type ButtonRef = InstanceType<typeof N8nButton>;
export default defineComponent({
components: {
N8nButton,
@ -32,7 +34,7 @@ export default defineComponent({
}
Object.entries(classToTypeMap).forEach(([className, mappedType]) => {
if (this.$refs.button && (this.$refs.button as Vue).$el.classList.contains(className)) {
if ((this.$refs.button as ButtonRef)?.$el.classList.contains(className)) {
type = mappedType;
}
});

View file

@ -27,6 +27,8 @@
import { Input as ElInput } from 'element-ui';
import { defineComponent } from 'vue';
type InputRef = InstanceType<typeof ElInput>;
export default defineComponent({
name: 'n8n-input',
components: {
@ -92,7 +94,7 @@ export default defineComponent({
},
methods: {
focus() {
const innerInput = this.$refs.innerInput as Vue | undefined;
const innerInput = this.$refs.innerInput as InputRef | undefined;
if (!innerInput) return;
@ -105,7 +107,7 @@ export default defineComponent({
inputElement.focus();
},
blur() {
const innerInput = this.$refs.innerInput as Vue | undefined;
const innerInput = this.$refs.innerInput as InputRef | undefined;
if (!innerInput) return;
@ -118,7 +120,7 @@ export default defineComponent({
inputElement.blur();
},
select() {
const innerInput = this.$refs.innerInput as Vue | undefined;
const innerInput = this.$refs.innerInput as InputRef | undefined;
if (!innerInput) return;

View file

@ -35,6 +35,8 @@
import { Select as ElSelect } from 'element-ui';
import { defineComponent } from 'vue';
type InnerSelectRef = InstanceType<typeof ElSelect>;
export interface IProps {
size?: string;
limitPopperWidth?: string;
@ -117,23 +119,23 @@ export default defineComponent({
},
methods: {
focus() {
const select = this.$refs.innerSelect as (Vue & HTMLElement) | undefined;
if (select) {
select.focus();
const selectRef = this.$refs.innerSelect as InnerSelectRef | undefined;
if (selectRef) {
selectRef.focus();
}
},
blur() {
const select = this.$refs.innerSelect as (Vue & HTMLElement) | undefined;
if (select) {
select.blur();
const selectRef = this.$refs.innerSelect as InnerSelectRef | undefined;
if (selectRef) {
selectRef.blur();
}
},
focusOnInput() {
const select = this.$refs.innerSelect as (Vue & HTMLElement) | undefined;
if (select) {
const input = select.$refs.input as (Vue & HTMLElement) | undefined;
if (input) {
input.focus();
const selectRef = this.$refs.innerSelect as InnerSelectRef | undefined;
if (selectRef) {
const inputRef = selectRef.$refs.input as HTMLInputElement | undefined;
if (inputRef) {
inputRef.focus();
}
}
},

View file

@ -0,0 +1,49 @@
export { default as N8nActionBox } from './N8nActionBox';
export { default as N8nActionDropdown } from './N8nActionDropdown';
export { default as N8nActionToggle } from './N8nActionToggle';
export { default as N8nAlert } from './N8nAlert';
export { default as N8nAvatar } from './N8nAvatar';
export { default as N8nBadge } from './N8nBadge';
export { default as N8nBlockUi } from './N8nBlockUi';
export { default as N8nButton } from './N8nButton';
export { N8nElButton } from './N8nButton/overrides';
export { default as N8nCallout } from './N8nCallout';
export { default as N8nCard } from './N8nCard';
export { default as N8nDatatable } from './N8nDatatable';
export { default as N8nFormBox } from './N8nFormBox';
export { default as N8nFormInputs } from './N8nFormInputs';
export { default as N8nFormInput } from './N8nFormInput';
export { default as N8nHeading } from './N8nHeading';
export { default as N8nIcon } from './N8nIcon';
export { default as N8nIconButton } from './N8nIconButton';
export { default as N8nInfoAccordion } from './N8nInfoAccordion';
export { default as N8nInfoTip } from './N8nInfoTip';
export { default as N8nInput } from './N8nInput';
export { default as N8nInputLabel } from './N8nInputLabel';
export { default as N8nInputNumber } from './N8nInputNumber';
export { default as N8nLink } from './N8nLink';
export { default as N8nLoading } from './N8nLoading';
export { default as N8nMarkdown } from './N8nMarkdown';
export { default as N8nMenu } from './N8nMenu';
export { default as N8nMenuItem } from './N8nMenuItem';
export { default as N8nNodeCreatorNode } from './N8nNodeCreatorNode';
export { default as N8nNodeIcon } from './N8nNodeIcon';
export { default as N8nNotice } from './N8nNotice';
export { default as N8nOption } from './N8nOption';
export { default as N8nPopover } from './N8nPopover';
export { default as N8nPulse } from './N8nPulse';
export { default as N8nRadioButtons } from './N8nRadioButtons';
export { default as N8nSelect } from './N8nSelect';
export { default as N8nSpinner } from './N8nSpinner';
export { default as N8nSticky } from './N8nSticky';
export { default as N8nTabs } from './N8nTabs';
export { default as N8nTag } from './N8nTag';
export { default as N8nTags } from './N8nTags';
export { default as N8nText } from './N8nText';
export { default as N8nTooltip } from './N8nTooltip';
export { default as N8nTree } from './N8nTree';
export { default as N8nUserInfo } from './N8nUserInfo';
export { default as N8nUserSelect } from './N8nUserSelect';
export { default as N8nUsersList } from './N8nUsersList';
export { default as N8nResizeWrapper } from './N8nResizeWrapper';
export { default as N8nRecycleScroller } from './N8nRecycleScroller';

View file

@ -1,6 +1,7 @@
import * as locale from './locale';
import designSystemComponents from './plugins/n8nComponents';
export * from './components';
export * from './plugin';
export * from './types';
export * from './utils';
export { locale, designSystemComponents };
export { locale };

View file

@ -0,0 +1,107 @@
/* eslint-disable @typescript-eslint/naming-convention */
import type { PluginObject } from 'vue';
import {
N8nActionBox,
N8nActionDropdown,
N8nActionToggle,
N8nAlert,
N8nAvatar,
N8nBadge,
N8nBlockUi,
N8nButton,
N8nElButton,
N8nCallout,
N8nCard,
N8nDatatable,
N8nFormBox,
N8nFormInputs,
N8nFormInput,
N8nHeading,
N8nIcon,
N8nIconButton,
N8nInfoAccordion,
N8nInfoTip,
N8nInput,
N8nInputLabel,
N8nInputNumber,
N8nLink,
N8nLoading,
N8nMarkdown,
N8nMenu,
N8nMenuItem,
N8nNodeCreatorNode,
N8nNodeIcon,
N8nNotice,
N8nOption,
N8nPopover,
N8nPulse,
N8nRadioButtons,
N8nSelect,
N8nSpinner,
N8nSticky,
N8nTabs,
N8nTag,
N8nTags,
N8nText,
N8nTooltip,
N8nTree,
N8nUserInfo,
N8nUserSelect,
N8nUsersList,
N8nResizeWrapper,
N8nRecycleScroller,
} from './components';
export const N8nPlugin: PluginObject<{}> = {
install: (app) => {
app.component('n8n-info-accordion', N8nInfoAccordion);
app.component('n8n-action-box', N8nActionBox);
app.component('n8n-action-dropdown', N8nActionDropdown);
app.component('n8n-action-toggle', N8nActionToggle);
app.component('n8n-alert', N8nAlert);
app.component('n8n-avatar', N8nAvatar);
app.component('n8n-badge', N8nBadge);
app.component('n8n-block-ui', N8nBlockUi);
app.component('n8n-button', N8nButton);
app.component('el-button', N8nElButton);
app.component('n8n-callout', N8nCallout);
app.component('n8n-card', N8nCard);
app.component('n8n-datatable', N8nDatatable);
app.component('n8n-form-box', N8nFormBox);
app.component('n8n-form-inputs', N8nFormInputs);
app.component('n8n-form-input', N8nFormInput);
app.component('n8n-icon', N8nIcon);
app.component('n8n-icon-button', N8nIconButton);
app.component('n8n-info-tip', N8nInfoTip);
app.component('n8n-input', N8nInput);
app.component('n8n-input-label', N8nInputLabel);
app.component('n8n-input-number', N8nInputNumber);
app.component('n8n-loading', N8nLoading);
app.component('n8n-heading', N8nHeading);
app.component('n8n-link', N8nLink);
app.component('n8n-markdown', N8nMarkdown);
app.component('n8n-menu', N8nMenu);
app.component('n8n-menu-item', N8nMenuItem);
app.component('n8n-node-creator-node', N8nNodeCreatorNode);
app.component('n8n-node-icon', N8nNodeIcon);
app.component('n8n-notice', N8nNotice);
app.component('n8n-option', N8nOption);
app.component('n8n-popover', N8nPopover);
app.component('n8n-pulse', N8nPulse);
app.component('n8n-select', N8nSelect);
app.component('n8n-spinner', N8nSpinner);
app.component('n8n-sticky', N8nSticky);
app.component('n8n-radio-buttons', N8nRadioButtons);
app.component('n8n-tags', N8nTags);
app.component('n8n-tabs', N8nTabs);
app.component('n8n-tag', N8nTag);
app.component('n8n-text', N8nText);
app.component('n8n-tooltip', N8nTooltip);
app.component('n8n-user-info', N8nUserInfo);
app.component('n8n-tree', N8nTree);
app.component('n8n-users-list', N8nUsersList);
app.component('n8n-user-select', N8nUserSelect);
app.component('n8n-resize-wrapper', N8nResizeWrapper);
app.component('n8n-recycle-scroller', N8nRecycleScroller);
},
};

View file

@ -1,106 +0,0 @@
import type { PluginObject } from 'vue';
import N8nActionBox from '../components/N8nActionBox';
import N8nActionDropdown from '../components/N8nActionDropdown';
import N8nActionToggle from '../components/N8nActionToggle';
import N8nAlert from '../components/N8nAlert';
import N8nAvatar from '../components/N8nAvatar';
import N8nBadge from '../components/N8nBadge';
import N8nBlockUi from '../components/N8nBlockUi';
import N8nButton from '../components/N8nButton';
import { N8nElButton } from '../components/N8nButton/overrides';
import N8nCallout from '../components/N8nCallout';
import N8nCard from '../components/N8nCard';
import N8nDatatable from '../components/N8nDatatable';
import N8nFormBox from '../components/N8nFormBox';
import N8nFormInputs from '../components/N8nFormInputs';
import N8nFormInput from '../components/N8nFormInput';
import N8nHeading from '../components/N8nHeading';
import N8nIcon from '../components/N8nIcon';
import N8nIconButton from '../components/N8nIconButton';
import N8nInfoAccordion from '../components/N8nInfoAccordion';
import N8nInfoTip from '../components/N8nInfoTip';
import { default as N8nInput } from '../components/N8nInput';
import N8nInputLabel from '../components/N8nInputLabel';
import N8nInputNumber from '../components/N8nInputNumber';
import N8nLink from '../components/N8nLink';
import N8nLoading from '../components/N8nLoading';
import N8nMarkdown from '../components/N8nMarkdown';
import N8nMenu from '../components/N8nMenu';
import N8nMenuItem from '../components/N8nMenuItem';
import N8nNodeCreatorNode from '../components/N8nNodeCreatorNode';
import N8nNodeIcon from '../components/N8nNodeIcon';
import N8nNotice from '../components/N8nNotice';
import N8nOption from '../components/N8nOption';
import N8nPopover from '../components/N8nPopover';
import N8nPulse from '../components/N8nPulse';
import N8nRadioButtons from '../components/N8nRadioButtons';
import N8nSelect from '../components/N8nSelect';
import N8nSpinner from '../components/N8nSpinner';
import N8nSticky from '../components/N8nSticky';
import N8nTabs from '../components/N8nTabs';
import N8nTag from '../components/N8nTag';
import N8nTags from '../components/N8nTags';
import N8nText from '../components/N8nText';
import N8nTooltip from '../components/N8nTooltip';
import N8nTree from '../components/N8nTree';
import N8nUserInfo from '../components/N8nUserInfo';
import N8nUserSelect from '../components/N8nUserSelect';
import N8nUsersList from '../components/N8nUsersList';
import N8nResizeWrapper from '../components/N8nResizeWrapper';
import N8nRecycleScroller from '../components/N8nRecycleScroller';
const n8nComponentsPlugin: PluginObject<{}> = {
install: (app) => {
app.component('n8n-info-accordion', N8nInfoAccordion);
app.component('n8n-action-box', N8nActionBox);
app.component('n8n-action-dropdown', N8nActionDropdown);
app.component('n8n-action-toggle', N8nActionToggle);
app.component('n8n-alert', N8nAlert);
app.component('n8n-avatar', N8nAvatar);
app.component('n8n-badge', N8nBadge);
app.component('n8n-block-ui', N8nBlockUi);
app.component('n8n-button', N8nButton);
app.component('el-button', N8nElButton);
app.component('n8n-callout', N8nCallout);
app.component('n8n-card', N8nCard);
app.component('n8n-datatable', N8nDatatable);
app.component('n8n-form-box', N8nFormBox);
app.component('n8n-form-inputs', N8nFormInputs);
app.component('n8n-form-input', N8nFormInput);
app.component('n8n-icon', N8nIcon);
app.component('n8n-icon-button', N8nIconButton);
app.component('n8n-info-tip', N8nInfoTip);
app.component('n8n-input', N8nInput);
app.component('n8n-input-label', N8nInputLabel);
app.component('n8n-input-number', N8nInputNumber);
app.component('n8n-loading', N8nLoading);
app.component('n8n-heading', N8nHeading);
app.component('n8n-link', N8nLink);
app.component('n8n-markdown', N8nMarkdown);
app.component('n8n-menu', N8nMenu);
app.component('n8n-menu-item', N8nMenuItem);
app.component('n8n-node-creator-node', N8nNodeCreatorNode);
app.component('n8n-node-icon', N8nNodeIcon);
app.component('n8n-notice', N8nNotice);
app.component('n8n-option', N8nOption);
app.component('n8n-popover', N8nPopover);
app.component('n8n-pulse', N8nPulse);
app.component('n8n-select', N8nSelect);
app.component('n8n-spinner', N8nSpinner);
app.component('n8n-sticky', N8nSticky);
app.component('n8n-radio-buttons', N8nRadioButtons);
app.component('n8n-tags', N8nTags);
app.component('n8n-tabs', N8nTabs);
app.component('n8n-tag', N8nTag);
app.component('n8n-text', N8nText);
app.component('n8n-tooltip', N8nTooltip);
app.component('n8n-user-info', N8nUserInfo);
app.component('n8n-tree', N8nTree);
app.component('n8n-users-list', N8nUsersList);
app.component('n8n-user-select', N8nUserSelect);
app.component('n8n-resize-wrapper', N8nResizeWrapper);
app.component('n8n-recycle-scroller', N8nRecycleScroller);
},
};
export default n8nComponentsPlugin;

View file

@ -95,15 +95,15 @@ export default mixins(linterExtension, completerExtension, workflowHelpers).exte
methods: {
onMouseOver(event: MouseEvent) {
const fromElement = event.relatedTarget as HTMLElement;
const ref = this.$refs.codeNodeEditorContainer as HTMLDivElement;
const ref = this.$refs.codeNodeEditorContainer as HTMLDivElement | undefined;
if (!ref.contains(fromElement)) this.isEditorHovered = true;
if (!ref?.contains(fromElement)) this.isEditorHovered = true;
},
onMouseOut(event: MouseEvent) {
const fromElement = event.relatedTarget as HTMLElement;
const ref = this.$refs.codeNodeEditorContainer as HTMLDivElement;
const ref = this.$refs.codeNodeEditorContainer as HTMLDivElement | undefined;
if (!ref.contains(fromElement)) this.isEditorHovered = false;
if (!ref?.contains(fromElement)) this.isEditorHovered = false;
},
onAskAiButtonClick() {
this.$telemetry.track('User clicked ask ai button', { source: 'code' });

View file

@ -35,6 +35,8 @@ import VueAgile from 'vue-agile';
import { genericHelpers } from '@/mixins/genericHelpers';
import mixins from 'vue-typed-mixins';
type SliderRef = InstanceType<typeof VueAgile>;
export default mixins(genericHelpers).extend({
name: 'CollectionsCarousel',
props: {
@ -97,22 +99,23 @@ export default mixins(genericHelpers).extend({
},
mounted() {
this.$nextTick(() => {
const slider = this.$refs.slider;
if (!slider) {
const sliderRef = this.$refs.slider as SliderRef | undefined;
if (!sliderRef) {
return;
}
// @ts-ignore
this.listElement = slider.$el.querySelector('.agile__list');
this.listElement = sliderRef.$el.querySelector('.agile__list');
if (this.listElement) {
this.listElement.addEventListener('scroll', this.updateCarouselScroll);
}
});
},
beforeDestroy() {
if (this.$refs.slider) {
// @ts-ignore
this.$refs.slider.destroy();
const sliderRef = this.$refs.slider as SliderRef | undefined;
if (sliderRef) {
sliderRef.destroy();
}
window.removeEventListener('scroll', this.updateCarouselScroll);
},
});

View file

@ -672,18 +672,18 @@ export default mixins(showMessage, nodeHelpers).extend({
scrollToTop() {
setTimeout(() => {
const content = this.$refs.content as Element;
if (content) {
content.scrollTop = 0;
const contentRef = this.$refs.content as Element | undefined;
if (contentRef) {
contentRef.scrollTop = 0;
}
}, 0);
},
scrollToBottom() {
setTimeout(() => {
const content = this.$refs.content as Element;
if (content) {
content.scrollTop = content.scrollHeight;
const contentRef = this.$refs.content as Element | undefined;
if (contentRef) {
contentRef.scrollTop = contentRef.scrollHeight;
}
}, 0);
},

View file

@ -61,6 +61,9 @@ import ScopesNotice from '@/components/ScopesNotice.vue';
import NodeCredentials from '@/components/NodeCredentials.vue';
import { mapStores } from 'pinia';
import { useCredentialsStore } from '@/stores/credentials';
import { N8nSelect } from 'n8n-design-system';
type N8nSelectRef = InstanceType<typeof N8nSelect>;
export default Vue.extend({
name: 'CredentialsSelect',
@ -93,9 +96,9 @@ export default Vue.extend({
},
methods: {
focus() {
const select = this.$refs.innerSelect as (Vue & HTMLElement) | undefined;
if (select) {
select.focus();
const selectRef = this.$refs.innerSelect as N8nSelectRef | undefined;
if (selectRef) {
selectRef.focus();
}
},
/**

View file

@ -80,9 +80,9 @@ export default mixins(externalHooks).extend({
this.loading = false;
setTimeout(() => {
const element = this.$refs.select as HTMLSelectElement;
if (element) {
element.focus();
const elementRef = this.$refs.select as HTMLSelectElement | undefined;
if (elementRef) {
elementRef.focus();
}
}, 0);
},

View file

@ -55,10 +55,10 @@ export default Vue.extend({
},
methods: {
onMouseMove(e: MouseEvent) {
const target = this.$refs.target as HTMLElement;
const targetRef = this.$refs.target as HTMLElement | undefined;
if (target && this.isDragging) {
const dim = target.getBoundingClientRect();
if (targetRef && this.isDragging) {
const dim = targetRef.getBoundingClientRect();
this.hovering =
e.clientX >= dim.left &&

View file

@ -115,9 +115,9 @@ export default mixins(showMessage, workflowHelpers, restApi).extend({
this.dropdownBus.emit('focus');
},
focusOnNameInput() {
const input = this.$refs.nameInput as HTMLElement;
if (input && input.focus) {
input.focus();
const inputRef = this.$refs.nameInput as HTMLElement | undefined;
if (inputRef && inputRef.focus) {
inputRef.focus();
}
},
onTagsBlur() {

View file

@ -137,6 +137,8 @@ import { useUIStore } from '@/stores/ui';
import { Dropdown as ElDropdown } from 'element-ui';
import { IAbstractEventMessage } from 'n8n-workflow';
type RetryDropdownRef = InstanceType<typeof ElDropdown> & { hide: () => void };
export default mixins(restApi, showMessage, executionHelpers).extend({
name: 'execution-preview',
components: {
@ -182,9 +184,9 @@ export default mixins(restApi, showMessage, executionHelpers).extend({
},
onRetryButtonBlur(event: FocusEvent): void {
// Hide dropdown when clicking outside of current document
const retryDropdown = this.$refs.retryDropdown as (Vue & { hide: () => void }) | undefined;
if (retryDropdown && event.relatedTarget === null) {
retryDropdown.hide();
const retryDropdownRef = this.$refs.retryDropdown as RetryDropdownRef | undefined;
if (retryDropdownRef && event.relatedTarget === null) {
retryDropdownRef.hide();
}
},
},

View file

@ -77,6 +77,8 @@ import { useUIStore } from '@/stores/ui';
import { useWorkflowsStore } from '@/stores/workflows';
import { ExecutionFilterType } from '@/Interface';
type ExecutionCardRef = InstanceType<typeof ExecutionCard>;
export default Vue.extend({
name: 'executions-sidebar',
components: {
@ -144,10 +146,11 @@ export default Vue.extend({
methods: {
loadMore(limit = 20): void {
if (!this.loading) {
const executionsList = this.$refs.executionList as HTMLElement;
if (executionsList) {
const executionsListRef = this.$refs.executionList as HTMLElement | undefined;
if (executionsListRef) {
const diff =
executionsList.offsetHeight - (executionsList.scrollHeight - executionsList.scrollTop);
executionsListRef.offsetHeight -
(executionsListRef.scrollHeight - executionsListRef.scrollTop);
if (diff > -10 && diff < 10) {
this.$emit('loadMore', limit);
}
@ -178,16 +181,16 @@ export default Vue.extend({
}
},
checkListSize(): void {
const sidebarContainer = this.$refs.container as HTMLElement;
const currentExecutionCard = this.$refs[
const sidebarContainerRef = this.$refs.container as HTMLElement | undefined;
const currentExecutionCardRefs = this.$refs[
`execution-${this.workflowsStore.activeWorkflowExecution?.id}`
] as Vue[];
] as ExecutionCardRef[] | undefined;
// Find out how many execution card can fit into list
// and load more if needed
if (sidebarContainer && currentExecutionCard?.length) {
const cardElement = currentExecutionCard[0].$el as HTMLElement;
const listCapacity = Math.ceil(sidebarContainer.clientHeight / cardElement.clientHeight);
if (sidebarContainerRef && currentExecutionCardRefs?.length) {
const cardElement = currentExecutionCardRefs[0].$el as HTMLElement;
const listCapacity = Math.ceil(sidebarContainerRef.clientHeight / cardElement.clientHeight);
if (listCapacity > this.executions.length) {
this.$emit('loadMore', listCapacity - this.executions.length);
@ -195,21 +198,21 @@ export default Vue.extend({
}
},
scrollToActiveCard(): void {
const executionsList = this.$refs.executionList as HTMLElement;
const currentExecutionCard = this.$refs[
const executionsListRef = this.$refs.executionList as HTMLElement | undefined;
const currentExecutionCardRefs = this.$refs[
`execution-${this.workflowsStore.activeWorkflowExecution?.id}`
] as Vue[];
] as ExecutionCardRef[] | undefined;
if (
executionsList &&
currentExecutionCard?.length &&
executionsListRef &&
currentExecutionCardRefs?.length &&
this.workflowsStore.activeWorkflowExecution
) {
const cardElement = currentExecutionCard[0].$el as HTMLElement;
const cardElement = currentExecutionCardRefs[0].$el as HTMLElement;
const cardRect = cardElement.getBoundingClientRect();
const LIST_HEADER_OFFSET = 200;
if (cardRect.top > executionsList.offsetHeight) {
executionsList.scrollTo({ top: cardRect.top - LIST_HEADER_OFFSET });
if (cardRect.top > executionsListRef.offsetHeight) {
executionsListRef.scrollTo({ top: cardRect.top - LIST_HEADER_OFFSET });
}
}
},

View file

@ -79,6 +79,8 @@ import { EXPRESSIONS_DOCS_URL } from '@/constants';
import type { Segment } from '@/types/expressions';
import type { TargetItem } from '@/Interface';
type InlineExpressionEditorInputRef = InstanceType<typeof InlineExpressionEditorInput>;
export default Vue.extend({
name: 'ExpressionParameterInput',
components: {
@ -127,9 +129,10 @@ export default Vue.extend({
},
methods: {
focus() {
const inlineInput = this.$refs.inlineInput as (Vue & HTMLElement) | undefined;
if (inlineInput?.$el) inlineInput.focus();
const inlineInputRef = this.$refs.inlineInput as InlineExpressionEditorInputRef | undefined;
if (inlineInputRef?.$el) {
inlineInputRef.focus();
}
},
onFocus() {
this.isFocused = true;

View file

@ -169,11 +169,12 @@ export default mixins(expressionManager).extend({
methods: {
root() {
const root = this.$refs.htmlEditor as HTMLDivElement | undefined;
const rootRef = this.$refs.htmlEditor as HTMLDivElement | undefined;
if (!rootRef) {
throw new Error('Expected div with ref "htmlEditor"');
}
if (!root) throw new Error('Expected div with ref "htmlEditor"');
return root;
return rootRef;
},
isMissingHtmlTags() {

View file

@ -65,9 +65,9 @@ export default mixins(showMessage).extend({
this.isNameEdit = true;
setTimeout(() => {
const input = this.$refs.nameInput as HTMLInputElement;
if (input) {
input.focus();
const inputRef = this.$refs.nameInput as HTMLInputElement | undefined;
if (inputRef) {
inputRef.focus();
}
}, 0);
},

View file

@ -424,9 +424,9 @@ export default mixins(workflowHelpers).extend({
this.$root.$emit('importWorkflowData', { data: workflowData });
};
const input = this.$refs.importFile as HTMLInputElement;
if (input !== null && input.files !== null && input.files.length !== 0) {
reader.readAsText(input!.files[0]!);
const inputRef = this.$refs.importFile as HTMLInputElement | undefined;
if (inputRef?.files && inputRef.files.length !== 0) {
reader.readAsText(inputRef.files[0]);
}
},
async onWorkflowMenuSelect(action: string): Promise<void> {

View file

@ -70,9 +70,9 @@ export default Vue.extend({
this.newName = this.value;
this.editName = true;
this.$nextTick(() => {
const input = this.$refs.input;
if (input) {
(input as HTMLInputElement).focus();
const inputRef = this.$refs.input as HTMLInputElement | undefined;
if (inputRef) {
inputRef.focus();
}
});
},

View file

@ -111,7 +111,7 @@ import { useWorkflowsStore } from '@/stores/workflows';
import { useNDVStore } from '@/stores/ndv';
import { useNodeTypesStore } from '@/stores/nodeTypes';
type RunDataRef = Vue & { enterEditMode: (args: EnterEditModeArgs) => void };
type RunDataRef = InstanceType<typeof RunData>;
export default mixins(pinData).extend({
name: 'OutputPanel',
@ -242,8 +242,9 @@ export default mixins(pinData).extend({
},
methods: {
insertTestData() {
if (this.$refs.runData) {
(this.$refs.runData as RunDataRef).enterEditMode({
const runDataRef = this.$refs.runData as RunDataRef | undefined;
if (runDataRef) {
runDataRef.enterEditMode({
origin: 'insertTestDataLink',
});

View file

@ -375,6 +375,8 @@ import { useNodeTypesStore } from '@/stores/nodeTypes';
import { useCredentialsStore } from '@/stores/credentials';
import { htmlEditorEventBus } from '@/event-bus';
type ResourceLocatorRef = InstanceType<typeof ResourceLocator>;
export default mixins(
externalHooks,
nodeHelpers,
@ -1099,10 +1101,9 @@ export default mixins(
}
} else if (command === 'refreshOptions') {
if (this.isResourceLocatorParameter) {
const resourceLocator = this.$refs.resourceLocator;
if (resourceLocator) {
(resourceLocator as Vue).$emit('refreshList');
}
const resourceLocatorRef = this.$refs.resourceLocator as ResourceLocatorRef | undefined;
resourceLocatorRef?.$emit('refreshList');
}
this.loadRemoteParameterOptions();
} else if (command === 'formatHtml') {

View file

@ -65,6 +65,8 @@ import { INodeParameterResourceLocator, INodeProperties, IParameterLabel } from
import { mapStores } from 'pinia';
import { useWorkflowsStore } from '@/stores/workflows';
type ParamRef = InstanceType<typeof ParameterInputWrapper>;
export default Vue.extend({
name: 'parameter-input-expanded',
components: {
@ -145,7 +147,7 @@ export default Vue.extend({
},
optionSelected(command: string) {
if (this.$refs.param) {
(this.$refs.param as Vue).$emit('optionSelected', command);
(this.$refs.param as ParamRef).$emit('optionSelected', command);
}
},
valueChanged(parameterData: IUpdateInformation) {

View file

@ -92,6 +92,8 @@ import { useSegment } from '@/stores/segment';
import { externalHooks } from '@/mixins/externalHooks';
import { getMappedResult } from '../utils/mappingUtils';
type ParamterInputWrapperRef = InstanceType<typeof ParameterInputWrapper>;
const DISPLAY_MODES_WITH_DATA_MAPPING = ['table', 'json', 'schema'];
export default mixins(showMessage, externalHooks).extend({
@ -219,18 +221,17 @@ export default mixins(showMessage, externalHooks).extend({
this.menuExpanded = expanded;
},
optionSelected(command: string) {
if (this.$refs.param) {
(this.$refs.param as Vue).$emit('optionSelected', command);
}
const paramRef = this.$refs.param as ParamterInputWrapperRef | undefined;
paramRef?.$emit('optionSelected', command);
},
valueChanged(parameterData: IUpdateInformation) {
this.$emit('valueChanged', parameterData);
},
onTextInput(parameterData: IUpdateInformation) {
const param = this.$refs.param as Vue | undefined;
const paramRef = this.$refs.param as ParamterInputWrapperRef | undefined;
if (isValueExpression(this.parameter, parameterData.value)) {
param?.$emit('optionSelected', 'addExpression');
paramRef?.$emit('optionSelected', 'addExpression');
}
},
onDrop(newParamValue: string) {

View file

@ -62,6 +62,8 @@ import { isValueExpression } from '@/utils';
import { mapStores } from 'pinia';
import { useNDVStore } from '@/stores/ndv';
type ParamRef = InstanceType<typeof ParameterInput>;
export default mixins(showMessage, workflowHelpers).extend({
name: 'parameter-input-wrapper',
components: {
@ -208,9 +210,9 @@ export default mixins(showMessage, workflowHelpers).extend({
this.$emit('drop', data);
},
optionSelected(command: string) {
if (this.$refs.param) {
(this.$refs.param as Vue).$emit('optionSelected', command);
}
const paramRef = this.$refs.param as ParamRef | undefined;
paramRef?.$emit('optionSelected', command);
},
onValueChanged(parameterData: IUpdateInformation) {
this.$emit('valueChanged', parameterData);

View file

@ -166,6 +166,8 @@ import { useRootStore } from '@/stores/n8nRootStore';
import { useNDVStore } from '@/stores/ndv';
import { useNodeTypesStore } from '@/stores/nodeTypes';
type ResourceLocatorDropdownRef = InstanceType<typeof ResourceLocatorDropdown>;
interface IResourceLocatorQuery {
results: INodeListSearchItems[];
nextPageToken: unknown;
@ -407,9 +409,9 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
watch: {
currentQueryError(curr: boolean, prev: boolean) {
if (this.showResourceDropdown && curr && !prev) {
const input = this.$refs.input;
if (input) {
(input as HTMLElement).focus();
const inputRef = this.$refs.input as HTMLInputElement | undefined;
if (inputRef) {
inputRef.focus();
}
}
},
@ -445,7 +447,7 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
},
methods: {
setWidth() {
const containerRef = this.$refs.container as HTMLElement;
const containerRef = this.$refs.container as HTMLElement | undefined;
if (containerRef) {
this.width = containerRef?.offsetWidth;
}
@ -465,9 +467,9 @@ export default mixins(debounceHelper, workflowHelpers, nodeHelpers).extend({
this.trackEvent('User refreshed resource locator list');
},
onKeyDown(e: MouseEvent) {
const dropdown = this.$refs.dropdown;
if (dropdown && this.showResourceDropdown && !this.isSearchable) {
(dropdown as Vue).$emit('keyDown', e);
const dropdownRef = this.$refs.dropdown as ResourceLocatorDropdownRef | undefined;
if (dropdownRef && this.showResourceDropdown && !this.isSearchable) {
dropdownRef.$emit('keyDown', e);
}
},
openResource(url: string) {

View file

@ -167,18 +167,21 @@ export default Vue.extend({
window.open(url, '_blank');
},
onKeyDown(e: KeyboardEvent) {
const container = this.$refs.resultsContainer as HTMLElement;
const containerRef = this.$refs.resultsContainer as HTMLElement | undefined;
if (e.key === 'ArrowDown') {
if (this.hoverIndex < this.sortedResources.length - 1) {
this.hoverIndex++;
const items = this.$refs[`item-${this.hoverIndex}`] as HTMLElement[];
if (container && Array.isArray(items) && items.length === 1) {
const item = items[0];
if (item.offsetTop + item.clientHeight > container.scrollTop + container.offsetHeight) {
const top = item.offsetTop - container.offsetHeight + item.clientHeight;
container.scrollTo({ top });
const itemRefs = this.$refs[`item-${this.hoverIndex}`] as HTMLElement[] | undefined;
if (containerRef && Array.isArray(itemRefs) && itemRefs.length === 1) {
const item = itemRefs[0];
if (
item.offsetTop + item.clientHeight >
containerRef.scrollTop + containerRef.offsetHeight
) {
const top = item.offsetTop - containerRef.offsetHeight + item.clientHeight;
containerRef.scrollTo({ top });
}
}
}
@ -187,11 +190,11 @@ export default Vue.extend({
this.hoverIndex--;
const searchOffset = this.filterable ? SEARCH_BAR_HEIGHT_PX : 0;
const items = this.$refs[`item-${this.hoverIndex}`] as HTMLElement[];
if (container && Array.isArray(items) && items.length === 1) {
const item = items[0];
if (item.offsetTop <= container.scrollTop + searchOffset) {
container.scrollTo({ top: item.offsetTop - searchOffset });
const itemRefs = this.$refs[`item-${this.hoverIndex}`] as HTMLElement[] | undefined;
if (containerRef && Array.isArray(itemRefs) && itemRefs.length === 1) {
const item = itemRefs[0];
if (item.offsetTop <= containerRef.scrollTop + searchOffset) {
containerRef.scrollTo({ top: item.offsetTop - searchOffset });
}
}
}
@ -225,9 +228,10 @@ export default Vue.extend({
return;
}
const container = this.$refs.resultsContainer as HTMLElement;
if (container) {
const diff = container.offsetHeight - (container.scrollHeight - container.scrollTop);
const containerRef = this.$refs.resultsContainer as HTMLElement | undefined;
if (containerRef) {
const diff =
containerRef.offsetHeight - (containerRef.scrollHeight - containerRef.scrollTop);
if (diff > -SCROLL_MARGIN_PX && diff < SCROLL_MARGIN_PX) {
this.$emit('loadMore');
}

View file

@ -1146,9 +1146,9 @@ export default mixins(externalHooks, genericHelpers, nodeHelpers, pinData).exten
const previous = this.displayMode;
this.ndvStore.setPanelDisplayMode({ pane: this.paneType, mode: displayMode });
const dataContainer = this.$refs.dataContainer;
if (dataContainer) {
const dataDisplay = (dataContainer as Element).children[0];
const dataContainerRef = this.$refs.dataContainer as Element | undefined;
if (dataContainerRef) {
const dataDisplay = dataContainerRef.children[0];
if (dataDisplay) {
dataDisplay.scrollTo(0, 0);

View file

@ -178,6 +178,8 @@ import { getMappedExpression } from '@/utils/mappingUtils';
const MAX_COLUMNS_LIMIT = 40;
type DraggableRef = InstanceType<typeof Draggable>;
export default mixins(externalHooks).extend({
name: 'run-data-table',
components: { Draggable, MappingPill },
@ -225,7 +227,7 @@ export default mixins(externalHooks).extend({
},
mounted() {
if (this.tableData && this.tableData.columns && this.$refs.draggable) {
const tbody = (this.$refs.draggable as Vue).$refs.wrapper as HTMLElement;
const tbody = (this.$refs.draggable as DraggableRef).$refs.wrapper;
if (tbody) {
this.$emit('mounted', {
avgRowHeight: tbody.offsetHeight / this.tableData.data.length,

View file

@ -66,6 +66,11 @@ import { useUIStore } from '@/stores/ui';
import { useTagsStore } from '@/stores/tags';
import { EventBus } from '@/event-bus';
import { PropType } from 'vue';
import { N8nOption, N8nSelect } from 'n8n-design-system';
type SelectRef = InstanceType<typeof N8nSelect>;
type TagRef = InstanceType<typeof N8nOption>;
type CreateRef = InstanceType<typeof N8nOption>;
const MANAGE_KEY = '__manage';
const CREATE_KEY = '__create';
@ -74,7 +79,10 @@ export default mixins(showMessage).extend({
name: 'TagsDropdown',
props: {
placeholder: {},
currentTagIds: {},
currentTagIds: {
type: Array as PropType<string[]>,
default: () => [],
},
createEnabled: {},
eventBus: {
type: Object as PropType<EventBus>,
@ -90,10 +98,8 @@ export default mixins(showMessage).extend({
};
},
mounted() {
// @ts-ignore
const select = (this.$refs.select &&
this.$refs.select.$refs &&
this.$refs.select.$refs.innerSelect) as Vue | undefined;
const selectRef = this.$refs.select as SelectRef | undefined;
const select = selectRef?.$refs?.innerSelect;
if (select) {
const input = select.$refs.input as Element | undefined;
if (input) {
@ -107,10 +113,8 @@ export default mixins(showMessage).extend({
this.$data.preventUpdate = true;
this.$emit('blur');
// @ts-ignore
if (this.$refs.select && typeof this.$refs.select.blur === 'function') {
// @ts-ignore
this.$refs.select.blur();
if (typeof selectRef?.blur === 'function') {
selectRef.blur();
}
}
});
@ -183,31 +187,27 @@ export default mixins(showMessage).extend({
}
},
focusOnTopOption() {
const tags = this.$refs.tag as Vue[] | undefined;
const create = this.$refs.create as Vue | undefined;
//@ts-ignore // focus on create option
if (create && create.hoverItem) {
// @ts-ignore
create.hoverItem();
const tagRefs = this.$refs.tag as TagRef[] | undefined;
const createRef = this.$refs.create as CreateRef | undefined;
// focus on create option
if (createRef && createRef.hoverItem) {
createRef.hoverItem();
}
//@ts-ignore // focus on top option after filter
else if (tags && tags[0] && tags[0].hoverItem) {
// @ts-ignore
tags[0].hoverItem();
// focus on top option after filter
else if (tagRefs && tagRefs[0] && tagRefs[0].hoverItem) {
tagRefs[0].hoverItem();
}
},
focusOnTag(tagId: string) {
const tagOptions = (this.$refs.tag as Vue[]) || [];
const tagOptions = (this.$refs.tag as TagRef[]) || [];
if (tagOptions && tagOptions.length) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const added = tagOptions.find((ref: any) => ref.value === tagId);
const added = tagOptions.find((ref) => ref.value === tagId);
}
},
focusOnInput() {
const select = this.$refs.select as Vue | undefined;
if (select) {
// @ts-ignore
select.focusOnInput();
const selectRef = this.$refs.select as SelectRef | undefined;
if (selectRef) {
selectRef.focusOnInput();
this.focused = true;
}
},

View file

@ -107,9 +107,14 @@
</template>
<script lang="ts">
import { Table as ElTable } from 'element-ui';
import { MAX_TAG_NAME_LENGTH } from '@/constants';
import { ITagRow } from '@/Interface';
import Vue from 'vue';
import { N8nInput } from 'n8n-design-system';
type TableRef = InstanceType<typeof ElTable>;
type N8nInputRef = InstanceType<typeof N8nInput>;
const INPUT_TRANSITION_TIMEOUT = 350;
const DELETE_TRANSITION_TIMEOUT = 100;
@ -173,26 +178,28 @@ export default Vue.extend({
focusOnInput(): void {
setTimeout(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const input = this.$refs.nameInput as any;
if (input && input.focus) {
input.focus();
const inputRef = this.$refs.nameInput as N8nInputRef | undefined;
if (inputRef && inputRef.focus) {
inputRef.focus();
}
}, INPUT_TRANSITION_TIMEOUT);
},
focusOnDelete(): void {
setTimeout(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const input = this.$refs.deleteHiddenInput as any;
if (input && input.focus) {
input.focus();
const inputRef = this.$refs.deleteHiddenInput as N8nInputRef | undefined;
if (inputRef && inputRef.focus) {
inputRef.focus();
}
}, DELETE_TRANSITION_TIMEOUT);
},
focusOnCreate(): void {
((this.$refs.table as Vue).$refs.bodyWrapper as Element).scrollTop = 0;
const bodyWrapperRef = (this.$refs.table as TableRef).$refs.bodyWrapper as HTMLElement;
if (bodyWrapperRef) {
bodyWrapperRef.scrollTop = 0;
}
this.focusOnInput();
},
},

View file

@ -76,12 +76,12 @@ export default mixins(genericHelpers).extend({
},
methods: {
onScroll() {
const el = this.$refs.loader;
if (!el || this.loading) {
const loaderRef = this.$refs.loader as HTMLElement | undefined;
if (!loaderRef || this.loading) {
return;
}
const rect = (el as Element).getBoundingClientRect();
const rect = loaderRef.getBoundingClientRect();
const inView =
rect.top >= 0 &&
rect.left >= 0 &&

View file

@ -113,6 +113,9 @@ import { useUIStore } from '@/stores/ui';
import { useWorkflowsStore } from '@/stores/workflows';
import { useNDVStore } from '@/stores/ndv';
import { useNodeTypesStore } from '@/stores/nodeTypes';
import { N8nInfoAccordion } from 'n8n-design-system';
type HelpRef = InstanceType<typeof N8nInfoAccordion>;
export default mixins(workflowHelpers, copyPaste, showMessage).extend({
name: 'TriggerPanel',
@ -355,7 +358,7 @@ export default mixins(workflowHelpers, copyPaste, showMessage).extend({
methods: {
expandExecutionHelp() {
if (this.$refs.help) {
(this.$refs.help as Vue).$emit('expand');
(this.$refs.help as HelpRef).$emit('expand');
}
},
onLinkClick(e: MouseEvent) {

View file

@ -82,6 +82,8 @@ import { useSettingsStore } from '@/stores/settings';
import { useUsersStore } from '@/stores/users';
import { useWorkflowsStore } from '@/stores/workflows';
type ActivatorRef = InstanceType<typeof WorkflowActivator>;
export const WORKFLOW_LIST_ITEM_ACTIONS = {
OPEN: 'open',
SHARE: 'share',
@ -165,7 +167,7 @@ export default mixins(showMessage, restApi).extend({
methods: {
async onClick(event?: PointerEvent) {
if (event) {
if ((this.$refs.activator as Vue)?.$el.contains(event.target as HTMLElement)) {
if ((this.$refs.activator as ActivatorRef)?.$el.contains(event.target as HTMLElement)) {
return;
}

View file

@ -96,9 +96,9 @@ export default mixins(showMessage).extend({
throw new Error(this.$locale.baseText('workflowPreview.showError.arrayEmpty'));
}
const iframe = this.$refs.preview_iframe as HTMLIFrameElement;
if (iframe.contentWindow) {
iframe.contentWindow.postMessage(
const iframeRef = this.$refs.preview_iframe as HTMLIFrameElement | undefined;
if (iframeRef?.contentWindow) {
iframeRef.contentWindow.postMessage(
JSON.stringify({
command: 'openWorkflow',
workflow: this.workflow,
@ -119,9 +119,9 @@ export default mixins(showMessage).extend({
if (!this.executionId) {
throw new Error(this.$locale.baseText('workflowPreview.showError.missingExecution'));
}
const iframe = this.$refs.preview_iframe as HTMLIFrameElement;
if (iframe.contentWindow) {
iframe.contentWindow.postMessage(
const iframeRef = this.$refs.preview_iframe as HTMLIFrameElement | undefined;
if (iframeRef?.contentWindow) {
iframeRef.contentWindow.postMessage(
JSON.stringify({
command: 'openExecution',
executionId: this.executionId,

View file

@ -196,7 +196,8 @@ import ResourceFiltersDropdown from '@/components/forms/ResourceFiltersDropdown.
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/settings';
import { useUsersStore } from '@/stores/users';
import { DatatableColumn } from 'n8n-design-system';
import { N8nInput } from 'n8n-design-system';
import type { DatatableColumn } from 'n8n-design-system';
export interface IResource {
id: string;
@ -216,6 +217,7 @@ interface IFilters {
}
type IResourceKeyType = 'credentials' | 'workflows';
type SearchRef = InstanceType<typeof N8nInput>;
const filterKeys = ['ownedBy', 'sharedWith'];
@ -405,7 +407,7 @@ export default mixins(showMessage, debounceHelper).extend({
},
focusSearchInput() {
if (this.$refs.search) {
(this.$refs.search as Vue & { focus: () => void }).focus();
(this.$refs.search as SearchRef).focus();
}
},
setOwnerSubview(active: boolean) {

View file

@ -1,39 +1,43 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import Vue from 'vue';
import { defineComponent } from 'vue';
function broadcast(componentName: string, eventName: string, params: any) {
// @ts-ignore
(this as Vue).$children.forEach((child) => {
function broadcast(
this: InstanceType<typeof EmitterMixin>,
componentName: string,
eventName: string,
params: any,
) {
this.$children.forEach((child) => {
const name = child.$options.name;
if (name === componentName) {
// @ts-ignore
// eslint-disable-next-line prefer-spread
child.$emit.apply(child, [eventName].concat(params));
child.$emit.apply(child, [eventName].concat(params) as Parameters<typeof child.$emit>);
} else {
// @ts-ignore
broadcast.apply(child, [componentName, eventName].concat([params]));
broadcast.apply(
child as InstanceType<typeof EmitterMixin>,
[componentName, eventName].concat([params]) as Parameters<typeof broadcast>,
);
}
});
}
export default Vue.extend({
const EmitterMixin = defineComponent({
methods: {
$dispatch(componentName: string, eventName: string, params: any) {
let parent = this.$parent || this.$root;
let name = parent.$options.name;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
parent = parent.$parent as InstanceType<typeof EmitterMixin>;
if (parent) {
name = parent.$options.name;
}
}
if (parent) {
// @ts-ignore
// eslint-disable-next-line prefer-spread
parent.$emit.apply(parent, [eventName].concat(params));
parent.$emit.apply(parent, [eventName].concat(params) as Parameters<typeof parent.$emit>);
}
},
@ -42,3 +46,5 @@ export default Vue.extend({
},
},
});
export default EmitterMixin;

View file

@ -1,5 +1,3 @@
// @ts-nocheck
import Vue from 'vue';
import Fragment from 'vue-fragment';
import VueAgile from 'vue-agile';
@ -8,7 +6,7 @@ import 'regenerator-runtime/runtime';
import ElementUI from 'element-ui';
import { Loading, MessageBox, Notification } from 'element-ui';
import { designSystemComponents } from 'n8n-design-system';
import { N8nPlugin } from 'n8n-design-system';
import EnterpriseEdition from '@/components/EnterpriseEdition.ee.vue';
import { useMessage } from '@/composables/useMessage';
@ -16,7 +14,7 @@ Vue.use(Fragment.Plugin);
Vue.use(VueAgile);
Vue.use(ElementUI);
Vue.use(designSystemComponents);
Vue.use(N8nPlugin);
Vue.component('enterprise-edition', EnterpriseEdition);

View file

@ -402,9 +402,9 @@ export default mixins(
this.canvasStore.setRecenteredCanvasAddButtonPosition(this.getNodeViewOffsetPosition);
},
nodeViewScale(newScale) {
const element = this.$refs.nodeView as HTMLDivElement;
if (element) {
element.style.transform = `scale(${newScale})`;
const elementRef = this.$refs.nodeView as HTMLDivElement | undefined;
if (elementRef) {
elementRef.style.transform = `scale(${newScale})`;
}
},
},

View file

@ -170,6 +170,9 @@ import { useSettingsStore } from '@/stores/settings';
import { getLdapSynchronizations } from '@/api/ldap';
import { N8N_CONTACT_EMAIL, N8N_SALES_EMAIL } from '@/constants';
import { createEventBus } from '@/event-bus';
import { N8nFormInputs } from 'n8n-design-system';
type N8nFormInputsRef = InstanceType<typeof N8nFormInputs>;
type FormValues = {
loginEnabled: boolean;
@ -295,32 +298,33 @@ export default mixins(showMessage).extend({
async onSubmit(): Promise<void> {
// We want to save all form values (incl. the hidden onces), so we are using
// `values` data prop of the `FormInputs` child component since they are all preserved there
const formInputs = this.$refs.ldapConfigForm as (Vue & { values: FormValues }) | undefined;
if (!this.hasAnyChanges || !formInputs) {
const formInputsRef = this.$refs.ldapConfigForm as N8nFormInputsRef | undefined;
if (!this.hasAnyChanges || !formInputsRef) {
return;
}
const newConfiguration: ILdapConfig = {
loginEnabled: formInputs.values.loginEnabled,
loginLabel: formInputs.values.loginLabel,
connectionUrl: formInputs.values.serverAddress,
allowUnauthorizedCerts: formInputs.values.allowUnauthorizedCerts,
connectionPort: +formInputs.values.port,
connectionSecurity: formInputs.values.connectionSecurity,
baseDn: formInputs.values.baseDn,
bindingAdminDn: formInputs.values.bindingType === 'admin' ? formInputs.values.adminDn : '',
loginEnabled: formInputsRef.values.loginEnabled,
loginLabel: formInputsRef.values.loginLabel,
connectionUrl: formInputsRef.values.serverAddress,
allowUnauthorizedCerts: formInputsRef.values.allowUnauthorizedCerts,
connectionPort: +formInputsRef.values.port,
connectionSecurity: formInputsRef.values.connectionSecurity,
baseDn: formInputsRef.values.baseDn,
bindingAdminDn:
formInputsRef.values.bindingType === 'admin' ? formInputsRef.values.adminDn : '',
bindingAdminPassword:
formInputs.values.bindingType === 'admin' ? formInputs.values.adminPassword : '',
emailAttribute: formInputs.values.email,
firstNameAttribute: formInputs.values.firstName,
lastNameAttribute: formInputs.values.lastName,
loginIdAttribute: formInputs.values.loginId,
ldapIdAttribute: formInputs.values.ldapId,
userFilter: formInputs.values.userFilter,
synchronizationEnabled: formInputs.values.synchronizationEnabled,
synchronizationInterval: +formInputs.values.synchronizationInterval,
searchPageSize: +formInputs.values.pageSize,
searchTimeout: +formInputs.values.searchTimeout,
formInputsRef.values.bindingType === 'admin' ? formInputsRef.values.adminPassword : '',
emailAttribute: formInputsRef.values.email,
firstNameAttribute: formInputsRef.values.firstName,
lastNameAttribute: formInputsRef.values.lastName,
loginIdAttribute: formInputsRef.values.loginId,
ldapIdAttribute: formInputsRef.values.ldapId,
userFilter: formInputsRef.values.userFilter,
synchronizationEnabled: formInputsRef.values.synchronizationEnabled,
synchronizationInterval: +formInputsRef.values.synchronizationInterval,
searchPageSize: +formInputsRef.values.pageSize,
searchTimeout: +formInputsRef.values.searchTimeout,
};
let saveForm = true;