Skip to content

Commit

Permalink
fix: refactor externalHooks mixin
Browse files Browse the repository at this point in the history
  • Loading branch information
alexgrozav committed Apr 21, 2023
1 parent 82821d7 commit 7ef2510
Show file tree
Hide file tree
Showing 14 changed files with 80 additions and 65 deletions.
8 changes: 8 additions & 0 deletions packages/editor-ui/src/__tests__/utils.ts
Original file line number Diff line number Diff line change
@@ -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) => {
Expand All @@ -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 = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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;
Expand Down Expand Up @@ -148,7 +148,7 @@ const emit = defineEmits<{
}>();
const instance = getCurrentInstance();
const { $externalHooks } = externalHooks.methods;
const externalHooks = useExternalHooks();
const { defaultLocale } = useRootStore();
const { workflowId } = useWorkflowsStore();
Expand Down Expand Up @@ -549,7 +549,7 @@ onUnmounted(() => {
});
watch(filteredNodeTypes, (returnItems) => {
$externalHooks().run('nodeCreateList.filteredNodeTypesComputed', {
externalHooks.run('nodeCreateList.filteredNodeTypesComputed', {
nodeFilter: nodeCreatorStore.itemsFilter,
result: returnItems,
selectedType: nodeCreatorStore.selectedView,
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -124,7 +124,8 @@ const state = reactive({
activeNodeActions: null as INodeTypeDescription | null,
});
const { baseUrl } = useRootStore();
const { $externalHooks } = externalHooks.methods;
const externalHooks = useExternalHooks();
const {
mergedAppNodes,
getActionData,
Expand Down Expand Up @@ -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 });
}
}
Expand Down Expand Up @@ -362,7 +363,7 @@ function trackActionsView() {
trigger_action_count,
};
$externalHooks().run('nodeCreateList.onViewActions', trackingPayload);
externalHooks.run('nodeCreateList.onViewActions', trackingPayload);
telemetry?.trackNodesPanel('nodeCreateList.onViewActions', trackingPayload);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -43,7 +43,7 @@ const emit = defineEmits<{
(event: 'input', value: string): void;
}>();
const { $externalHooks } = externalHooks.methods;
const externalHooks = useExternalHooks();
const state = reactive({
inputRef: null as HTMLInputElement | null,
Expand All @@ -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);
});
Expand Down
3 changes: 1 addition & 2 deletions packages/editor-ui/src/components/RunDataSchema.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
19 changes: 13 additions & 6 deletions packages/editor-ui/src/components/__tests__/VariablesRow.spec.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -33,23 +36,25 @@ describe('VariablesRow', () => {
};

it('should render correctly', () => {
const wrapper = render(VariablesRow, {
const wrapper = renderComponent(VariablesRow, {
props: {
data: environmentVariable,
},
stubs,
pinia,
});

expect(wrapper.html()).toMatchSnapshot();
expect(wrapper.container.querySelectorAll('td')).toHaveLength(4);
});

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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down
8 changes: 4 additions & 4 deletions packages/editor-ui/src/composables/useExternalHooks.ts
Original file line number Diff line number Diff line change
@@ -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);
},
};
}
6 changes: 2 additions & 4 deletions packages/editor-ui/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
31 changes: 3 additions & 28 deletions packages/editor-ui/src/mixins/externalHooks.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,8 @@
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 { defineComponent } from 'vue';

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);
}
}
}
import { runExternalHook } from '@/utils';

export const externalHooks = defineComponent({
methods: {
Expand Down
6 changes: 6 additions & 0 deletions packages/editor-ui/src/shims.d.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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 {
Expand Down
11 changes: 5 additions & 6 deletions packages/editor-ui/src/stores/nodeCreator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -286,14 +287,12 @@ export const useNodeCreatorStore = defineStore(STORES.NODE_CREATOR, {
return storeWatcher;
},
trackActionSelected(action: IUpdateInformation, telemetry?: Telemetry) {
const { $externalHooks } = externalHooks.methods;

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);
},
},
Expand Down
18 changes: 18 additions & 0 deletions packages/editor-ui/src/utils/externalHooks.ts
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
1 change: 1 addition & 0 deletions packages/editor-ui/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './apiUtils';
export * from './canvasUtils';
export * from './externalHooks';
export * from './htmlUtils';
export * from './nodeTypesUtils';
export * from './sortUtils';
Expand Down
Loading

0 comments on commit 7ef2510

Please sign in to comment.