From 9c94050debca6a18a931bd762f94cac9eedaeb6b Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Fri, 21 Apr 2023 18:51:08 +0300 Subject: [PATCH] feat: Replace Vue.extend with defineComponent in editor-ui (no-changelog) (#6033) * refactor: replace Vue.extend with defineComponent in editor-ui * fix: change $externalHooks extractions from mixins * fix: refactor externalHooks mixin --- packages/editor-ui/src/__tests__/utils.ts | 8 +++++ .../editor-ui/src/components/AboutModal.vue | 4 +-- .../src/components/ActivationModal.vue | 4 +-- .../editor-ui/src/components/AskAiModal.vue | 4 +-- packages/editor-ui/src/components/Banner.vue | 4 +-- .../CredentialEdit/CredentialInfo.vue | 4 +-- .../CredentialEdit/CredentialInputs.vue | 4 +-- .../src/components/CredentialIcon.vue | 4 +-- .../src/components/CredentialsSelect.vue | 4 +-- .../editor-ui/src/components/Draggable.vue | 4 +-- .../src/components/DraggableTarget.vue | 5 +-- .../src/components/EnterpriseEdition.ee.vue | 4 +-- .../src/components/ExecutionsModal.vue | 4 +-- .../ExecutionsView/ExecutionsLandingPage.vue | 4 +-- .../ExecutionsView/ExecutionsSidebar.vue | 4 +-- .../ExpandableInput/ExpandableInputBase.vue | 4 +-- .../ExpandableInput/ExpandableInputEdit.vue | 7 ++-- .../ExpandableInputPreview.vue | 4 +-- .../ExpressionEditorModalOutput.vue | 5 +-- .../components/ExpressionParameterInput.vue | 4 +-- .../src/components/FeatureComingSoon.vue | 4 +-- .../components/FixedCollectionParameter.vue | 12 +++---- .../editor-ui/src/components/GoBackButton.vue | 4 +-- .../src/components/HoverableNodeIcon.vue | 4 +-- .../InlineExpressionEditorOutput.vue | 6 ++-- .../src/components/InlineTextEdit.vue | 4 +-- .../src/components/IntersectionObserver.vue | 4 +-- packages/editor-ui/src/components/Logo.vue | 4 +-- .../src/components/MainHeader/TabBar.vue | 7 ++-- packages/editor-ui/src/components/Modal.vue | 7 ++-- .../editor-ui/src/components/ModalDrawer.vue | 7 ++-- .../editor-ui/src/components/ModalRoot.vue | 4 +-- packages/editor-ui/src/components/Modals.vue | 4 +-- .../src/components/MultipleParameter.vue | 7 ++-- .../src/components/Node/NodeCreation.vue | 4 +-- .../Node/NodeCreator/CategorizedItems.vue | 8 ++--- .../components/Node/NodeCreator/MainPanel.vue | 9 ++--- .../components/Node/NodeCreator/SearchBar.vue | 6 ++-- .../editor-ui/src/components/NodeIcon.vue | 4 +-- .../editor-ui/src/components/NodeTitle.vue | 4 +-- .../src/components/PageContentWrapper.vue | 4 +-- .../src/components/PanelDragButton.vue | 4 +-- .../src/components/ParameterInputExpanded.vue | 5 +-- .../src/components/ParameterInputHint.vue | 4 +-- .../src/components/ParameterIssues.vue | 4 +-- .../src/components/ParameterOptions.vue | 7 ++-- .../src/components/PushConnectionTracker.vue | 4 +-- .../ResourceLocatorDropdown.vue | 5 +-- .../src/components/RunDataSchema.vue | 3 +- packages/editor-ui/src/components/RunInfo.vue | 6 ++-- .../editor-ui/src/components/SaveButton.vue | 4 +-- .../editor-ui/src/components/ScopesNotice.vue | 4 +-- .../editor-ui/src/components/ShortenName.vue | 4 +-- .../src/components/TagsContainer.vue | 4 +-- .../src/components/TagsManager/NoTagsView.vue | 4 +-- .../TagsManager/TagsView/TagsTable.vue | 4 +-- .../TagsManager/TagsView/TagsTableHeader.vue | 4 +-- .../TagsManager/TagsView/TagsView.vue | 6 ++-- .../src/components/TemplateDetails.vue | 6 ++-- .../src/components/TemplateDetailsBlock.vue | 4 +-- .../editor-ui/src/components/TextEdit.vue | 6 ++-- packages/editor-ui/src/components/TimeAgo.vue | 4 +-- .../editor-ui/src/components/TitledList.vue | 4 +-- .../editor-ui/src/components/UpdatesPanel.vue | 4 +-- .../editor-ui/src/components/VersionCard.vue | 4 +-- .../__tests__/ExecutionsList.test.ts | 4 +-- .../components/__tests__/VariablesRow.spec.ts | 19 ++++++---- .../src/components/forms/CodeEditor.vue | 4 +-- .../forms/ResourceFiltersDropdown.vue | 7 ++-- .../forms/ResourceOwnershipSelect.ee.vue | 4 +-- .../src/components/layouts/PageViewLayout.vue | 4 +-- .../transitions/SlideTransition.vue | 4 +-- .../src/composables/useExternalHooks.ts | 8 ++--- packages/editor-ui/src/main.ts | 6 ++-- packages/editor-ui/src/mixins/copyPaste.ts | 4 +-- packages/editor-ui/src/mixins/debounce.ts | 4 +-- .../src/mixins/deviceSupportHelpers.ts | 4 +-- .../editor-ui/src/mixins/externalHooks.ts | 35 +++---------------- packages/editor-ui/src/mixins/restApi.ts | 4 +-- packages/editor-ui/src/mixins/userHelpers.ts | 8 ++--- packages/editor-ui/src/shims.d.ts | 6 ++++ packages/editor-ui/src/stores/nodeCreator.ts | 11 +++--- packages/editor-ui/src/utils/externalHooks.ts | 18 ++++++++++ packages/editor-ui/src/utils/index.ts | 1 + packages/editor-ui/src/views/AuthView.vue | 4 +-- packages/editor-ui/src/views/ErrorView.vue | 4 +-- .../editor-ui/src/views/ExecutionsView.vue | 4 +-- .../src/views/SettingsFakeDoorView.vue | 4 +-- .../editor-ui/src/views/TemplatesView.vue | 4 +-- .../src/views/__tests__/VariablesView.spec.ts | 11 +++--- 90 files changed, 265 insertions(+), 235 deletions(-) create mode 100644 packages/editor-ui/src/utils/externalHooks.ts diff --git a/packages/editor-ui/src/__tests__/utils.ts b/packages/editor-ui/src/__tests__/utils.ts index 8e0cacf179..9f9a7afb53 100644 --- a/packages/editor-ui/src/__tests__/utils.ts +++ b/packages/editor-ui/src/__tests__/utils.ts @@ -1,4 +1,6 @@ import { ISettingsState, UserManagementAuthenticationMethod } from '@/Interface'; +import { render } from '@testing-library/vue'; +import { PiniaVuePlugin } from 'pinia'; export const retry = (assertion: () => any, { interval = 20, timeout = 200 } = {}) => { return new Promise((resolve, reject) => { @@ -18,6 +20,12 @@ export const retry = (assertion: () => any, { interval = 20, timeout = 200 } = { }); }; +type RenderParams = Parameters; +export const renderComponent = (Component: RenderParams[0], renderOptions: RenderParams[1] = {}) => + render(Component, renderOptions, (vue) => { + vue.use(PiniaVuePlugin); + }); + export const waitAllPromises = () => new Promise((resolve) => setTimeout(resolve)); export const SETTINGS_STORE_DEFAULT_STATE: ISettingsState = { diff --git a/packages/editor-ui/src/components/AboutModal.vue b/packages/editor-ui/src/components/AboutModal.vue index f23621cea6..19b57c1fd0 100644 --- a/packages/editor-ui/src/components/AboutModal.vue +++ b/packages/editor-ui/src/components/AboutModal.vue @@ -54,7 +54,7 @@ diff --git a/packages/editor-ui/src/components/PanelDragButton.vue b/packages/editor-ui/src/components/PanelDragButton.vue index 6413ff061e..58acc80d9f 100644 --- a/packages/editor-ui/src/components/PanelDragButton.vue +++ b/packages/editor-ui/src/components/PanelDragButton.vue @@ -42,10 +42,10 @@ diff --git a/packages/editor-ui/src/components/TagsManager/TagsView/TagsTable.vue b/packages/editor-ui/src/components/TagsManager/TagsView/TagsTable.vue index c228cc436a..a93e25d985 100644 --- a/packages/editor-ui/src/components/TagsManager/TagsView/TagsTable.vue +++ b/packages/editor-ui/src/components/TagsManager/TagsView/TagsTable.vue @@ -110,7 +110,7 @@ import { Table as ElTable } from 'element-ui'; import { MAX_TAG_NAME_LENGTH } from '@/constants'; import { ITagRow } from '@/Interface'; -import Vue from 'vue'; +import { defineComponent } from 'vue'; import { N8nInput } from 'n8n-design-system'; type TableRef = InstanceType; @@ -119,7 +119,7 @@ type N8nInputRef = InstanceType; const INPUT_TRANSITION_TIMEOUT = 350; const DELETE_TRANSITION_TIMEOUT = 100; -export default Vue.extend({ +export default defineComponent({ name: 'TagsTable', props: ['rows', 'isLoading', 'newName', 'isSaving'], data() { diff --git a/packages/editor-ui/src/components/TagsManager/TagsView/TagsTableHeader.vue b/packages/editor-ui/src/components/TagsManager/TagsView/TagsTableHeader.vue index a7079d0232..543fd1b213 100644 --- a/packages/editor-ui/src/components/TagsManager/TagsView/TagsTableHeader.vue +++ b/packages/editor-ui/src/components/TagsManager/TagsView/TagsTableHeader.vue @@ -29,9 +29,9 @@ diff --git a/packages/editor-ui/src/composables/useExternalHooks.ts b/packages/editor-ui/src/composables/useExternalHooks.ts index ff3e3ab481..cd9b1049b5 100644 --- a/packages/editor-ui/src/composables/useExternalHooks.ts +++ b/packages/editor-ui/src/composables/useExternalHooks.ts @@ -1,12 +1,12 @@ -import { IExternalHooks } from '@/Interface'; -import { IDataObject } from 'n8n-workflow'; +import type { IExternalHooks } from '@/Interface'; +import type { IDataObject } from 'n8n-workflow'; import { useWebhooksStore } from '@/stores'; -import { runExternalHook } from '@/mixins/externalHooks'; +import { runExternalHook } from '@/utils'; export function useExternalHooks(): IExternalHooks { return { async run(eventName: string, metadata?: IDataObject): Promise { - return await runExternalHook.call(this, eventName, useWebhooksStore(), metadata); + return await runExternalHook(eventName, useWebhooksStore(), metadata); }, }; } diff --git a/packages/editor-ui/src/main.ts b/packages/editor-ui/src/main.ts index b95beda7f2..c25f6cc79d 100644 --- a/packages/editor-ui/src/main.ts +++ b/packages/editor-ui/src/main.ts @@ -19,16 +19,14 @@ import '@fontsource/open-sans/latin-700.css'; import App from '@/App.vue'; import router from './router'; -import { runExternalHook } from '@/mixins/externalHooks'; +import { runExternalHook } from '@/utils'; import { TelemetryPlugin } from './plugins/telemetry'; import { I18nPlugin, i18nInstance } from './plugins/i18n'; import { createPinia, PiniaVuePlugin } from 'pinia'; -import { useWebhooksStore } from './stores/webhooks'; -import { useUsersStore } from './stores/users'; +import { useWebhooksStore, useUsersStore } from '@/stores'; import { VIEWS } from '@/constants'; -import { useUIStore } from './stores/ui'; Vue.config.productionTip = false; diff --git a/packages/editor-ui/src/mixins/copyPaste.ts b/packages/editor-ui/src/mixins/copyPaste.ts index eee52394d9..49c4ae830d 100644 --- a/packages/editor-ui/src/mixins/copyPaste.ts +++ b/packages/editor-ui/src/mixins/copyPaste.ts @@ -2,10 +2,10 @@ * Captures any pasted data and sends it to method "receivedCopyPasteData" which has to be * defined on the component which uses this mixin */ -import Vue from 'vue'; +import { defineComponent } from 'vue'; import { debounce } from 'lodash-es'; -export const copyPaste = Vue.extend({ +export const copyPaste = defineComponent({ data() { return { copyPasteElementsGotCreated: false, diff --git a/packages/editor-ui/src/mixins/debounce.ts b/packages/editor-ui/src/mixins/debounce.ts index 7c491780aa..217db45d7a 100644 --- a/packages/editor-ui/src/mixins/debounce.ts +++ b/packages/editor-ui/src/mixins/debounce.ts @@ -1,7 +1,7 @@ import { debounce } from 'lodash-es'; -import Vue from 'vue'; +import { defineComponent } from 'vue'; -export const debounceHelper = Vue.extend({ +export const debounceHelper = defineComponent({ data() { return { debouncedFunctions: [] as any[], diff --git a/packages/editor-ui/src/mixins/deviceSupportHelpers.ts b/packages/editor-ui/src/mixins/deviceSupportHelpers.ts index 6b316bf87d..a8f87f8820 100644 --- a/packages/editor-ui/src/mixins/deviceSupportHelpers.ts +++ b/packages/editor-ui/src/mixins/deviceSupportHelpers.ts @@ -1,6 +1,6 @@ -import Vue from 'vue'; +import { defineComponent } from 'vue'; -export const deviceSupportHelpers = Vue.extend({ +export const deviceSupportHelpers = defineComponent({ data() { return { // @ts-ignore msMaxTouchPoints is deprecated but must fix tablet bugs before fixing this.. otherwise breaks touchscreen computers diff --git a/packages/editor-ui/src/mixins/externalHooks.ts b/packages/editor-ui/src/mixins/externalHooks.ts index 5a336ae125..09b180b039 100644 --- a/packages/editor-ui/src/mixins/externalHooks.ts +++ b/packages/editor-ui/src/mixins/externalHooks.ts @@ -1,35 +1,10 @@ -import { IExternalHooks } from '@/Interface'; +import type { IExternalHooks } from '@/Interface'; +import type { IDataObject } from 'n8n-workflow'; import { useWebhooksStore } from '@/stores/webhooks'; -import { IDataObject } from 'n8n-workflow'; -import { Store } from 'pinia'; -import Vue from 'vue'; +import { defineComponent } from 'vue'; +import { runExternalHook } from '@/utils'; -declare global { - interface Window { - n8nExternalHooks?: Record< - string, - Record Promise>> - >; - } -} - -export async function runExternalHook(eventName: string, store: Store, metadata?: IDataObject) { - if (!window.n8nExternalHooks) { - return; - } - - const [resource, operator] = eventName.split('.'); - - if (window.n8nExternalHooks[resource]?.[operator]) { - const hookMethods = window.n8nExternalHooks[resource][operator]; - - for (const hookMethod of hookMethods) { - await hookMethod(store, metadata); - } - } -} - -export const externalHooks = Vue.extend({ +export const externalHooks = defineComponent({ methods: { $externalHooks(): IExternalHooks { return { diff --git a/packages/editor-ui/src/mixins/restApi.ts b/packages/editor-ui/src/mixins/restApi.ts index f14d197815..7663eb1a7b 100644 --- a/packages/editor-ui/src/mixins/restApi.ts +++ b/packages/editor-ui/src/mixins/restApi.ts @@ -1,4 +1,4 @@ -import Vue from 'vue'; +import { defineComponent } from 'vue'; import { parse } from 'flatted'; import { Method } from 'axios'; @@ -55,7 +55,7 @@ function unflattenExecutionData(fullExecutionData: IExecutionFlattedResponse): I return returnData; } -export const restApi = Vue.extend({ +export const restApi = defineComponent({ computed: { ...mapStores(useRootStore), }, diff --git a/packages/editor-ui/src/mixins/userHelpers.ts b/packages/editor-ui/src/mixins/userHelpers.ts index 8ac4d45e03..ecf4bd6d9d 100644 --- a/packages/editor-ui/src/mixins/userHelpers.ts +++ b/packages/editor-ui/src/mixins/userHelpers.ts @@ -1,10 +1,10 @@ -import { IPermissions, IUser } from '@/Interface'; +import type { IPermissions } from '@/Interface'; import { isAuthorized } from '@/utils'; import { useUsersStore } from '@/stores/users'; -import Vue from 'vue'; -import { Route } from 'vue-router'; +import { defineComponent } from 'vue'; +import type { Route } from 'vue-router'; -export const userHelpers = Vue.extend({ +export const userHelpers = defineComponent({ methods: { canUserAccessRouteByName(name: string): boolean { const { route } = this.$router.resolve({ name }); diff --git a/packages/editor-ui/src/shims.d.ts b/packages/editor-ui/src/shims.d.ts index c231305c43..fc95a6f17d 100644 --- a/packages/editor-ui/src/shims.d.ts +++ b/packages/editor-ui/src/shims.d.ts @@ -1,4 +1,6 @@ import Vue, { VNode } from 'vue'; +import type { Store } from 'pinia'; +import type { IDataObject } from 'n8n-workflow'; declare module 'markdown-it-link-attributes'; declare module 'markdown-it-emoji'; @@ -17,6 +19,10 @@ declare global { interface Window { BASE_PATH: string; REST_ENDPOINT: string; + n8nExternalHooks?: Record< + string, + Record Promise>> + >; } namespace JSX { diff --git a/packages/editor-ui/src/stores/nodeCreator.ts b/packages/editor-ui/src/stores/nodeCreator.ts index 49bf4e0a58..f3709cd5e1 100644 --- a/packages/editor-ui/src/stores/nodeCreator.ts +++ b/packages/editor-ui/src/stores/nodeCreator.ts @@ -20,11 +20,12 @@ import { } from '@/constants'; import { useNodeTypesStore } from '@/stores/nodeTypes'; import { useWorkflowsStore } from './workflows'; -import { CUSTOM_API_CALL_KEY, ALL_NODE_FILTER } from '@/constants'; +import { CUSTOM_API_CALL_KEY } from '@/constants'; import { INodeCreatorState, INodeFilterType, IUpdateInformation } from '@/Interface'; -import { BaseTextKey, i18n } from '@/plugins/i18n'; -import { externalHooks } from '@/mixins/externalHooks'; +import { i18n } from '@/plugins/i18n'; import { Telemetry } from '@/plugins/telemetry'; +import { runExternalHook } from '@/utils'; +import { useWebhooksStore } from '@/stores/webhooks'; const PLACEHOLDER_RECOMMENDED_ACTION_KEY = 'placeholder_recommended'; @@ -286,14 +287,12 @@ export const useNodeCreatorStore = defineStore(STORES.NODE_CREATOR, { return storeWatcher; }, trackActionSelected(action: IUpdateInformation, telemetry?: Telemetry) { - const { $externalHooks } = new externalHooks(); - const payload = { node_type: action.key, action: action.name, resource: (action.value as INodeParameters).resource || '', }; - $externalHooks().run('nodeCreateList.addAction', payload); + runExternalHook('nodeCreateList.addAction', useWebhooksStore(), payload); telemetry?.trackNodesPanel('nodeCreateList.addAction', payload); }, }, diff --git a/packages/editor-ui/src/utils/externalHooks.ts b/packages/editor-ui/src/utils/externalHooks.ts new file mode 100644 index 0000000000..2cb48bc769 --- /dev/null +++ b/packages/editor-ui/src/utils/externalHooks.ts @@ -0,0 +1,18 @@ +import type { IDataObject } from 'n8n-workflow'; +import type { Store } from 'pinia'; + +export async function runExternalHook(eventName: string, store: Store, metadata?: IDataObject) { + if (!window.n8nExternalHooks) { + return; + } + + const [resource, operator] = eventName.split('.'); + + if (window.n8nExternalHooks[resource]?.[operator]) { + const hookMethods = window.n8nExternalHooks[resource][operator]; + + for (const hookMethod of hookMethods) { + await hookMethod(store, metadata); + } + } +} diff --git a/packages/editor-ui/src/utils/index.ts b/packages/editor-ui/src/utils/index.ts index 8cb8b02816..f5b1bdb5c1 100644 --- a/packages/editor-ui/src/utils/index.ts +++ b/packages/editor-ui/src/utils/index.ts @@ -1,5 +1,6 @@ export * from './apiUtils'; export * from './canvasUtils'; +export * from './externalHooks'; export * from './htmlUtils'; export * from './nodeTypesUtils'; export * from './sortUtils'; diff --git a/packages/editor-ui/src/views/AuthView.vue b/packages/editor-ui/src/views/AuthView.vue index 611090cbd4..7a3fa27ac7 100644 --- a/packages/editor-ui/src/views/AuthView.vue +++ b/packages/editor-ui/src/views/AuthView.vue @@ -22,12 +22,12 @@