From 54f99a7d0d9adafc9e7433b38eadd5f93b34d80b Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Fri, 21 Apr 2023 16:59:04 +0300 Subject: [PATCH] feat: Replace this.$refs.refName as Vue with InstanceType (no-changelog) (#6050) * refactor: use InstanceType 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> --- .../N8nButton/overrides/ElButton.vue | 4 +- .../src/components/N8nInput/Input.vue | 8 +- .../src/components/N8nSelect/Select.vue | 24 ++-- .../design-system/src/components/index.ts | 49 ++++++++ packages/design-system/src/main.ts | 5 +- packages/design-system/src/plugin.ts | 107 ++++++++++++++++++ .../src/plugins/n8nComponents.ts | 106 ----------------- .../CodeNodeEditor/CodeNodeEditor.vue | 8 +- .../src/components/CollectionsCarousel.vue | 17 +-- .../CredentialEdit/CredentialEdit.vue | 12 +- .../src/components/CredentialsSelect.vue | 9 +- .../src/components/CredentialsSelectModal.vue | 6 +- .../src/components/DraggableTarget.vue | 6 +- .../components/DuplicateWorkflowDialog.vue | 6 +- .../ExecutionsView/ExecutionPreview.vue | 8 +- .../ExecutionsView/ExecutionsSidebar.vue | 37 +++--- .../components/ExpressionParameterInput.vue | 9 +- .../src/components/HtmlEditor/HtmlEditor.vue | 9 +- .../src/components/InlineNameEdit.vue | 6 +- .../components/MainHeader/WorkflowDetails.vue | 6 +- .../editor-ui/src/components/NodeTitle.vue | 6 +- .../editor-ui/src/components/OutputPanel.vue | 7 +- .../src/components/ParameterInput.vue | 9 +- .../src/components/ParameterInputExpanded.vue | 4 +- .../src/components/ParameterInputFull.vue | 11 +- .../src/components/ParameterInputWrapper.vue | 8 +- .../ResourceLocator/ResourceLocator.vue | 16 +-- .../ResourceLocatorDropdown.vue | 34 +++--- packages/editor-ui/src/components/RunData.vue | 6 +- .../editor-ui/src/components/RunDataTable.vue | 4 +- .../editor-ui/src/components/TagsDropdown.vue | 52 ++++----- .../TagsManager/TagsView/TagsTable.vue | 25 ++-- .../editor-ui/src/components/TemplateList.vue | 6 +- .../editor-ui/src/components/TriggerPanel.vue | 5 +- .../editor-ui/src/components/WorkflowCard.vue | 4 +- .../src/components/WorkflowPreview.vue | 12 +- .../layouts/ResourcesListLayout.vue | 6 +- packages/editor-ui/src/mixins/emitter.ts | 30 +++-- packages/editor-ui/src/plugins/components.ts | 6 +- packages/editor-ui/src/views/NodeView.vue | 6 +- .../editor-ui/src/views/SettingsLdapView.vue | 46 ++++---- 41 files changed, 427 insertions(+), 318 deletions(-) create mode 100644 packages/design-system/src/components/index.ts create mode 100644 packages/design-system/src/plugin.ts delete mode 100644 packages/design-system/src/plugins/n8nComponents.ts diff --git a/packages/design-system/src/components/N8nButton/overrides/ElButton.vue b/packages/design-system/src/components/N8nButton/overrides/ElButton.vue index 817e6d7a55..1cbb31b820 100644 --- a/packages/design-system/src/components/N8nButton/overrides/ElButton.vue +++ b/packages/design-system/src/components/N8nButton/overrides/ElButton.vue @@ -13,6 +13,8 @@ const classToTypeMap = { 'el-picker-panel__link-btn': 'secondary', }; +type ButtonRef = InstanceType; + 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; } }); diff --git a/packages/design-system/src/components/N8nInput/Input.vue b/packages/design-system/src/components/N8nInput/Input.vue index 3408ea14ae..68e617d590 100644 --- a/packages/design-system/src/components/N8nInput/Input.vue +++ b/packages/design-system/src/components/N8nInput/Input.vue @@ -27,6 +27,8 @@ import { Input as ElInput } from 'element-ui'; import { defineComponent } from 'vue'; +type InputRef = InstanceType; + 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; diff --git a/packages/design-system/src/components/N8nSelect/Select.vue b/packages/design-system/src/components/N8nSelect/Select.vue index 856c4a9d98..7ea6eeb799 100644 --- a/packages/design-system/src/components/N8nSelect/Select.vue +++ b/packages/design-system/src/components/N8nSelect/Select.vue @@ -35,6 +35,8 @@ import { Select as ElSelect } from 'element-ui'; import { defineComponent } from 'vue'; +type InnerSelectRef = InstanceType; + 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(); } } }, diff --git a/packages/design-system/src/components/index.ts b/packages/design-system/src/components/index.ts new file mode 100644 index 0000000000..22683c0296 --- /dev/null +++ b/packages/design-system/src/components/index.ts @@ -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'; diff --git a/packages/design-system/src/main.ts b/packages/design-system/src/main.ts index 65ae159c2c..cf75163855 100644 --- a/packages/design-system/src/main.ts +++ b/packages/design-system/src/main.ts @@ -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 }; diff --git a/packages/design-system/src/plugin.ts b/packages/design-system/src/plugin.ts new file mode 100644 index 0000000000..0a9a470210 --- /dev/null +++ b/packages/design-system/src/plugin.ts @@ -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); + }, +}; diff --git a/packages/design-system/src/plugins/n8nComponents.ts b/packages/design-system/src/plugins/n8nComponents.ts deleted file mode 100644 index 6c182b53f2..0000000000 --- a/packages/design-system/src/plugins/n8nComponents.ts +++ /dev/null @@ -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; diff --git a/packages/editor-ui/src/components/CodeNodeEditor/CodeNodeEditor.vue b/packages/editor-ui/src/components/CodeNodeEditor/CodeNodeEditor.vue index fff8c461fa..3c95a9d018 100644 --- a/packages/editor-ui/src/components/CodeNodeEditor/CodeNodeEditor.vue +++ b/packages/editor-ui/src/components/CodeNodeEditor/CodeNodeEditor.vue @@ -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' }); diff --git a/packages/editor-ui/src/components/CollectionsCarousel.vue b/packages/editor-ui/src/components/CollectionsCarousel.vue index 00505c2781..cc86203f2d 100644 --- a/packages/editor-ui/src/components/CollectionsCarousel.vue +++ b/packages/editor-ui/src/components/CollectionsCarousel.vue @@ -35,6 +35,8 @@ import VueAgile from 'vue-agile'; import { genericHelpers } from '@/mixins/genericHelpers'; import mixins from 'vue-typed-mixins'; +type SliderRef = InstanceType; + 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); }, }); diff --git a/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue b/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue index 29b970f90c..5f37e2b0bd 100644 --- a/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue +++ b/packages/editor-ui/src/components/CredentialEdit/CredentialEdit.vue @@ -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); }, diff --git a/packages/editor-ui/src/components/CredentialsSelect.vue b/packages/editor-ui/src/components/CredentialsSelect.vue index 559bed74dd..d24ff30306 100644 --- a/packages/editor-ui/src/components/CredentialsSelect.vue +++ b/packages/editor-ui/src/components/CredentialsSelect.vue @@ -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; 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(); } }, /** diff --git a/packages/editor-ui/src/components/CredentialsSelectModal.vue b/packages/editor-ui/src/components/CredentialsSelectModal.vue index b2470bd0f6..8298633f39 100644 --- a/packages/editor-ui/src/components/CredentialsSelectModal.vue +++ b/packages/editor-ui/src/components/CredentialsSelectModal.vue @@ -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); }, diff --git a/packages/editor-ui/src/components/DraggableTarget.vue b/packages/editor-ui/src/components/DraggableTarget.vue index 742ff4d515..5ee76876c3 100644 --- a/packages/editor-ui/src/components/DraggableTarget.vue +++ b/packages/editor-ui/src/components/DraggableTarget.vue @@ -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 && diff --git a/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue b/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue index 3628ee0c95..fa433c420a 100644 --- a/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue +++ b/packages/editor-ui/src/components/DuplicateWorkflowDialog.vue @@ -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() { diff --git a/packages/editor-ui/src/components/ExecutionsView/ExecutionPreview.vue b/packages/editor-ui/src/components/ExecutionsView/ExecutionPreview.vue index bd5774a47a..1df971aac6 100644 --- a/packages/editor-ui/src/components/ExecutionsView/ExecutionPreview.vue +++ b/packages/editor-ui/src/components/ExecutionsView/ExecutionPreview.vue @@ -137,6 +137,8 @@ import { useUIStore } from '@/stores/ui'; import { Dropdown as ElDropdown } from 'element-ui'; import { IAbstractEventMessage } from 'n8n-workflow'; +type RetryDropdownRef = InstanceType & { 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(); } }, }, diff --git a/packages/editor-ui/src/components/ExecutionsView/ExecutionsSidebar.vue b/packages/editor-ui/src/components/ExecutionsView/ExecutionsSidebar.vue index 4a126a33d3..1f8e7d3c2d 100644 --- a/packages/editor-ui/src/components/ExecutionsView/ExecutionsSidebar.vue +++ b/packages/editor-ui/src/components/ExecutionsView/ExecutionsSidebar.vue @@ -77,6 +77,8 @@ import { useUIStore } from '@/stores/ui'; import { useWorkflowsStore } from '@/stores/workflows'; import { ExecutionFilterType } from '@/Interface'; +type ExecutionCardRef = InstanceType; + 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 }); } } }, diff --git a/packages/editor-ui/src/components/ExpressionParameterInput.vue b/packages/editor-ui/src/components/ExpressionParameterInput.vue index 3a8b6e79a5..4ef4f0519e 100644 --- a/packages/editor-ui/src/components/ExpressionParameterInput.vue +++ b/packages/editor-ui/src/components/ExpressionParameterInput.vue @@ -79,6 +79,8 @@ import { EXPRESSIONS_DOCS_URL } from '@/constants'; import type { Segment } from '@/types/expressions'; import type { TargetItem } from '@/Interface'; +type InlineExpressionEditorInputRef = InstanceType; + 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; diff --git a/packages/editor-ui/src/components/HtmlEditor/HtmlEditor.vue b/packages/editor-ui/src/components/HtmlEditor/HtmlEditor.vue index 23b7168b96..133c9be751 100644 --- a/packages/editor-ui/src/components/HtmlEditor/HtmlEditor.vue +++ b/packages/editor-ui/src/components/HtmlEditor/HtmlEditor.vue @@ -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() { diff --git a/packages/editor-ui/src/components/InlineNameEdit.vue b/packages/editor-ui/src/components/InlineNameEdit.vue index 4ec839fbd3..269c7d8656 100644 --- a/packages/editor-ui/src/components/InlineNameEdit.vue +++ b/packages/editor-ui/src/components/InlineNameEdit.vue @@ -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); }, diff --git a/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue b/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue index 44a5027f63..0e194b87df 100644 --- a/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue +++ b/packages/editor-ui/src/components/MainHeader/WorkflowDetails.vue @@ -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 { diff --git a/packages/editor-ui/src/components/NodeTitle.vue b/packages/editor-ui/src/components/NodeTitle.vue index a5a045b6be..2e51615c7b 100644 --- a/packages/editor-ui/src/components/NodeTitle.vue +++ b/packages/editor-ui/src/components/NodeTitle.vue @@ -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(); } }); }, diff --git a/packages/editor-ui/src/components/OutputPanel.vue b/packages/editor-ui/src/components/OutputPanel.vue index 3810071352..5c764637c0 100644 --- a/packages/editor-ui/src/components/OutputPanel.vue +++ b/packages/editor-ui/src/components/OutputPanel.vue @@ -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; 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', }); diff --git a/packages/editor-ui/src/components/ParameterInput.vue b/packages/editor-ui/src/components/ParameterInput.vue index 0cd176a07c..5936310e31 100644 --- a/packages/editor-ui/src/components/ParameterInput.vue +++ b/packages/editor-ui/src/components/ParameterInput.vue @@ -375,6 +375,8 @@ import { useNodeTypesStore } from '@/stores/nodeTypes'; import { useCredentialsStore } from '@/stores/credentials'; import { htmlEditorEventBus } from '@/event-bus'; +type ResourceLocatorRef = InstanceType; + 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') { diff --git a/packages/editor-ui/src/components/ParameterInputExpanded.vue b/packages/editor-ui/src/components/ParameterInputExpanded.vue index bba92cbbfd..53dc51d412 100644 --- a/packages/editor-ui/src/components/ParameterInputExpanded.vue +++ b/packages/editor-ui/src/components/ParameterInputExpanded.vue @@ -65,6 +65,8 @@ import { INodeParameterResourceLocator, INodeProperties, IParameterLabel } from import { mapStores } from 'pinia'; import { useWorkflowsStore } from '@/stores/workflows'; +type ParamRef = InstanceType; + 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) { diff --git a/packages/editor-ui/src/components/ParameterInputFull.vue b/packages/editor-ui/src/components/ParameterInputFull.vue index b884d76b12..35a15f7d2c 100644 --- a/packages/editor-ui/src/components/ParameterInputFull.vue +++ b/packages/editor-ui/src/components/ParameterInputFull.vue @@ -92,6 +92,8 @@ import { useSegment } from '@/stores/segment'; import { externalHooks } from '@/mixins/externalHooks'; import { getMappedResult } from '../utils/mappingUtils'; +type ParamterInputWrapperRef = InstanceType; + 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) { diff --git a/packages/editor-ui/src/components/ParameterInputWrapper.vue b/packages/editor-ui/src/components/ParameterInputWrapper.vue index 86e6ad9acb..34bfb4d3ea 100644 --- a/packages/editor-ui/src/components/ParameterInputWrapper.vue +++ b/packages/editor-ui/src/components/ParameterInputWrapper.vue @@ -62,6 +62,8 @@ import { isValueExpression } from '@/utils'; import { mapStores } from 'pinia'; import { useNDVStore } from '@/stores/ndv'; +type ParamRef = InstanceType; + 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); diff --git a/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue b/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue index 1b4f3f7c76..7ce47af422 100644 --- a/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue +++ b/packages/editor-ui/src/components/ResourceLocator/ResourceLocator.vue @@ -166,6 +166,8 @@ import { useRootStore } from '@/stores/n8nRootStore'; import { useNDVStore } from '@/stores/ndv'; import { useNodeTypesStore } from '@/stores/nodeTypes'; +type ResourceLocatorDropdownRef = InstanceType; + 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) { diff --git a/packages/editor-ui/src/components/ResourceLocator/ResourceLocatorDropdown.vue b/packages/editor-ui/src/components/ResourceLocator/ResourceLocatorDropdown.vue index c26e8cbda8..0b8c362e3a 100644 --- a/packages/editor-ui/src/components/ResourceLocator/ResourceLocatorDropdown.vue +++ b/packages/editor-ui/src/components/ResourceLocator/ResourceLocatorDropdown.vue @@ -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'); } diff --git a/packages/editor-ui/src/components/RunData.vue b/packages/editor-ui/src/components/RunData.vue index 8a97746285..b5fc193e8e 100644 --- a/packages/editor-ui/src/components/RunData.vue +++ b/packages/editor-ui/src/components/RunData.vue @@ -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); diff --git a/packages/editor-ui/src/components/RunDataTable.vue b/packages/editor-ui/src/components/RunDataTable.vue index 453f71cf3d..a295ec913d 100644 --- a/packages/editor-ui/src/components/RunDataTable.vue +++ b/packages/editor-ui/src/components/RunDataTable.vue @@ -178,6 +178,8 @@ import { getMappedExpression } from '@/utils/mappingUtils'; const MAX_COLUMNS_LIMIT = 40; +type DraggableRef = InstanceType; + 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, diff --git a/packages/editor-ui/src/components/TagsDropdown.vue b/packages/editor-ui/src/components/TagsDropdown.vue index a8a9b06d6b..48a8c001c2 100644 --- a/packages/editor-ui/src/components/TagsDropdown.vue +++ b/packages/editor-ui/src/components/TagsDropdown.vue @@ -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; +type TagRef = InstanceType; +type CreateRef = InstanceType; 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, + default: () => [], + }, createEnabled: {}, eventBus: { type: Object as PropType, @@ -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; } }, diff --git a/packages/editor-ui/src/components/TagsManager/TagsView/TagsTable.vue b/packages/editor-ui/src/components/TagsManager/TagsView/TagsTable.vue index 76af2dd739..c228cc436a 100644 --- a/packages/editor-ui/src/components/TagsManager/TagsView/TagsTable.vue +++ b/packages/editor-ui/src/components/TagsManager/TagsView/TagsTable.vue @@ -107,9 +107,14 @@