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
This commit is contained in:
Alex Grozav 2023-04-21 18:51:08 +03:00 committed by GitHub
parent 8a38624cbc
commit 9c94050deb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
90 changed files with 265 additions and 235 deletions

View file

@ -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<typeof render>;
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 = {

View file

@ -54,7 +54,7 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import Modal from './Modal.vue';
import { ABOUT_MODAL_KEY } from '../constants';
import { mapStores } from 'pinia';
@ -62,7 +62,7 @@ import { useSettingsStore } from '@/stores/settings';
import { useRootStore } from '@/stores/n8nRootStore';
import { createEventBus } from '@/event-bus';
export default Vue.extend({
export default defineComponent({
name: 'About',
components: {
Modal,

View file

@ -35,7 +35,7 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import Modal from '@/components/Modal.vue';
import {
@ -51,7 +51,7 @@ import { useWorkflowsStore } from '@/stores/workflows';
import { useNodeTypesStore } from '@/stores/nodeTypes';
import { createEventBus } from '@/event-bus';
export default Vue.extend({
export default defineComponent({
name: 'ActivationModal',
components: {
Modal,

View file

@ -23,12 +23,12 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import Modal from './Modal.vue';
import { ASK_AI_MODAL_KEY, ASK_AI_WAITLIST_URL } from '../constants';
import { createEventBus } from '@/event-bus';
export default Vue.extend({
export default defineComponent({
name: 'AskAI',
components: {
Modal,

View file

@ -36,9 +36,9 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'Banner',
data() {
return {

View file

@ -68,12 +68,12 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import TimeAgo from '../TimeAgo.vue';
import { INodeTypeDescription } from 'n8n-workflow';
export default Vue.extend({
export default defineComponent({
name: 'CredentialInfo',
props: ['nodesWithAccess', 'nodeAccess', 'currentCredential', 'credentialPermissions'],
components: {

View file

@ -24,12 +24,12 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import { IParameterLabel } from 'n8n-workflow';
import { IUpdateInformation } from '@/Interface';
import ParameterInputExpanded from '../ParameterInputExpanded.vue';
export default Vue.extend({
export default defineComponent({
name: 'CredentialsInput',
props: [
'credentialProperties',

View file

@ -12,9 +12,9 @@ import { useRootStore } from '@/stores/n8nRootStore';
import { useNodeTypesStore } from '@/stores/nodeTypes';
import { ICredentialType, INodeTypeDescription } from 'n8n-workflow';
import { mapStores } from 'pinia';
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
props: {
credentialTypeName: {
type: String,

View file

@ -56,7 +56,7 @@
<script lang="ts">
import { ICredentialType } from 'n8n-workflow';
import Vue from 'vue';
import Vue, { defineComponent } from 'vue';
import ScopesNotice from '@/components/ScopesNotice.vue';
import NodeCredentials from '@/components/NodeCredentials.vue';
import { mapStores } from 'pinia';
@ -65,7 +65,7 @@ import { N8nSelect } from 'n8n-design-system';
type N8nSelectRef = InstanceType<typeof N8nSelect>;
export default Vue.extend({
export default defineComponent({
name: 'CredentialsSelect',
components: {
ScopesNotice,

View file

@ -19,12 +19,12 @@
import { XYPosition } from '@/Interface';
import { useNDVStore } from '@/stores/ndv';
import { mapStores } from 'pinia';
import Vue from 'vue';
import { defineComponent } from 'vue';
// @ts-ignore
import Teleport from 'vue2-teleport';
export default Vue.extend({
export default defineComponent({
name: 'draggable',
components: {
Teleport,

View file

@ -7,9 +7,10 @@
<script lang="ts">
import { useNDVStore } from '@/stores/ndv';
import { mapStores } from 'pinia';
import Vue, { PropType } from 'vue';
import { defineComponent } from 'vue';
import type { PropType } from 'vue';
export default Vue.extend({
export default defineComponent({
props: {
type: {
type: String,

View file

@ -6,12 +6,12 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import { EnterpriseEditionFeature } from '@/constants';
import { mapStores } from 'pinia';
import { useSettingsStore } from '@/stores/settings';
export default Vue.extend({
export default defineComponent({
name: 'EnterpriseEdition',
props: {
features: {

View file

@ -7,13 +7,13 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import ExecutionsList from '@/components/ExecutionsList.vue';
import Modal from '@/components/Modal.vue';
import { EXECUTIONS_MODAL_KEY } from '@/constants';
import { createEventBus } from '@/event-bus';
export default Vue.extend({
export default defineComponent({
name: 'ExecutionsModal',
components: {
Modal,

View file

@ -27,10 +27,10 @@ import { PLACEHOLDER_EMPTY_WORKFLOW_ID, VIEWS } from '@/constants';
import { useUIStore } from '@/stores/ui';
import { useWorkflowsStore } from '@/stores/workflows';
import { mapStores } from 'pinia';
import Vue from 'vue';
import { defineComponent } from 'vue';
import ExecutionsInfoAccordion from './ExecutionsInfoAccordion.vue';
export default Vue.extend({
export default defineComponent({
name: 'executions-landing-page',
components: {
ExecutionsInfoAccordion,

View file

@ -70,7 +70,7 @@ import ExecutionFilter from '@/components/ExecutionFilter.vue';
import { VIEWS } from '@/constants';
import type { IExecutionsSummary } from 'n8n-workflow';
import { Route } from 'vue-router';
import Vue from 'vue';
import { defineComponent } from 'vue';
import { PropType } from 'vue';
import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui';
@ -79,7 +79,7 @@ import { ExecutionFilterType } from '@/Interface';
type ExecutionCardRef = InstanceType<typeof ExecutionCard>;
export default Vue.extend({
export default defineComponent({
name: 'executions-sidebar',
components: {
ExecutionCard,

View file

@ -6,9 +6,9 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'ExpandableInputBase',
props: ['value', 'placeholder', 'staticSize'],
computed: {

View file

@ -16,11 +16,12 @@
</template>
<script lang="ts">
import Vue, { PropType } from 'vue';
import { defineComponent } from 'vue';
import ExpandableInputBase from './ExpandableInputBase.vue';
import { EventBus } from '@/event-bus';
import type { PropType } from 'vue';
import type { EventBus } from '@/event-bus';
export default Vue.extend({
export default defineComponent({
components: { ExpandableInputBase },
name: 'ExpandableInputEdit',
props: {

View file

@ -12,10 +12,10 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import ExpandableInputBase from './ExpandableInputBase.vue';
export default Vue.extend({
export default defineComponent({
components: { ExpandableInputBase },
name: 'ExpandableInputPreview',
props: ['value'],

View file

@ -3,9 +3,10 @@
</template>
<script lang="ts">
import Vue, { PropType } from 'vue';
import { EditorView } from '@codemirror/view';
import { EditorState } from '@codemirror/state';
import { defineComponent } from 'vue';
import type { PropType } from 'vue';
import { highlighter } from '@/plugins/codemirror/resolvableHighlighter';
import { outputTheme } from './theme';
@ -13,7 +14,7 @@ import { outputTheme } from './theme';
import type { Plaintext, Resolved, Segment } from '@/types/expressions';
import { forceParse } from '@/utils/forceParse';
export default Vue.extend({
export default defineComponent({
name: 'ExpressionEditorModalOutput',
props: {
segments: {

View file

@ -66,7 +66,7 @@
<script lang="ts">
import { mapStores } from 'pinia';
import Vue from 'vue';
import { defineComponent } from 'vue';
import { useNDVStore } from '@/stores/ndv';
import { useWorkflowsStore } from '@/stores/workflows';
@ -81,7 +81,7 @@ import type { TargetItem } from '@/Interface';
type InlineExpressionEditorInputRef = InstanceType<typeof InlineExpressionEditorInput>;
export default Vue.extend({
export default defineComponent({
name: 'ExpressionParameterInput',
components: {
InlineExpressionEditorInput,

View file

@ -35,9 +35,9 @@ import { useSettingsStore } from '@/stores/settings';
import { useUIStore } from '@/stores/ui';
import { useUsersStore } from '@/stores/users';
import { mapStores } from 'pinia';
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'FeatureComingSoon',
props: {
featureId: {

View file

@ -112,21 +112,21 @@
</template>
<script lang="ts">
import Vue, { Component, PropType } from 'vue';
import { IUpdateInformation } from '@/Interface';
import { defineComponent } from 'vue';
import type { Component, PropType } from 'vue';
import type { IUpdateInformation } from '@/Interface';
import {
import { deepCopy, isINodePropertyCollectionList } from 'n8n-workflow';
import type {
INodeParameters,
INodeProperties,
INodePropertyCollection,
NodeParameterValue,
deepCopy,
isINodePropertyCollectionList,
} from 'n8n-workflow';
import { get } from 'lodash-es';
export default Vue.extend({
export default defineComponent({
name: 'FixedCollectionParameter',
props: {
nodeValues: {

View file

@ -7,9 +7,9 @@
<script lang="ts">
import { VIEWS } from '@/constants';
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'GoBackButton',
data() {
return {

View file

@ -40,7 +40,7 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import { ITemplatesNode } from '@/Interface';
import { INodeTypeDescription } from 'n8n-workflow';
@ -54,7 +54,7 @@ interface NodeIconData {
fileBuffer?: string;
}
export default Vue.extend({
export default defineComponent({
name: 'HoverableNodeIcon',
props: {
circle: {

View file

@ -3,16 +3,18 @@
</template>
<script lang="ts">
import Vue, { PropType } from 'vue';
import { EditorView } from '@codemirror/view';
import { EditorState } from '@codemirror/state';
import { defineComponent } from 'vue';
import type { PropType } from 'vue';
import { highlighter } from '@/plugins/codemirror/resolvableHighlighter';
import { outputTheme } from './theme';
import type { Plaintext, Resolved, Segment } from '@/types/expressions';
export default Vue.extend({
export default defineComponent({
name: 'InlineExpressionEditorOutput',
props: {
segments: {

View file

@ -21,12 +21,12 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import ExpandableInputEdit from '@/components/ExpandableInput/ExpandableInputEdit.vue';
import ExpandableInputPreview from '@/components/ExpandableInput/ExpandableInputPreview.vue';
import { createEventBus } from '@/event-bus';
export default Vue.extend({
export default defineComponent({
name: 'InlineTextEdit',
components: { ExpandableInputEdit, ExpandableInputPreview },
props: ['isEditEnabled', 'value', 'placeholder', 'maxLength', 'previewValue'],

View file

@ -5,9 +5,9 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'IntersectionObserver',
props: ['threshold', 'enabled'],
data() {

View file

@ -5,9 +5,9 @@
<script lang="ts">
import { useRootStore } from '@/stores/n8nRootStore';
import { mapStores } from 'pinia';
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
computed: {
...mapStores(useRootStore),
basePath(): string {

View file

@ -12,13 +12,14 @@
</template>
<script lang="ts">
import Vue, { PropType } from 'vue';
import { ITabBarItem } from '@/Interface';
import { defineComponent } from 'vue';
import type { PropType } from 'vue';
import type { ITabBarItem } from '@/Interface';
import { MAIN_HEADER_TABS } from '@/constants';
import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui';
export default Vue.extend({
export default defineComponent({
name: 'tab-bar',
data() {
return {

View file

@ -43,12 +43,13 @@
</template>
<script lang="ts">
import Vue, { PropType } from 'vue';
import { defineComponent } from 'vue';
import type { PropType } from 'vue';
import { useUIStore } from '@/stores/ui';
import { mapStores } from 'pinia';
import { EventBus } from '@/event-bus';
import type { EventBus } from '@/event-bus';
export default Vue.extend({
export default defineComponent({
name: 'Modal',
props: {
name: {

View file

@ -21,10 +21,11 @@
<script lang="ts">
import { useUIStore } from '@/stores/ui';
import { mapStores } from 'pinia';
import Vue, { PropType } from 'vue';
import { EventBus } from '@/event-bus';
import { defineComponent } from 'vue';
import type { PropType } from 'vue';
import type { EventBus } from '@/event-bus';
export default Vue.extend({
export default defineComponent({
name: 'ModalDrawer',
props: {
name: {

View file

@ -12,11 +12,11 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import { useUIStore } from '@/stores/ui';
import { mapStores } from 'pinia';
export default Vue.extend({
export default defineComponent({
name: 'ModalRoot',
props: {
name: {

View file

@ -119,7 +119,7 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import {
ABOUT_MODAL_KEY,
CHANGE_PASSWORD_MODAL_KEY,
@ -171,7 +171,7 @@ import WorkflowShareModal from './WorkflowShareModal.ee.vue';
import WorkflowSuccessModal from './UserActivationSurveyModal.vue';
import EventDestinationSettingsModal from '@/components/SettingsLogStreaming/EventDestinationSettingsModal.ee.vue';
export default Vue.extend({
export default defineComponent({
name: 'Modals',
components: {
AboutModal,

View file

@ -84,15 +84,16 @@
</template>
<script lang="ts">
import Vue, { PropType } from 'vue';
import { IUpdateInformation } from '@/Interface';
import { defineComponent } from 'vue';
import type { PropType } from 'vue';
import type { IUpdateInformation } from '@/Interface';
import { deepCopy, INodeParameters, INodeProperties } from 'n8n-workflow';
import CollectionParameter from '@/components/CollectionParameter.vue';
import ParameterInputFull from '@/components/ParameterInputFull.vue';
import { get } from 'lodash-es';
export default Vue.extend({
export default defineComponent({
name: 'MultipleParameter',
components: {
CollectionParameter,

View file

@ -37,7 +37,7 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import { getMidCanvasPosition } from '@/utils/nodeViewUtils';
import {
DEFAULT_STICKY_HEIGHT,
@ -48,7 +48,7 @@ import {
import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui';
export default Vue.extend({
export default defineComponent({
name: 'node-creation',
components: {
NodeCreator: () => import('@/components/Node/NodeCreator/NodeCreator.vue'),

View file

@ -96,7 +96,6 @@ import {
nextTick,
} from 'vue';
import { camelCase } from 'lodash-es';
import { externalHooks } from '@/mixins/externalHooks';
import { INodeTypeDescription } from 'n8n-workflow';
import ItemIterator from './ItemIterator.vue';
import SearchBar from './SearchBar.vue';
@ -114,6 +113,7 @@ import { sublimeSearch, matchesNodeType, matchesSelectType } from '@/utils';
import { useWorkflowsStore } from '@/stores/workflows';
import { useRootStore } from '@/stores/n8nRootStore';
import { useNodeCreatorStore } from '@/stores/nodeCreator';
import { useExternalHooks } from '@/composables';
export interface Props {
showSubcategoryIcon?: boolean;
@ -148,7 +148,7 @@ const emit = defineEmits<{
}>();
const instance = getCurrentInstance();
const { $externalHooks } = new externalHooks();
const externalHooks = useExternalHooks();
const { defaultLocale } = useRootStore();
const { workflowId } = useWorkflowsStore();
@ -549,7 +549,7 @@ onUnmounted(() => {
});
watch(filteredNodeTypes, (returnItems) => {
$externalHooks().run('nodeCreateList.filteredNodeTypesComputed', {
externalHooks.run('nodeCreateList.filteredNodeTypesComputed', {
nodeFilter: nodeCreatorStore.itemsFilter,
result: returnItems,
selectedType: nodeCreatorStore.selectedView,
@ -569,7 +569,7 @@ watch(
// Reset the index whenver the filter-value changes
state.activeIndex = 0;
state.activeSubcategoryIndex = 0;
$externalHooks().run('nodeCreateList.nodeFilterChanged', {
externalHooks.run('nodeCreateList.nodeFilterChanged', {
oldValue,
newValue,
selectedType: nodeCreatorStore.selectedView,

View file

@ -105,12 +105,12 @@ import {
import CategorizedItems from './CategorizedItems.vue';
import { useNodeCreatorStore } from '@/stores/nodeCreator';
import { getCategoriesWithNodes, getCategorizedList } from '@/utils';
import { externalHooks } from '@/mixins/externalHooks';
import { useNodeTypesStore } from '@/stores/nodeTypes';
import { BaseTextKey } from '@/plugins/i18n';
import NoResults from './NoResults.vue';
import { useRootStore } from '@/stores/n8nRootStore';
import useMainPanelView from './useMainPanelView';
import { useExternalHooks } from '@/composables';
const instance = getCurrentInstance();
@ -124,7 +124,8 @@ const state = reactive({
activeNodeActions: null as INodeTypeDescription | null,
});
const { baseUrl } = useRootStore();
const { $externalHooks } = new externalHooks();
const externalHooks = useExternalHooks();
const {
mergedAppNodes,
getActionData,
@ -324,7 +325,7 @@ function addHttpNode(isAction: boolean) {
setAddedNodeActionParameters(updateData, telemetry, false);
const app_identifier = state.activeNodeActions?.name;
$externalHooks().run('nodeCreateList.onActionsCustmAPIClicked', { app_identifier });
externalHooks.run('nodeCreateList.onActionsCustmAPIClicked', { app_identifier });
telemetry?.trackNodesPanel('nodeCreateList.onActionsCustmAPIClicked', { app_identifier });
}
}
@ -362,7 +363,7 @@ function trackActionsView() {
trigger_action_count,
};
$externalHooks().run('nodeCreateList.onViewActions', trackingPayload);
externalHooks.run('nodeCreateList.onViewActions', trackingPayload);
telemetry?.trackNodesPanel('nodeCreateList.onViewActions', trackingPayload);
}

View file

@ -25,8 +25,8 @@
<script setup lang="ts">
import { onMounted, reactive, toRefs, onBeforeUnmount } from 'vue';
import { externalHooks } from '@/mixins/externalHooks';
import { EventBus } from '@/event-bus';
import { useExternalHooks } from '@/composables';
export interface Props {
placeholder: string;
@ -43,7 +43,7 @@ const emit = defineEmits<{
(event: 'input', value: string): void;
}>();
const { $externalHooks } = new externalHooks();
const externalHooks = useExternalHooks();
const state = reactive({
inputRef: null as HTMLInputElement | null,
@ -63,7 +63,7 @@ function clear() {
}
onMounted(() => {
$externalHooks().run('nodeCreator_searchBar.mount', { inputRef: state.inputRef });
externalHooks.run('nodeCreator_searchBar.mount', { inputRef: state.inputRef });
setTimeout(focus, 0);
});

View file

@ -18,7 +18,7 @@ import { IVersionNode } from '@/Interface';
import { useRootStore } from '@/stores/n8nRootStore';
import { INodeTypeDescription } from 'n8n-workflow';
import { mapStores } from 'pinia';
import Vue from 'vue';
import { defineComponent } from 'vue';
interface NodeIconSource {
path?: string;
@ -26,7 +26,7 @@ interface NodeIconSource {
icon?: string;
}
export default Vue.extend({
export default defineComponent({
name: 'NodeIcon',
props: {
nodeType: {},

View file

@ -40,9 +40,9 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'NodeTitle',
props: {
value: {

View file

@ -9,9 +9,9 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'PageContentWrapper',
});
</script>

View file

@ -42,10 +42,10 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import Draggable from './Draggable.vue';
export default Vue.extend({
export default defineComponent({
components: {
Draggable,
},

View file

@ -58,7 +58,8 @@
<script lang="ts">
import { IUpdateInformation } from '@/Interface';
import ParameterOptions from './ParameterOptions.vue';
import Vue, { PropType } from 'vue';
import { defineComponent } from 'vue';
import type { PropType } from 'vue';
import ParameterInputWrapper from './ParameterInputWrapper.vue';
import { isValueExpression } from '@/utils';
import { INodeParameterResourceLocator, INodeProperties, IParameterLabel } from 'n8n-workflow';
@ -67,7 +68,7 @@ import { useWorkflowsStore } from '@/stores/workflows';
type ParamRef = InstanceType<typeof ParameterInputWrapper>;
export default Vue.extend({
export default defineComponent({
name: 'parameter-input-expanded',
components: {
ParameterOptions,

View file

@ -17,9 +17,9 @@
<script lang="ts">
import { sanitizeHtml } from '@/utils';
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'InputHint',
props: {
hint: {

View file

@ -10,10 +10,10 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import TitledList from '@/components/TitledList.vue';
export default Vue.extend({
export default defineComponent({
name: 'ParameterIssues',
components: {
TitledList,

View file

@ -25,11 +25,12 @@
</template>
<script lang="ts">
import { NodeParameterValueType } from 'n8n-workflow';
import Vue, { PropType } from 'vue';
import type { NodeParameterValueType } from 'n8n-workflow';
import { defineComponent } from 'vue';
import type { PropType } from 'vue';
import { isValueExpression, isResourceLocatorValue } from '@/utils';
export default Vue.extend({
export default defineComponent({
name: 'parameter-options',
props: {
parameter: {

View file

@ -18,9 +18,9 @@
<script lang="ts">
import { useRootStore } from '@/stores/n8nRootStore';
import { mapStores } from 'pinia';
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'PushConnectionTracker',
computed: {
...mapStores(useRootStore),

View file

@ -79,12 +79,13 @@
<script lang="ts">
import { IResourceLocatorResultExpanded } from '@/Interface';
import Vue, { PropType } from 'vue';
import { defineComponent } from 'vue';
import type { PropType } from 'vue';
const SEARCH_BAR_HEIGHT_PX = 40;
const SCROLL_MARGIN_PX = 10;
export default Vue.extend({
export default defineComponent({
name: 'resource-locator-dropdown',
props: {
value: {

View file

@ -6,10 +6,9 @@ import RunDataSchemaItem from '@/components/RunDataSchemaItem.vue';
import Draggable from '@/components/Draggable.vue';
import { useNDVStore } from '@/stores/ndv';
import { useWebhooksStore } from '@/stores/webhooks';
import { runExternalHook } from '@/mixins/externalHooks';
import { telemetry } from '@/plugins/telemetry';
import { IDataObject } from 'n8n-workflow';
import { getSchema, isEmpty } from '@/utils';
import { getSchema, isEmpty, runExternalHook } from '@/utils';
import { i18n } from '@/plugins/i18n';
import MappingPill from './MappingPill.vue';

View file

@ -14,10 +14,10 @@
</template>
<script lang="ts">
import { ITaskData } from 'n8n-workflow';
import Vue from 'vue';
import type { ITaskData } from 'n8n-workflow';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
props: {
taskData: {}, // ITaskData
},

View file

@ -14,9 +14,9 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'SaveButton',
props: {
saved: {

View file

@ -5,9 +5,9 @@
<script lang="ts">
import { useCredentialsStore } from '@/stores/credentials';
import { mapStores } from 'pinia';
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'ScopesNotice',
props: ['activeCredentialType', 'scopes'],
computed: {

View file

@ -5,13 +5,13 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import { shorten } from '@/utils';
const DEFAULT_WORKFLOW_NAME_LIMIT = 25;
const WORKFLOW_NAME_END_COUNT_TO_KEEP = 4;
export default Vue.extend({
export default defineComponent({
name: 'ShortenName',
props: ['name', 'limit', 'testId'],
computed: {

View file

@ -39,7 +39,7 @@
</template>
<script lang="ts">
import Vue from 'vue';
import Vue, { defineComponent } from 'vue';
import { ITag } from '@/Interface';
import IntersectionObserver from './IntersectionObserver.vue';
@ -56,7 +56,7 @@ interface TagEl extends ITag {
isCount?: boolean;
}
export default Vue.extend({
export default defineComponent({
components: { IntersectionObserver, IntersectionObserved },
name: 'TagsContainer',
props: ['tagIds', 'limit', 'clickable', 'responsive', 'hoverable'],

View file

@ -16,9 +16,9 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'NoTagsView',
});
</script>

View file

@ -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<typeof ElTable>;
@ -119,7 +119,7 @@ type N8nInputRef = InstanceType<typeof N8nInput>;
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() {

View file

@ -29,9 +29,9 @@
<script lang="ts">
import { MAX_TAG_NAME_LENGTH } from '@/constants';
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
props: {
disabled: {
default: false,

View file

@ -23,9 +23,9 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import { ITag, ITagRow } from '@/Interface';
import type { ITag, ITagRow } from '@/Interface';
import TagsTableHeader from '@/components/TagsManager/TagsView/TagsTableHeader.vue';
import TagsTable from '@/components/TagsManager/TagsView/TagsTable.vue';
import { mapStores } from 'pinia';
@ -34,7 +34,7 @@ import { useUsersStore } from '@/stores/users';
const matches = (name: string, filter: string) =>
name.toLowerCase().trim().includes(filter.toLowerCase().trim());
export default Vue.extend({
export default defineComponent({
components: { TagsTableHeader, TagsTable },
name: 'TagsView',
props: ['tags', 'isLoading'],

View file

@ -47,14 +47,16 @@
</div>
</template>
<script lang="ts">
import Vue, { PropType } from 'vue';
import { defineComponent } from 'vue';
import type { PropType } from 'vue';
import TemplateDetailsBlock from '@/components/TemplateDetailsBlock.vue';
import NodeIcon from '@/components/NodeIcon.vue';
import { abbreviateNumber, filterTemplateNodes } from '@/utils';
import { ITemplatesNode, ITemplatesWorkflow, ITemplatesWorkflowFull } from '@/Interface';
import { mapStores } from 'pinia';
import { useTemplatesStore } from '@/stores/templates';
export default Vue.extend({
export default defineComponent({
name: 'TemplateDetails',
props: {
blockTitle: {

View file

@ -10,9 +10,9 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'TemplateDetailsBlock',
props: {
title: {

View file

@ -30,9 +30,9 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { nextTick, defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'TextEdit',
props: ['dialogVisible', 'parameter', 'path', 'value', 'isReadOnly'],
data() {
@ -65,7 +65,7 @@ export default Vue.extend({
watch: {
dialogVisible() {
if (this.dialogVisible === true) {
Vue.nextTick(() => {
nextTick(() => {
(this.$refs.inputField as HTMLInputElement).focus();
});
}

View file

@ -7,11 +7,11 @@
<script lang="ts">
import { format, LocaleFunc, register } from 'timeago.js';
import { convertToHumanReadableDate } from '@/utils';
import Vue from 'vue';
import { defineComponent } from 'vue';
import { mapStores } from 'pinia';
import { useRootStore } from '@/stores/n8nRootStore';
export default Vue.extend({
export default defineComponent({
name: 'TimeAgo',
props: {
date: {

View file

@ -8,9 +8,9 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'TitledList',
props: {
title: {

View file

@ -43,7 +43,7 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import ModalDrawer from './ModalDrawer.vue';
import TimeAgo from './TimeAgo.vue';
@ -53,7 +53,7 @@ import { mapStores } from 'pinia';
import { useVersionsStore } from '@/stores/versions';
import { IVersion } from '@/Interface';
export default Vue.extend({
export default defineComponent({
name: 'UpdatesPanel',
components: {
ModalDrawer,

View file

@ -55,7 +55,7 @@
</template>
<script lang="ts">
import Vue from 'vue';
import Vue, { defineComponent } from 'vue';
import NodeIcon from './NodeIcon.vue';
import TimeAgo from './TimeAgo.vue';
import Badge from './Badge.vue';
@ -67,7 +67,7 @@ Vue.component('TimeAgo', TimeAgo);
Vue.component('Badge', Badge);
Vue.component('WarningTooltip', WarningTooltip);
export default Vue.extend({
export default defineComponent({
components: { NodeIcon, TimeAgo, Badge, WarningTooltip },
name: 'VersionCard',
props: ['version'],

View file

@ -1,5 +1,5 @@
import { vi, describe, it, expect } from 'vitest';
import Vue from 'vue';
import Vue, { defineComponent } from 'vue';
import { PiniaVuePlugin } from 'pinia';
import { createTestingPinia } from '@pinia/testing';
import { render } from '@testing-library/vue';
@ -47,7 +47,7 @@ const executionsData = Array.from({ length: 2 }, () => ({
let getPastExecutionsSpy = vi.fn().mockResolvedValue({ count: 0, results: [], estimated: false });
const mockRestApiMixin = Vue.extend({
const mockRestApiMixin = defineComponent({
methods: {
restApi() {
return {

View file

@ -1,20 +1,23 @@
import VariablesRow from '../VariablesRow.vue';
import { EnvironmentVariable } from '@/Interface';
import { fireEvent, render } from '@testing-library/vue';
import { fireEvent } from '@testing-library/vue';
import { createPinia, setActivePinia } from 'pinia';
import { setupServer } from '@/__tests__/server';
import { afterAll, beforeAll } from 'vitest';
import { useSettingsStore, useUsersStore } from '@/stores';
import { renderComponent } from '@/__tests__/utils';
describe('VariablesRow', () => {
let server: ReturnType<typeof setupServer>;
let pinia: ReturnType<typeof createPinia>;
beforeAll(() => {
server = setupServer();
});
beforeEach(async () => {
setActivePinia(createPinia());
pinia = createPinia();
setActivePinia(pinia);
await useSettingsStore().getSettings();
await useUsersStore().loginWithCookie();
@ -33,11 +36,12 @@ describe('VariablesRow', () => {
};
it('should render correctly', () => {
const wrapper = render(VariablesRow, {
const wrapper = renderComponent(VariablesRow, {
props: {
data: environmentVariable,
},
stubs,
pinia,
});
expect(wrapper.html()).toMatchSnapshot();
@ -45,11 +49,12 @@ describe('VariablesRow', () => {
});
it('should show edit and delete buttons on hover', async () => {
const wrapper = render(VariablesRow, {
const wrapper = renderComponent(VariablesRow, {
props: {
data: environmentVariable,
},
stubs,
pinia,
});
await fireEvent.mouseEnter(wrapper.container);
@ -59,12 +64,13 @@ describe('VariablesRow', () => {
});
it('should show key and value inputs in edit mode', async () => {
const wrapper = render(VariablesRow, {
const wrapper = renderComponent(VariablesRow, {
props: {
data: environmentVariable,
editing: true,
},
stubs,
pinia,
});
await fireEvent.mouseEnter(wrapper.container);
@ -82,12 +88,13 @@ describe('VariablesRow', () => {
});
it('should show cancel and save buttons in edit mode', async () => {
const wrapper = render(VariablesRow, {
const wrapper = renderComponent(VariablesRow, {
props: {
data: environmentVariable,
editing: true,
},
stubs,
pinia,
});
await fireEvent.mouseEnter(wrapper.container);

View file

@ -3,10 +3,10 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import * as monaco from 'monaco-editor';
export default Vue.extend({
export default defineComponent({
props: {
type: {
type: String,

View file

@ -63,15 +63,16 @@
</template>
<script lang="ts">
import Vue, { PropType } from 'vue';
import { defineComponent } from 'vue';
import { EnterpriseEditionFeature } from '@/constants';
import { IUser } from '@/Interface';
import { mapStores } from 'pinia';
import { useUsersStore } from '@/stores/users';
import type { PropType } from 'vue';
import type { IUser } from '@/Interface';
export type IResourceFiltersType = Record<string, boolean | string | string[]>;
export default Vue.extend({
export default defineComponent({
props: {
value: {
type: Object as PropType<IResourceFiltersType>,

View file

@ -8,10 +8,10 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import { IMenuItem } from 'n8n-design-system';
export default Vue.extend({
export default defineComponent({
props: {
value: {
type: Boolean,

View file

@ -14,9 +14,9 @@
<script lang="ts">
import { useUIStore } from '@/stores/ui';
import { mapStores } from 'pinia';
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'PageViewLayout',
data() {
return {

View file

@ -5,9 +5,9 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'SlideTransition',
});
</script>

View file

@ -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<void> {
return await runExternalHook.call(this, eventName, useWebhooksStore(), metadata);
return await runExternalHook(eventName, useWebhooksStore(), metadata);
},
};
}

View file

@ -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;

View file

@ -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,

View file

@ -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[],

View file

@ -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

View file

@ -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<string, Array<(store: Store, metadata?: IDataObject) => Promise<void>>>
>;
}
}
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 {

View file

@ -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),
},

View file

@ -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 });

View file

@ -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<string, Array<(store: Store, metadata?: IDataObject) => Promise<void>>>
>;
}
namespace JSX {

View file

@ -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);
},
},

View file

@ -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);
}
}
}

View file

@ -1,5 +1,6 @@
export * from './apiUtils';
export * from './canvasUtils';
export * from './externalHooks';
export * from './htmlUtils';
export * from './nodeTypesUtils';
export * from './sortUtils';

View file

@ -22,12 +22,12 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import Logo from '@/components/Logo.vue';
import SSOLogin from '@/components/SSOLogin.vue';
export default Vue.extend({
export default defineComponent({
name: 'AuthView',
components: {
Logo,

View file

@ -18,9 +18,9 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
export default Vue.extend({
export default defineComponent({
name: 'ErrorView',
props: {
messageKey: {

View file

@ -3,10 +3,10 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import ExecutionsList from '@/components/ExecutionsList.vue';
export default Vue.extend({
export default defineComponent({
name: 'ExecutionsView',
components: {
ExecutionsList,

View file

@ -4,12 +4,12 @@
<script lang="ts">
import { IFakeDoor } from '@/Interface';
import Vue from 'vue';
import { defineComponent } from 'vue';
import FeatureComingSoon from '@/components/FeatureComingSoon.vue';
import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui';
export default Vue.extend({
export default defineComponent({
name: 'SettingsFakeDoorView',
components: {
FeatureComingSoon,

View file

@ -15,10 +15,10 @@
</template>
<script lang="ts">
import Vue from 'vue';
import { defineComponent } from 'vue';
import GoBackButton from '@/components/GoBackButton.vue';
export default Vue.extend({
export default defineComponent({
name: 'TemplatesView',
components: {
GoBackButton,

View file

@ -4,16 +4,19 @@ import { setupServer } from '@/__tests__/server';
import { render } from '@testing-library/vue';
import VariablesView from '@/views/VariablesView.vue';
import { useSettingsStore, useUsersStore } from '@/stores';
import { renderComponent } from '@/__tests__/utils';
describe('store', () => {
let server: ReturnType<typeof setupServer>;
let pinia: ReturnType<typeof createPinia>;
beforeAll(() => {
server = setupServer();
});
beforeEach(async () => {
setActivePinia(createPinia());
pinia = createPinia();
setActivePinia(pinia);
await useSettingsStore().getSettings();
await useUsersStore().fetchUsers();
@ -25,13 +28,13 @@ describe('store', () => {
});
it('should render loading state', () => {
const wrapper = render(VariablesView);
const wrapper = renderComponent(VariablesView, { pinia });
expect(wrapper.container.querySelectorAll('.n8n-loading')).toHaveLength(3);
});
it('should render empty state', async () => {
const wrapper = render(VariablesView);
const wrapper = renderComponent(VariablesView, { pinia });
await wrapper.findByTestId('empty-resources-list');
expect(wrapper.getByTestId('empty-resources-list')).toBeVisible();
@ -40,7 +43,7 @@ describe('store', () => {
it('should render variable entries', async () => {
server.createList('variable', 3);
const wrapper = render(VariablesView);
const wrapper = renderComponent(VariablesView, { pinia });
await wrapper.findByTestId('resources-table');
expect(wrapper.getByTestId('resources-table')).toBeVisible();