mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
refactor: Migrate externalHooks mixin to composables (no-changelog) (#7930)
## Summary Provide details about your pull request and what it adds, fixes, or changes. Photos and videos are recommended. As part of NodeView refactor, this PR migrates all externalHooks calls to `useExternalHooks` composable. #### How to test the change: 1. Run using env `export N8N_DEPLOYMENT_TYPE=cloud` 2. Hooks should still run as expected ## Issues fixed Include links to Github issue or Community forum post or **Linear ticket**: > Important in order to close automatically and provide context to reviewers https://linear.app/n8n/issue/N8N-6349/externalhooks ## Review / Merge checklist - [x] PR title and summary are descriptive. **Remember, the title automatically goes into the changelog. Use `(no-changelog)` otherwise.** ([conventions](https://github.com/n8n-io/n8n/blob/master/.github/pull_request_title_conventions.md)) - [x] [Docs updated](https://github.com/n8n-io/n8n-docs) or follow-up ticket created. - [x] Tests included. > A bug is not considered fixed, unless a test is added to prevent it from happening again. A feature is not complete without tests. > > *(internal)* You can use Slack commands to trigger [e2e tests](https://www.notion.so/n8n/How-to-use-Test-Instances-d65f49dfc51f441ea44367fb6f67eb0a?pvs=4#a39f9e5ba64a48b58a71d81c837e8227) or [deploy test instance](https://www.notion.so/n8n/How-to-use-Test-Instances-d65f49dfc51f441ea44367fb6f67eb0a?pvs=4#f6a177d32bde4b57ae2da0b8e454bfce) or [deploy early access version on Cloud](https://www.notion.so/n8n/Cloudbot-3dbe779836004972b7057bc989526998?pvs=4#fef2d36ab02247e1a0f65a74f6fb534e).
This commit is contained in:
parent
c461025f70
commit
885dba6f12
|
@ -59,7 +59,6 @@ import { useUsageStore } from '@/stores/usage.store';
|
|||
import { useUsersStore } from '@/stores/users.store';
|
||||
import { useHistoryHelper } from '@/composables/useHistoryHelper';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { runExternalHook } from '@/utils/externalHooks';
|
||||
import { initializeAuthenticatedFeatures } from '@/init';
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -119,7 +118,7 @@ export default defineComponent({
|
|||
void this.checkForNewVersions();
|
||||
void initializeAuthenticatedFeatures();
|
||||
|
||||
void runExternalHook('app.mount');
|
||||
void useExternalHooks().run('app.mount');
|
||||
this.loading = false;
|
||||
},
|
||||
watch: {
|
||||
|
|
|
@ -51,7 +51,6 @@ import type { BulkCommand, Undoable } from '@/models/history';
|
|||
import type { PartialBy, TupleToUnion } from '@/utils/typeHelpers';
|
||||
import type { Component } from 'vue';
|
||||
import type { Scope } from '@n8n/permissions';
|
||||
import type { runExternalHook } from '@/utils/externalHooks';
|
||||
|
||||
export * from 'n8n-design-system/types';
|
||||
|
||||
|
@ -161,10 +160,6 @@ export interface INodeTypesMaxCount {
|
|||
};
|
||||
}
|
||||
|
||||
export interface IExternalHooks {
|
||||
run: typeof runExternalHook;
|
||||
}
|
||||
|
||||
export interface INodeTranslationHeaders {
|
||||
data: {
|
||||
[key: string]: {
|
||||
|
|
|
@ -164,7 +164,7 @@ import {
|
|||
} from '@/utils/nodeTypesUtils';
|
||||
import { isValidCredentialResponse, isCredentialModalState } from '@/utils/typeGuards';
|
||||
import { isExpression, isTestableExpression } from '@/utils/expressions';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
interface NodeAccessMap {
|
||||
[nodeType: string]: ICredentialNodeAccess | null;
|
||||
|
@ -172,7 +172,7 @@ interface NodeAccessMap {
|
|||
|
||||
export default defineComponent({
|
||||
name: 'CredentialEdit',
|
||||
mixins: [nodeHelpers, externalHooks],
|
||||
mixins: [nodeHelpers],
|
||||
components: {
|
||||
CredentialSharing,
|
||||
CredentialConfig,
|
||||
|
@ -198,6 +198,7 @@ export default defineComponent({
|
|||
},
|
||||
setup() {
|
||||
return {
|
||||
externalHooks: useExternalHooks(),
|
||||
...useToast(),
|
||||
...useMessage(),
|
||||
};
|
||||
|
@ -266,7 +267,7 @@ export default defineComponent({
|
|||
}
|
||||
}
|
||||
|
||||
await this.$externalHooks().run('credentialsEdit.credentialModalOpened', {
|
||||
await this.externalHooks.run('credentialsEdit.credentialModalOpened', {
|
||||
credentialType: this.credentialTypeName,
|
||||
isEditingCredential: this.mode === 'edit',
|
||||
activeNode: this.ndvStore.activeNode,
|
||||
|
@ -876,7 +877,7 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
this.$telemetry.track('User saved credentials', trackProperties);
|
||||
await this.$externalHooks().run('credentialEdit.saveCredential', trackProperties);
|
||||
await this.externalHooks.run('credentialEdit.saveCredential', trackProperties);
|
||||
}
|
||||
|
||||
return credential;
|
||||
|
@ -899,7 +900,7 @@ export default defineComponent({
|
|||
return null;
|
||||
}
|
||||
|
||||
await this.$externalHooks().run('credential.saved', {
|
||||
await this.externalHooks.run('credential.saved', {
|
||||
credential_type: credentialDetails.type,
|
||||
credential_id: credential.id,
|
||||
is_new: true,
|
||||
|
@ -933,7 +934,7 @@ export default defineComponent({
|
|||
return null;
|
||||
}
|
||||
|
||||
await this.$externalHooks().run('credential.saved', {
|
||||
await this.externalHooks.run('credential.saved', {
|
||||
credential_type: credentialDetails.type,
|
||||
credential_id: credential.id,
|
||||
is_new: false,
|
||||
|
|
|
@ -61,19 +61,24 @@
|
|||
import { defineComponent } from 'vue';
|
||||
import Modal from './Modal.vue';
|
||||
import { CREDENTIAL_SELECT_MODAL_KEY } from '../constants';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { mapStores } from 'pinia';
|
||||
import { useUIStore } from '@/stores/ui.store';
|
||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { useCredentialsStore } from '@/stores/credentials.store';
|
||||
import { createEventBus } from 'n8n-design-system/utils';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CredentialsSelectModal',
|
||||
mixins: [externalHooks],
|
||||
components: {
|
||||
Modal,
|
||||
},
|
||||
setup() {
|
||||
const externalHooks = useExternalHooks();
|
||||
return {
|
||||
externalHooks,
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
try {
|
||||
await this.credentialsStore.fetchCredentialTypes(false);
|
||||
|
@ -114,7 +119,7 @@ export default defineComponent({
|
|||
};
|
||||
|
||||
this.$telemetry.track('User opened Credential modal', telemetryPayload);
|
||||
void this.$externalHooks().run('credentialsSelectModal.openCredentialType', telemetryPayload);
|
||||
void this.externalHooks.run('credentialsSelectModal.openCredentialType', telemetryPayload);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -287,7 +287,6 @@ import { defineComponent } from 'vue';
|
|||
import { mapStores } from 'pinia';
|
||||
import ExecutionTime from '@/components/ExecutionTime.vue';
|
||||
import ExecutionFilter from '@/components/ExecutionFilter.vue';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { MODAL_CONFIRM, VIEWS, WAIT_TIME_UNLIMITED } from '@/constants';
|
||||
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||
import { executionHelpers } from '@/mixins/executionsHelpers';
|
||||
|
@ -310,10 +309,11 @@ import { useWorkflowsStore } from '@/stores/workflows.store';
|
|||
import { isEmpty } from '@/utils/typesUtils';
|
||||
import { setPageTitle } from '@/utils/htmlUtils';
|
||||
import { executionFilterToQueryFilter } from '@/utils/executionUtils';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ExecutionsList',
|
||||
mixins: [externalHooks, genericHelpers, executionHelpers],
|
||||
mixins: [genericHelpers, executionHelpers],
|
||||
components: {
|
||||
ExecutionTime,
|
||||
ExecutionFilter,
|
||||
|
@ -327,10 +327,12 @@ export default defineComponent({
|
|||
setup() {
|
||||
const i18n = useI18n();
|
||||
const telemetry = useTelemetry();
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
return {
|
||||
i18n,
|
||||
telemetry,
|
||||
externalHooks,
|
||||
...useToast(),
|
||||
...useMessage(),
|
||||
};
|
||||
|
@ -368,7 +370,7 @@ export default defineComponent({
|
|||
async created() {
|
||||
await this.loadWorkflows();
|
||||
|
||||
void this.$externalHooks().run('executionsList.openDialog');
|
||||
void this.externalHooks.run('executionsList.openDialog');
|
||||
this.telemetry.track('User opened Executions log', {
|
||||
workflow_id: this.workflowsStore.workflowId,
|
||||
});
|
||||
|
|
|
@ -68,6 +68,7 @@ import { useSettingsStore } from '@/stores/settings.store';
|
|||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||
import { useTagsStore } from '@/stores/tags.store';
|
||||
import { executionFilterToQueryFilter } from '@/utils/executionUtils';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
// Number of execution pages that are fetched before temporary execution card is shown
|
||||
const MAX_LOADING_ATTEMPTS = 5;
|
||||
|
@ -91,7 +92,10 @@ export default defineComponent({
|
|||
};
|
||||
},
|
||||
setup() {
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
return {
|
||||
externalHooks,
|
||||
...useToast(),
|
||||
...useMessage(),
|
||||
};
|
||||
|
@ -586,7 +590,7 @@ export default defineComponent({
|
|||
|
||||
this.tagsStore.upsertTags(tags);
|
||||
|
||||
void this.$externalHooks().run('workflow.open', { workflowId, workflowName: data.name });
|
||||
void this.externalHooks.run('workflow.open', { workflowId, workflowName: data.name });
|
||||
this.uiStore.stateIsDirty = false;
|
||||
},
|
||||
async addNodes(nodes: INodeUi[], connections?: IConnections) {
|
||||
|
|
|
@ -87,7 +87,6 @@ import VariableSelector from '@/components/VariableSelector.vue';
|
|||
|
||||
import type { IVariableItemSelected } from '@/Interface';
|
||||
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||
|
||||
import { EXPRESSIONS_DOCS_URL } from '@/constants';
|
||||
|
@ -95,14 +94,21 @@ import { EXPRESSIONS_DOCS_URL } from '@/constants';
|
|||
import { debounceHelper } from '@/mixins/debounce';
|
||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { useNDVStore } from '@/stores/ndv.store';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
import { createExpressionTelemetryPayload } from '@/utils/telemetryUtils';
|
||||
|
||||
import type { Segment } from '@/types/expressions';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ExpressionEdit',
|
||||
mixins: [externalHooks, genericHelpers, debounceHelper],
|
||||
mixins: [genericHelpers, debounceHelper],
|
||||
props: ['dialogVisible', 'parameter', 'path', 'modelValue', 'eventSource', 'redactValues'],
|
||||
setup() {
|
||||
const externalHooks = useExternalHooks();
|
||||
return {
|
||||
externalHooks,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
ExpressionEditorModalInput,
|
||||
ExpressionEditorModalOutput,
|
||||
|
@ -152,7 +158,7 @@ export default defineComponent({
|
|||
itemSelected: (variable: IVariableItemSelected) => void;
|
||||
}
|
||||
).itemSelected(eventData);
|
||||
void this.$externalHooks().run('expressionEdit.itemSelected', {
|
||||
void this.externalHooks.run('expressionEdit.itemSelected', {
|
||||
parameter: this.parameter,
|
||||
value: this.modelValue,
|
||||
selectedItem: eventData,
|
||||
|
@ -233,7 +239,7 @@ export default defineComponent({
|
|||
getValue: () => string;
|
||||
}
|
||||
)?.getValue() || '';
|
||||
void this.$externalHooks().run('expressionEdit.dialogVisibleChanged', {
|
||||
void this.externalHooks.run('expressionEdit.dialogVisibleChanged', {
|
||||
dialogVisible: newValue,
|
||||
parameter: this.parameter,
|
||||
value: this.modelValue,
|
||||
|
@ -250,7 +256,7 @@ export default defineComponent({
|
|||
);
|
||||
|
||||
this.$telemetry.track('User closed Expression Editor', telemetryPayload);
|
||||
void this.$externalHooks().run('expressionEdit.closeDialog', telemetryPayload);
|
||||
void this.externalHooks.run('expressionEdit.closeDialog', telemetryPayload);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
@ -41,12 +41,12 @@ export default defineComponent({
|
|||
TabBar,
|
||||
},
|
||||
mixins: [pushConnection, workflowHelpers],
|
||||
setup(props) {
|
||||
setup(props, ctx) {
|
||||
return {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
...pushConnection.setup?.(props),
|
||||
...pushConnection.setup?.(props, ctx),
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
...workflowHelpers.setup?.(props),
|
||||
...workflowHelpers.setup?.(props, ctx),
|
||||
};
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -121,6 +121,7 @@ import { isNavigationFailure } from 'vue-router';
|
|||
import ExecutionsUsage from '@/components/ExecutionsUsage.vue';
|
||||
import MainSidebarSourceControl from '@/components/MainSidebarSourceControl.vue';
|
||||
import { hasPermission } from '@/rbac/permissions';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MainSidebar',
|
||||
|
@ -130,11 +131,14 @@ export default defineComponent({
|
|||
MainSidebarSourceControl,
|
||||
},
|
||||
mixins: [genericHelpers, workflowHelpers, workflowRun, userHelpers, debounceHelper],
|
||||
setup(props) {
|
||||
setup(props, ctx) {
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
return {
|
||||
externalHooks,
|
||||
...useMessage(),
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
...workflowRun.setup?.(props),
|
||||
...workflowRun.setup?.(props, ctx),
|
||||
};
|
||||
},
|
||||
data() {
|
||||
|
@ -349,7 +353,7 @@ export default defineComponent({
|
|||
async mounted() {
|
||||
this.basePath = this.rootStore.baseUrl;
|
||||
if (this.$refs.user) {
|
||||
void this.$externalHooks().run('mainSidebar.mounted', {
|
||||
void this.externalHooks.run('mainSidebar.mounted', {
|
||||
userRef: this.$refs.user as Element,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -156,7 +156,6 @@ import {
|
|||
NOT_DUPLICATABE_NODE_TYPES,
|
||||
WAIT_TIME_UNLIMITED,
|
||||
} from '@/constants';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { nodeBase } from '@/mixins/nodeBase';
|
||||
import { nodeHelpers } from '@/mixins/nodeHelpers';
|
||||
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
||||
|
@ -187,14 +186,17 @@ import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
|||
import { EnableNodeToggleCommand } from '@/models/history';
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||
import { type ContextMenuTarget, useContextMenu } from '@/composables/useContextMenu';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Node',
|
||||
setup() {
|
||||
const contextMenu = useContextMenu();
|
||||
return { contextMenu };
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
return { contextMenu, externalHooks };
|
||||
},
|
||||
mixins: [externalHooks, nodeBase, nodeHelpers, workflowHelpers, pinData, debounceHelper],
|
||||
mixins: [nodeBase, nodeHelpers, workflowHelpers, pinData, debounceHelper],
|
||||
components: {
|
||||
TitledList,
|
||||
FontAwesomeIcon,
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
} from '@/constants';
|
||||
|
||||
import { useUsersStore } from '@/stores/users.store';
|
||||
import { runExternalHook } from '@/utils/externalHooks';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
import { useActions } from '../composables/useActions';
|
||||
import { useKeyboardNavigation } from '../composables/useKeyboardNavigation';
|
||||
|
@ -170,7 +170,7 @@ function trackActionsView() {
|
|||
trigger_action_count,
|
||||
};
|
||||
|
||||
void runExternalHook('nodeCreateList.onViewActions', trackingPayload);
|
||||
void useExternalHooks().run('nodeCreateList.onViewActions', trackingPayload);
|
||||
telemetry?.trackNodesPanel('nodeCreateList.onViewActions', trackingPayload);
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@ function addHttpNode() {
|
|||
if (telemetry) setAddedNodeActionParameters(updateData);
|
||||
|
||||
const app_identifier = actions.value[0].key;
|
||||
void runExternalHook('nodeCreateList.onActionsCustmAPIClicked', {
|
||||
void useExternalHooks().run('nodeCreateList.onActionsCustmAPIClicked', {
|
||||
app_identifier,
|
||||
});
|
||||
telemetry?.trackNodesPanel('nodeCreateList.onActionsCustmAPIClicked', { app_identifier });
|
||||
|
|
|
@ -26,7 +26,7 @@ import type { Telemetry } from '@/plugins/telemetry';
|
|||
import { useNodeCreatorStore } from '@/stores/nodeCreator.store';
|
||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||
import { runExternalHook } from '@/utils/externalHooks';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
import { sortNodeCreateElements, transformNodeType } from '../utils';
|
||||
|
||||
|
@ -255,7 +255,7 @@ export const useActions = () => {
|
|||
source_mode: rootView.toLowerCase(),
|
||||
resource: (action.value as INodeParameters).resource || '',
|
||||
};
|
||||
void runExternalHook('nodeCreateList.addAction', payload);
|
||||
void useExternalHooks().run('nodeCreateList.addAction', payload);
|
||||
telemetry?.trackNodesPanel('nodeCreateList.addAction', payload);
|
||||
}
|
||||
|
||||
|
|
|
@ -147,7 +147,6 @@ import type {
|
|||
import { jsonParse, NodeHelpers, NodeConnectionType } from 'n8n-workflow';
|
||||
import type { IExecutionResponse, INodeUi, IUpdateInformation, TargetItem } from '@/Interface';
|
||||
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { nodeHelpers } from '@/mixins/nodeHelpers';
|
||||
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
||||
|
||||
|
@ -175,10 +174,11 @@ import { useUIStore } from '@/stores/ui.store';
|
|||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { useDeviceSupport } from 'n8n-design-system/composables/useDeviceSupport';
|
||||
import { useMessage } from '@/composables/useMessage';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NodeDetailsView',
|
||||
mixins: [externalHooks, nodeHelpers, workflowHelpers, workflowActivate, pinData],
|
||||
mixins: [nodeHelpers, workflowHelpers, workflowActivate, pinData],
|
||||
components: {
|
||||
NodeSettings,
|
||||
InputPanel,
|
||||
|
@ -198,12 +198,15 @@ export default defineComponent({
|
|||
default: false,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
setup(props, ctx) {
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
return {
|
||||
externalHooks,
|
||||
...useDeviceSupport(),
|
||||
...useMessage(),
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
...workflowActivate.setup?.(props),
|
||||
...workflowActivate.setup?.(props, ctx),
|
||||
};
|
||||
},
|
||||
data() {
|
||||
|
@ -467,7 +470,7 @@ export default defineComponent({
|
|||
this.avgInputRowHeight = 0;
|
||||
|
||||
setTimeout(() => this.ndvStore.setNDVSessionId(), 0);
|
||||
void this.$externalHooks().run('dataDisplay.nodeTypeChanged', {
|
||||
void this.externalHooks.run('dataDisplay.nodeTypeChanged', {
|
||||
nodeSubtitle: this.getNodeSubtitle(node, this.activeNodeType, this.getCurrentWorkflow()),
|
||||
});
|
||||
|
||||
|
@ -691,7 +694,7 @@ export default defineComponent({
|
|||
this.ndvStore.setOutputPanelEditModeEnabled(false);
|
||||
}
|
||||
|
||||
await this.$externalHooks().run('dataDisplay.nodeEditingFinished');
|
||||
await this.externalHooks.run('dataDisplay.nodeEditingFinished');
|
||||
this.$telemetry.track('User closed node modal', {
|
||||
node_type: this.activeNodeType ? this.activeNodeType.name : '',
|
||||
session_id: this.sessionId,
|
||||
|
|
|
@ -39,6 +39,7 @@ import { useNDVStore } from '@/stores/ndv.store';
|
|||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||
import { useMessage } from '@/composables/useMessage';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
inheritAttrs: false,
|
||||
|
@ -68,12 +69,15 @@ export default defineComponent({
|
|||
type: String,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
setup(props, ctx) {
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
return {
|
||||
externalHooks,
|
||||
...useToast(),
|
||||
...useMessage(),
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
...workflowRun.setup?.(props),
|
||||
...workflowRun.setup?.(props, ctx),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -241,7 +245,7 @@ export default defineComponent({
|
|||
session_id: this.ndvStore.sessionId,
|
||||
};
|
||||
this.$telemetry.track('User clicked execute node button', telemetryPayload);
|
||||
await this.$externalHooks().run('nodeExecuteButton.onClick', telemetryPayload);
|
||||
await this.externalHooks.run('nodeExecuteButton.onClick', telemetryPayload);
|
||||
|
||||
await this.runWorkflow({
|
||||
destinationNode: this.nodeName,
|
||||
|
|
|
@ -201,7 +201,6 @@ import NodeSettingsTabs from '@/components/NodeSettingsTabs.vue';
|
|||
import NodeWebhooks from '@/components/NodeWebhooks.vue';
|
||||
import { get, set, unset } from 'lodash-es';
|
||||
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { nodeHelpers } from '@/mixins/nodeHelpers';
|
||||
|
||||
import NodeExecuteButton from './NodeExecuteButton.vue';
|
||||
|
@ -215,10 +214,11 @@ import { RenameNodeCommand } from '@/models/history';
|
|||
import useWorkflowsEEStore from '@/stores/workflows.ee.store';
|
||||
import { useCredentialsStore } from '@/stores/credentials.store';
|
||||
import type { EventBus } from 'n8n-design-system';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NodeSettings',
|
||||
mixins: [externalHooks, nodeHelpers],
|
||||
mixins: [nodeHelpers],
|
||||
components: {
|
||||
NodeTitle,
|
||||
NodeCredentials,
|
||||
|
@ -227,6 +227,12 @@ export default defineComponent({
|
|||
NodeWebhooks,
|
||||
NodeExecuteButton,
|
||||
},
|
||||
setup() {
|
||||
const externalHooks = useExternalHooks();
|
||||
return {
|
||||
externalHooks,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapStores(
|
||||
useHistoryStore,
|
||||
|
@ -676,7 +682,7 @@ export default defineComponent({
|
|||
this.updateNodeCredentialIssues(node);
|
||||
}
|
||||
|
||||
void this.$externalHooks().run('nodeSettings.credentialSelected', { updateInformation });
|
||||
void this.externalHooks.run('nodeSettings.credentialSelected', { updateInformation });
|
||||
},
|
||||
nameChanged(name: string) {
|
||||
if (this.node) {
|
||||
|
@ -775,7 +781,7 @@ export default defineComponent({
|
|||
}
|
||||
}
|
||||
|
||||
void this.$externalHooks().run('nodeSettings.valueChanged', {
|
||||
void this.externalHooks.run('nodeSettings.valueChanged', {
|
||||
parameterPath,
|
||||
newValue,
|
||||
parameters: this.parameters,
|
||||
|
@ -883,7 +889,7 @@ export default defineComponent({
|
|||
|
||||
this.workflowsStore.setNodeParameters(updateInformation);
|
||||
|
||||
void this.$externalHooks().run('nodeSettings.valueChanged', {
|
||||
void this.externalHooks.run('nodeSettings.valueChanged', {
|
||||
parameterPath,
|
||||
newValue,
|
||||
parameters: this.parameters,
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { mapStores } from 'pinia';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import {
|
||||
BUILTIN_NODES_DOCS_URL,
|
||||
COMMUNITY_NODES_INSTALLATION_DOCS_URL,
|
||||
|
@ -23,10 +22,10 @@ import type { INodeTypeDescription } from 'n8n-workflow';
|
|||
import { NodeConnectionType } from 'n8n-workflow';
|
||||
|
||||
import { isCommunityPackageName } from '@/utils/nodeTypesUtils';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NodeSettingsTabs',
|
||||
mixins: [externalHooks],
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
|
@ -37,6 +36,12 @@ export default defineComponent({
|
|||
type: String,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const externalHooks = useExternalHooks();
|
||||
return {
|
||||
externalHooks,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapStores(useNDVStore, useWorkflowsStore),
|
||||
activeNode(): INodeUi | null {
|
||||
|
@ -123,7 +128,7 @@ export default defineComponent({
|
|||
methods: {
|
||||
onTabSelect(tab: string) {
|
||||
if (tab === 'docs' && this.nodeType) {
|
||||
void this.$externalHooks().run('dataDisplay.onDocumentationUrlClick', {
|
||||
void this.externalHooks.run('dataDisplay.onDocumentationUrlClick', {
|
||||
nodeType: this.nodeType as INodeTypeDescription,
|
||||
documentationUrl: this.documentationUrl,
|
||||
});
|
||||
|
|
|
@ -395,7 +395,6 @@ import TextEdit from '@/components/TextEdit.vue';
|
|||
import CodeNodeEditor from '@/components/CodeNodeEditor/CodeNodeEditor.vue';
|
||||
import HtmlEditor from '@/components/HtmlEditor/HtmlEditor.vue';
|
||||
import SqlEditor from '@/components/SqlEditor/SqlEditor.vue';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { nodeHelpers } from '@/mixins/nodeHelpers';
|
||||
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
||||
import { hasExpressionMapping, isValueExpression } from '@/utils/nodeTypesUtils';
|
||||
|
@ -421,12 +420,13 @@ import { createEventBus } from 'n8n-design-system/utils';
|
|||
import { useI18n } from '@/composables/useI18n';
|
||||
import type { N8nInput } from 'n8n-design-system';
|
||||
import { isCredentialOnlyNodeType } from '@/utils/credentialOnlyNodes';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
type Picker = { $emit: (arg0: string, arg1: Date) => void };
|
||||
|
||||
export default defineComponent({
|
||||
name: 'parameter-input',
|
||||
mixins: [externalHooks, nodeHelpers, workflowHelpers, debounceHelper],
|
||||
mixins: [nodeHelpers, workflowHelpers, debounceHelper],
|
||||
components: {
|
||||
CodeNodeEditor,
|
||||
HtmlEditor,
|
||||
|
@ -503,9 +503,11 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const externalHooks = useExternalHooks();
|
||||
const i18n = useI18n();
|
||||
|
||||
return {
|
||||
externalHooks,
|
||||
i18n,
|
||||
};
|
||||
},
|
||||
|
@ -882,7 +884,7 @@ export default defineComponent({
|
|||
this.updateNodeCredentialIssues(node);
|
||||
}
|
||||
|
||||
void this.$externalHooks().run('nodeSettings.credentialSelected', { updateInformation });
|
||||
void this.externalHooks.run('nodeSettings.credentialSelected', { updateInformation });
|
||||
},
|
||||
/**
|
||||
* Check whether a param value must be skipped when collecting node param issues for validation.
|
||||
|
@ -1207,7 +1209,7 @@ export default defineComponent({
|
|||
had_parameter: typeof prevValue === 'string' && prevValue.includes('$parameter'),
|
||||
};
|
||||
this.$telemetry.track('User switched parameter mode', telemetryPayload);
|
||||
void this.$externalHooks().run('parameterInput.modeSwitch', telemetryPayload);
|
||||
void this.externalHooks.run('parameterInput.modeSwitch', telemetryPayload);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
@ -1216,7 +1218,7 @@ export default defineComponent({
|
|||
const remoteParameterOptions = this.$el.querySelectorAll('.remote-parameter-option');
|
||||
|
||||
if (remoteParameterOptions.length > 0) {
|
||||
void this.$externalHooks().run('parameterInput.updated', { remoteParameterOptions });
|
||||
void this.externalHooks.run('parameterInput.updated', { remoteParameterOptions });
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@ -1255,7 +1257,7 @@ export default defineComponent({
|
|||
);
|
||||
}
|
||||
|
||||
void this.$externalHooks().run('parameterInput.mount', {
|
||||
void this.externalHooks.run('parameterInput.mount', {
|
||||
parameter: this.parameter,
|
||||
inputFieldRef: this.$refs.inputField as InstanceType<typeof N8nInput>,
|
||||
});
|
||||
|
|
|
@ -91,7 +91,6 @@ import type {
|
|||
import type { BaseTextKey } from '@/plugins/i18n';
|
||||
import { useNDVStore } from '@/stores/ndv.store';
|
||||
import { useSegment } from '@/stores/segment.store';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { getMappedResult } from '@/utils/mappingUtils';
|
||||
import { createEventBus } from 'n8n-design-system/utils';
|
||||
|
||||
|
@ -99,7 +98,6 @@ const DISPLAY_MODES_WITH_DATA_MAPPING = ['table', 'json', 'schema'];
|
|||
|
||||
export default defineComponent({
|
||||
name: 'parameter-input-full',
|
||||
mixins: [externalHooks],
|
||||
components: {
|
||||
ParameterOptions,
|
||||
DraggableTarget,
|
||||
|
|
|
@ -139,6 +139,7 @@ import { useRootStore } from '@/stores/n8nRoot.store';
|
|||
import { useUsersStore } from '@/stores/users.store';
|
||||
import { createEventBus } from 'n8n-design-system/utils';
|
||||
import { usePostHog } from '@/stores/posthog.store';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PersonalizationModal',
|
||||
|
@ -162,7 +163,10 @@ export default defineComponent({
|
|||
};
|
||||
},
|
||||
setup() {
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
return {
|
||||
externalHooks,
|
||||
...useToast(),
|
||||
};
|
||||
},
|
||||
|
@ -642,7 +646,7 @@ export default defineComponent({
|
|||
personalization_survey_n8n_version: this.rootStore.versionCli,
|
||||
};
|
||||
|
||||
await this.$externalHooks().run(
|
||||
await this.externalHooks.run(
|
||||
'personalizationModal.onSubmit',
|
||||
survey as IPersonalizationLatestVersion,
|
||||
);
|
||||
|
|
|
@ -605,7 +605,6 @@ import {
|
|||
import BinaryDataDisplay from '@/components/BinaryDataDisplay.vue';
|
||||
import NodeErrorView from '@/components/Error/NodeErrorView.vue';
|
||||
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||
import { nodeHelpers } from '@/mixins/nodeHelpers';
|
||||
import { pinData } from '@/mixins/pinData';
|
||||
|
@ -620,6 +619,7 @@ import { useNDVStore } from '@/stores/ndv.store';
|
|||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
import { isObject } from 'lodash-es';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
const RunDataTable = defineAsyncComponent(async () => import('@/components/RunDataTable.vue'));
|
||||
const RunDataJson = defineAsyncComponent(async () => import('@/components/RunDataJson.vue'));
|
||||
|
@ -633,7 +633,7 @@ export type EnterEditModeArgs = {
|
|||
|
||||
export default defineComponent({
|
||||
name: 'RunData',
|
||||
mixins: [externalHooks, genericHelpers, nodeHelpers, pinData],
|
||||
mixins: [genericHelpers, nodeHelpers, pinData],
|
||||
components: {
|
||||
BinaryDataDisplay,
|
||||
NodeErrorView,
|
||||
|
@ -699,7 +699,10 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
return {
|
||||
externalHooks,
|
||||
...useToast(),
|
||||
};
|
||||
},
|
||||
|
@ -1134,7 +1137,7 @@ export default defineComponent({
|
|||
view: !this.hasNodeRun && !this.hasPinData ? 'none' : this.displayMode,
|
||||
};
|
||||
|
||||
void this.$externalHooks().run('runData.onTogglePinData', telemetryPayload);
|
||||
void this.externalHooks.run('runData.onTogglePinData', telemetryPayload);
|
||||
this.$telemetry.track('User clicked pin data icon', telemetryPayload);
|
||||
}
|
||||
|
||||
|
@ -1244,7 +1247,7 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
this.closeBinaryDataDisplay();
|
||||
void this.$externalHooks().run('runData.displayModeChanged', {
|
||||
void this.externalHooks.run('runData.displayModeChanged', {
|
||||
newValue: displayMode,
|
||||
oldValue: previous,
|
||||
});
|
||||
|
|
|
@ -79,13 +79,13 @@ import { isString } from '@/utils/typeGuards';
|
|||
import { highlightText, sanitizeHtml } from '@/utils/htmlUtils';
|
||||
import { shorten } from '@/utils/typesUtils';
|
||||
import type { INodeUi } from '@/Interface';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { mapStores } from 'pinia';
|
||||
import { useNDVStore } from '@/stores/ndv.store';
|
||||
import MappingPill from './MappingPill.vue';
|
||||
import { getMappedExpression } from '@/utils/mappingUtils';
|
||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { nonExistingJsonPath } from '@/constants';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
const RunDataJsonActions = defineAsyncComponent(
|
||||
async () => import('@/components/RunDataJsonActions.vue'),
|
||||
|
@ -93,7 +93,6 @@ const RunDataJsonActions = defineAsyncComponent(
|
|||
|
||||
export default defineComponent({
|
||||
name: 'run-data-json',
|
||||
mixins: [externalHooks],
|
||||
components: {
|
||||
VueJsonPretty,
|
||||
Draggable,
|
||||
|
@ -133,11 +132,14 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
const selectedJsonPath = ref(nonExistingJsonPath);
|
||||
const draggingPath = ref<null | string>(null);
|
||||
const displayMode = ref('json');
|
||||
|
||||
return {
|
||||
externalHooks,
|
||||
selectedJsonPath,
|
||||
draggingPath,
|
||||
displayMode,
|
||||
|
@ -190,7 +192,7 @@ export default defineComponent({
|
|||
};
|
||||
|
||||
setTimeout(() => {
|
||||
void this.$externalHooks().run('runDataJson.onDragEnd', telemetryPayload);
|
||||
void this.externalHooks.run('runDataJson.onDragEnd', telemetryPayload);
|
||||
this.$telemetry.track('User dragged data for mapping', telemetryPayload);
|
||||
}, 1000); // ensure dest data gets set if drop
|
||||
},
|
||||
|
|
|
@ -7,10 +7,11 @@ import { useNDVStore } from '@/stores/ndv.store';
|
|||
import { telemetry } from '@/plugins/telemetry';
|
||||
import type { IDataObject } from 'n8n-workflow';
|
||||
import { isEmpty } from '@/utils/typesUtils';
|
||||
import { runExternalHook } from '@/utils/externalHooks';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
import { i18n } from '@/plugins/i18n';
|
||||
import MappingPill from './MappingPill.vue';
|
||||
import { useDataSchema } from '@/composables/useDataSchema';
|
||||
|
||||
type Props = {
|
||||
data: IDataObject[];
|
||||
mappingEnabled: boolean;
|
||||
|
@ -59,7 +60,7 @@ const onDragEnd = (el: HTMLElement) => {
|
|||
...mappingTelemetry,
|
||||
};
|
||||
|
||||
void runExternalHook('runDataJson.onDragEnd', telemetryPayload);
|
||||
void useExternalHooks().run('runDataJson.onDragEnd', telemetryPayload);
|
||||
|
||||
telemetry.track('User dragged data for mapping', telemetryPayload);
|
||||
}, 1000); // ensure dest data gets set if drop
|
||||
|
|
|
@ -166,11 +166,11 @@ import { highlightText, sanitizeHtml } from '@/utils/htmlUtils';
|
|||
import { getPairedItemId } from '@/utils/pairedItemUtils';
|
||||
import type { GenericValue, IDataObject, INodeExecutionData } from 'n8n-workflow';
|
||||
import Draggable from './Draggable.vue';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { useNDVStore } from '@/stores/ndv.store';
|
||||
import MappingPill from './MappingPill.vue';
|
||||
import { getMappedExpression } from '@/utils/mappingUtils';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
const MAX_COLUMNS_LIMIT = 40;
|
||||
|
||||
|
@ -178,7 +178,6 @@ type DraggableRef = InstanceType<typeof Draggable>;
|
|||
|
||||
export default defineComponent({
|
||||
name: 'run-data-table',
|
||||
mixins: [externalHooks],
|
||||
components: { Draggable, MappingPill },
|
||||
props: {
|
||||
node: {
|
||||
|
@ -212,6 +211,12 @@ export default defineComponent({
|
|||
type: String,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const externalHooks = useExternalHooks();
|
||||
return {
|
||||
externalHooks,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeColumn: -1,
|
||||
|
@ -429,7 +434,7 @@ export default defineComponent({
|
|||
...mappingTelemetry,
|
||||
};
|
||||
|
||||
void this.$externalHooks().run('runDataTable.onDragEnd', telemetryPayload);
|
||||
void this.externalHooks.run('runDataTable.onDragEnd', telemetryPayload);
|
||||
|
||||
this.$telemetry.track('User dragged data for mapping', telemetryPayload);
|
||||
}, 1000); // ensure dest data gets set if drop
|
||||
|
|
|
@ -104,7 +104,6 @@
|
|||
import { defineComponent, ref } from 'vue';
|
||||
import { mapStores } from 'pinia';
|
||||
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { nodeBase } from '@/mixins/nodeBase';
|
||||
import { nodeHelpers } from '@/mixins/nodeHelpers';
|
||||
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
||||
|
@ -126,7 +125,7 @@ import { useContextMenu } from '@/composables/useContextMenu';
|
|||
|
||||
export default defineComponent({
|
||||
name: 'Sticky',
|
||||
mixins: [externalHooks, nodeBase, nodeHelpers, workflowHelpers],
|
||||
mixins: [nodeBase, nodeHelpers, workflowHelpers],
|
||||
setup() {
|
||||
const colorPopoverTrigger = ref<HTMLDivElement>();
|
||||
const forceActions = ref(false);
|
||||
|
@ -139,6 +138,7 @@ export default defineComponent({
|
|||
colorPopoverTrigger.value?.click();
|
||||
}
|
||||
});
|
||||
|
||||
return { colorPopoverTrigger, contextMenu, forceActions, setForceActions };
|
||||
},
|
||||
props: {
|
||||
|
|
|
@ -9,11 +9,9 @@ import { useRootStore } from '@/stores/n8nRoot.store';
|
|||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { useUsersStore } from '@/stores/users.store';
|
||||
import type { ITelemetrySettings } from 'n8n-workflow';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Telemetry',
|
||||
mixins: [externalHooks],
|
||||
data() {
|
||||
return {
|
||||
isTelemetryInitialized: false,
|
||||
|
|
|
@ -62,11 +62,9 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import type { IVariableSelectorOption, IVariableItemSelected } from '@/Interface';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'VariableSelectorItem',
|
||||
mixins: [externalHooks],
|
||||
props: ['allowParentSelect', 'extendAll', 'item', 'redactValues'],
|
||||
mounted() {
|
||||
if (this.extended) return;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { mapStores } from 'pinia';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import PushConnectionTracker from '@/components/PushConnectionTracker.vue';
|
||||
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||
import { executionHelpers } from '@/mixins/executionsHelpers';
|
||||
|
@ -38,7 +37,7 @@ import WorkerCard from './Workers/WorkerCard.ee.vue';
|
|||
// eslint-disable-next-line import/no-default-export
|
||||
export default defineComponent({
|
||||
name: 'WorkerList',
|
||||
mixins: [pushConnection, externalHooks, genericHelpers, executionHelpers],
|
||||
mixins: [pushConnection, genericHelpers, executionHelpers],
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/naming-convention
|
||||
components: { PushConnectionTracker, WorkerCard },
|
||||
props: {
|
||||
|
@ -47,11 +46,13 @@ export default defineComponent({
|
|||
default: true,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
setup(props, ctx) {
|
||||
const i18n = useI18n();
|
||||
return {
|
||||
i18n,
|
||||
...useToast(),
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
...pushConnection.setup?.(props, ctx),
|
||||
};
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -63,11 +63,11 @@ export default defineComponent({
|
|||
name: 'WorkflowActivator',
|
||||
props: ['workflowActive', 'workflowId'],
|
||||
mixins: [workflowActivate],
|
||||
setup(props) {
|
||||
setup(props, ctx) {
|
||||
return {
|
||||
...useToast(),
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
...workflowActivate.setup?.(props),
|
||||
...workflowActivate.setup?.(props, ctx),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
|
@ -133,6 +133,7 @@ import { createEventBus } from 'n8n-design-system/utils';
|
|||
import type { IDataObject, INodeType, INode, ITaskData } from 'n8n-workflow';
|
||||
import { NodeHelpers, NodeConnectionType } from 'n8n-workflow';
|
||||
import type { INodeUi } from '@/Interface';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
const RunDataAi = defineAsyncComponent(async () => import('@/components/RunDataAi/RunDataAi.vue'));
|
||||
|
||||
|
@ -160,11 +161,14 @@ export default defineComponent({
|
|||
Modal,
|
||||
RunDataAi,
|
||||
},
|
||||
setup(props) {
|
||||
setup(props, ctx) {
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
return {
|
||||
externalHooks,
|
||||
...useToast(),
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
...workflowRun.setup?.(props),
|
||||
...workflowRun.setup?.(props, ctx),
|
||||
};
|
||||
},
|
||||
data() {
|
||||
|
@ -479,7 +483,7 @@ export default defineComponent({
|
|||
},
|
||||
closeDialog() {
|
||||
this.modalBus.emit('close');
|
||||
void this.$externalHooks().run('workflowSettings.dialogVisibleChanged', {
|
||||
void this.externalHooks.run('workflowSettings.dialogVisibleChanged', {
|
||||
dialogVisible: false,
|
||||
});
|
||||
},
|
||||
|
|
|
@ -355,7 +355,6 @@
|
|||
import { defineComponent } from 'vue';
|
||||
import { mapStores } from 'pinia';
|
||||
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
import type {
|
||||
|
@ -383,15 +382,19 @@ import { useWorkflowsStore } from '@/stores/workflows.store';
|
|||
import { createEventBus } from 'n8n-design-system/utils';
|
||||
import type { IPermissions } from '@/permissions';
|
||||
import { getWorkflowPermissions } from '@/permissions';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'WorkflowSettings',
|
||||
mixins: [externalHooks, genericHelpers],
|
||||
mixins: [genericHelpers],
|
||||
components: {
|
||||
Modal,
|
||||
},
|
||||
setup() {
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
return {
|
||||
externalHooks,
|
||||
...useToast(),
|
||||
};
|
||||
},
|
||||
|
@ -561,7 +564,7 @@ export default defineComponent({
|
|||
this.timeoutHMS = this.convertToHMS(workflowSettings.executionTimeout);
|
||||
this.isLoading = false;
|
||||
|
||||
void this.$externalHooks().run('workflowSettings.dialogVisibleChanged', {
|
||||
void this.externalHooks.run('workflowSettings.dialogVisibleChanged', {
|
||||
dialogVisible: true,
|
||||
});
|
||||
this.$telemetry.track('User opened workflow settings', {
|
||||
|
@ -576,7 +579,7 @@ export default defineComponent({
|
|||
},
|
||||
closeDialog() {
|
||||
this.modalBus.emit('close');
|
||||
void this.$externalHooks().run('workflowSettings.dialogVisibleChanged', {
|
||||
void this.externalHooks.run('workflowSettings.dialogVisibleChanged', {
|
||||
dialogVisible: false,
|
||||
});
|
||||
},
|
||||
|
@ -852,7 +855,7 @@ export default defineComponent({
|
|||
|
||||
this.closeDialog();
|
||||
|
||||
void this.$externalHooks().run('workflowSettings.saveSettings', { oldSettings });
|
||||
void this.externalHooks.run('workflowSettings.saveSettings', { oldSettings });
|
||||
this.$telemetry.track('User updated workflow settings', {
|
||||
workflow_id: this.workflowsStore.workflowId,
|
||||
});
|
||||
|
|
|
@ -1,7 +1,38 @@
|
|||
import type { IExternalHooks } from '@/Interface';
|
||||
import { runExternalHook } from '@/utils/externalHooks';
|
||||
import type { IDataObject } from 'n8n-workflow';
|
||||
import type {
|
||||
ExternalHooks,
|
||||
ExternalHooksKey,
|
||||
ExternalHooksGenericContext,
|
||||
ExtractExternalHooksMethodPayloadFromKey,
|
||||
} from '@/types/externalHooks';
|
||||
import { useWebhooksStore } from '@/stores/webhooks.store';
|
||||
|
||||
export function useExternalHooks(): IExternalHooks {
|
||||
export async function runExternalHook<T extends ExternalHooksKey>(
|
||||
eventName: T,
|
||||
metadata?: ExtractExternalHooksMethodPayloadFromKey<T>,
|
||||
) {
|
||||
if (!window.n8nExternalHooks) {
|
||||
return;
|
||||
}
|
||||
|
||||
const store = useWebhooksStore();
|
||||
|
||||
const [resource, operator] = eventName.split('.') as [
|
||||
keyof ExternalHooks,
|
||||
keyof ExternalHooks[keyof ExternalHooks],
|
||||
];
|
||||
|
||||
const context = window.n8nExternalHooks[resource] as ExternalHooksGenericContext;
|
||||
if (context?.[operator]) {
|
||||
const hookMethods = context[operator];
|
||||
|
||||
for (const hookMethod of hookMethods) {
|
||||
await hookMethod(store, metadata as IDataObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function useExternalHooks() {
|
||||
return {
|
||||
run: runExternalHook,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,27 @@
|
|||
import { extendExternalHooks } from '@/mixins/externalHooks';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import type { ExternalHooks, ExternalHooksGenericContext } from '@/types';
|
||||
|
||||
export function extendExternalHooks(hooksExtension: PartialDeep<ExternalHooks>) {
|
||||
if (typeof window.n8nExternalHooks === 'undefined') {
|
||||
window.n8nExternalHooks = {};
|
||||
}
|
||||
|
||||
for (const resource of Object.keys(hooksExtension) as Array<keyof ExternalHooks>) {
|
||||
if (typeof window.n8nExternalHooks[resource] === 'undefined') {
|
||||
window.n8nExternalHooks[resource] = {};
|
||||
}
|
||||
|
||||
const extensionContext = hooksExtension[resource] as ExternalHooksGenericContext;
|
||||
const context = window.n8nExternalHooks[resource] as ExternalHooksGenericContext;
|
||||
for (const operator of Object.keys(extensionContext)) {
|
||||
if (typeof context[operator] === 'undefined') {
|
||||
context[operator] = [];
|
||||
}
|
||||
|
||||
context[operator].push(...extensionContext[operator]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let cloudHooksInitialized = false;
|
||||
export async function initializeCloudHooks() {
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
import type { IExternalHooks } from '@/Interface';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import type { ExternalHooks, ExternalHooksGenericContext } from '@/types';
|
||||
import { defineComponent } from 'vue';
|
||||
import { runExternalHook } from '@/utils/externalHooks';
|
||||
|
||||
export function extendExternalHooks(hooksExtension: PartialDeep<ExternalHooks>) {
|
||||
if (typeof window.n8nExternalHooks === 'undefined') {
|
||||
window.n8nExternalHooks = {};
|
||||
}
|
||||
|
||||
for (const resource of Object.keys(hooksExtension) as Array<keyof ExternalHooks>) {
|
||||
if (typeof window.n8nExternalHooks[resource] === 'undefined') {
|
||||
window.n8nExternalHooks[resource] = {};
|
||||
}
|
||||
|
||||
const extensionContext = hooksExtension[resource] as ExternalHooksGenericContext;
|
||||
const context = window.n8nExternalHooks[resource] as ExternalHooksGenericContext;
|
||||
for (const operator of Object.keys(extensionContext)) {
|
||||
if (typeof context[operator] === 'undefined') {
|
||||
context[operator] = [];
|
||||
}
|
||||
|
||||
context[operator].push(...extensionContext[operator]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const externalHooks = defineComponent({
|
||||
methods: {
|
||||
$externalHooks(): IExternalHooks {
|
||||
return {
|
||||
run: runExternalHook,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
|
@ -13,6 +13,7 @@ import { useWorkflowsStore } from '@/stores/workflows.store';
|
|||
import { useNDVStore } from '@/stores/ndv.store';
|
||||
import { NodeConnectionType, NodeHelpers, jsonParse, jsonStringify } from 'n8n-workflow';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export type PinDataSource =
|
||||
| 'pin-icon-click'
|
||||
|
@ -168,7 +169,7 @@ export const pinData = defineComponent({
|
|||
view: this.displayMode,
|
||||
run_index: this.runIndex,
|
||||
};
|
||||
void this.$externalHooks().run('runData.onDataPinningSuccess', telemetryPayload);
|
||||
void useExternalHooks().run('runData.onDataPinningSuccess', telemetryPayload);
|
||||
this.$telemetry.track('Ndv data pinning success', telemetryPayload);
|
||||
},
|
||||
onDataPinningError({
|
||||
|
|
|
@ -5,7 +5,6 @@ import type {
|
|||
IPushDataExecutionFinished,
|
||||
} from '@/Interface';
|
||||
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { nodeHelpers } from '@/mixins/nodeHelpers';
|
||||
import { useTitleChange } from '@/composables/useTitleChange';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
|
@ -39,6 +38,7 @@ import { defineComponent } from 'vue';
|
|||
import { useOrchestrationStore } from '@/stores/orchestration.store';
|
||||
import { usePushConnectionStore } from '@/stores/pushConnection.store';
|
||||
import { useCollaborationStore } from '@/stores/collaboration.store';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export const pushConnection = defineComponent({
|
||||
setup() {
|
||||
|
@ -52,7 +52,7 @@ export const pushConnection = defineComponent({
|
|||
void this.pushMessageReceived(message);
|
||||
});
|
||||
},
|
||||
mixins: [externalHooks, nodeHelpers, workflowHelpers],
|
||||
mixins: [nodeHelpers, workflowHelpers],
|
||||
data() {
|
||||
return {
|
||||
retryTimeout: null as NodeJS.Timeout | null,
|
||||
|
@ -518,7 +518,7 @@ export const pushConnection = defineComponent({
|
|||
runDataExecuted.data.resultData.runData[lastNodeExecuted][0].data!.main[0]!.length;
|
||||
}
|
||||
|
||||
void this.$externalHooks().run('pushConnection.executionFinished', {
|
||||
void useExternalHooks().run('pushConnection.executionFinished', {
|
||||
itemsCount,
|
||||
nodeName: runDataExecuted.data.resultData.lastNodeExecuted,
|
||||
errorMessage: runDataExecutedErrorMessage,
|
||||
|
|
|
@ -2,7 +2,6 @@ import { defineComponent } from 'vue';
|
|||
import { mapStores } from 'pinia';
|
||||
import { useStorage } from '@/composables/useStorage';
|
||||
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
|
||||
|
@ -14,9 +13,10 @@ import {
|
|||
import { useUIStore } from '@/stores/ui.store';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export const workflowActivate = defineComponent({
|
||||
mixins: [externalHooks, workflowHelpers],
|
||||
mixins: [workflowHelpers],
|
||||
setup() {
|
||||
return {
|
||||
...useToast(),
|
||||
|
@ -64,7 +64,7 @@ export const workflowActivate = defineComponent({
|
|||
ndv_input: telemetrySource === 'ndv',
|
||||
};
|
||||
this.$telemetry.track('User set workflow active status', telemetryPayload);
|
||||
void this.$externalHooks().run('workflowActivate.updateWorkflowActivation', telemetryPayload);
|
||||
void useExternalHooks().run('workflowActivate.updateWorkflowActivation', telemetryPayload);
|
||||
|
||||
try {
|
||||
if (isWorkflowActive && newActiveState) {
|
||||
|
@ -111,7 +111,7 @@ export const workflowActivate = defineComponent({
|
|||
const activationEventName = isCurrentWorkflow
|
||||
? 'workflow.activeChangeCurrent'
|
||||
: 'workflow.activeChange';
|
||||
void this.$externalHooks().run(activationEventName, {
|
||||
void useExternalHooks().run(activationEventName, {
|
||||
workflowId: currWorkflowId,
|
||||
active: newActiveState,
|
||||
});
|
||||
|
|
|
@ -47,7 +47,6 @@ import type {
|
|||
|
||||
import { useMessage } from '@/composables/useMessage';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||
import { nodeHelpers } from '@/mixins/nodeHelpers';
|
||||
|
||||
|
@ -68,6 +67,7 @@ import { getSourceItems } from '@/utils/pairedItemUtils';
|
|||
import { v4 as uuid } from 'uuid';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { getCredentialTypeName, isCredentialOnlyNodeType } from '@/utils/credentialOnlyNodes';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export function getParentMainInputNode(workflow: Workflow, node: INode): INode {
|
||||
const nodeType = useNodeTypesStore().getNodeType(node.type);
|
||||
|
@ -474,7 +474,7 @@ export function executeData(
|
|||
}
|
||||
|
||||
export const workflowHelpers = defineComponent({
|
||||
mixins: [externalHooks, nodeHelpers, genericHelpers],
|
||||
mixins: [nodeHelpers, genericHelpers],
|
||||
setup() {
|
||||
return {
|
||||
...useToast(),
|
||||
|
@ -912,7 +912,7 @@ export const workflowHelpers = defineComponent({
|
|||
|
||||
this.uiStore.stateIsDirty = false;
|
||||
this.uiStore.removeActiveAction('workflowSaving');
|
||||
void this.$externalHooks().run('workflow.afterUpdate', { workflowData });
|
||||
void useExternalHooks().run('workflow.afterUpdate', { workflowData });
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
|
@ -1077,7 +1077,7 @@ export const workflowHelpers = defineComponent({
|
|||
|
||||
this.uiStore.removeActiveAction('workflowSaving');
|
||||
this.uiStore.stateIsDirty = false;
|
||||
void this.$externalHooks().run('workflow.afterUpdate', { workflowData });
|
||||
void useExternalHooks().run('workflow.afterUpdate', { workflowData });
|
||||
|
||||
getCurrentWorkflow(true); // refresh cache
|
||||
return true;
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
} from 'n8n-workflow';
|
||||
|
||||
import { useToast } from '@/composables/useToast';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
||||
|
||||
import { useTitleChange } from '@/composables/useTitleChange';
|
||||
|
@ -20,9 +19,10 @@ import { useUIStore } from '@/stores/ui.store';
|
|||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { FORM_TRIGGER_NODE_TYPE } from '@/constants';
|
||||
import { openPopUpWindow } from '@/utils/executionUtils';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export const workflowRun = defineComponent({
|
||||
mixins: [externalHooks, workflowHelpers],
|
||||
mixins: [workflowHelpers],
|
||||
setup() {
|
||||
return {
|
||||
...useTitleChange(),
|
||||
|
@ -125,7 +125,7 @@ export const workflowRun = defineComponent({
|
|||
duration: 0,
|
||||
});
|
||||
this.titleSet(workflow.name as string, 'ERROR');
|
||||
void this.$externalHooks().run('workflowRun.runError', {
|
||||
void useExternalHooks().run('workflowRun.runError', {
|
||||
errorMessages,
|
||||
nodeName: options.destinationNode,
|
||||
});
|
||||
|
@ -287,7 +287,7 @@ export const workflowRun = defineComponent({
|
|||
}
|
||||
}
|
||||
|
||||
await this.$externalHooks().run('workflowRun.runWorkflow', {
|
||||
await useExternalHooks().run('workflowRun.runWorkflow', {
|
||||
nodeName: options.destinationNode,
|
||||
source: options.source,
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@ import type {
|
|||
RouteLocationNormalized,
|
||||
} from 'vue-router';
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import { runExternalHook } from '@/utils/externalHooks';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { useTemplatesStore } from '@/stores/templates.store';
|
||||
import { useUIStore } from '@/stores/ui.store';
|
||||
|
@ -828,7 +828,7 @@ router.afterEach((to, from) => {
|
|||
* Run external hooks
|
||||
*/
|
||||
|
||||
void runExternalHook('main.routeChange', { from, to });
|
||||
void useExternalHooks().run('main.routeChange', { from, to });
|
||||
|
||||
/**
|
||||
* Track current view for telemetry
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
import type { IDataObject } from 'n8n-workflow';
|
||||
import type {
|
||||
ExternalHooks,
|
||||
ExternalHooksKey,
|
||||
ExternalHooksGenericContext,
|
||||
ExtractExternalHooksMethodPayloadFromKey,
|
||||
} from '@/types/externalHooks';
|
||||
import { useWebhooksStore } from '@/stores/webhooks.store';
|
||||
|
||||
export async function runExternalHook<T extends ExternalHooksKey>(
|
||||
eventName: T,
|
||||
metadata?: ExtractExternalHooksMethodPayloadFromKey<T>,
|
||||
) {
|
||||
if (!window.n8nExternalHooks) {
|
||||
return;
|
||||
}
|
||||
|
||||
const store = useWebhooksStore();
|
||||
|
||||
const [resource, operator] = eventName.split('.') as [
|
||||
keyof ExternalHooks,
|
||||
keyof ExternalHooks[keyof ExternalHooks],
|
||||
];
|
||||
|
||||
const context = window.n8nExternalHooks[resource] as ExternalHooksGenericContext;
|
||||
if (context?.[operator]) {
|
||||
const hookMethods = context[operator];
|
||||
|
||||
for (const hookMethod of hookMethods) {
|
||||
await hookMethod(store, metadata as IDataObject);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -235,7 +235,6 @@ import {
|
|||
TIME,
|
||||
} from '@/constants';
|
||||
import { copyPaste } from '@/mixins/copyPaste';
|
||||
import { externalHooks } from '@/mixins/externalHooks';
|
||||
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||
import { moveNodeWorkflow } from '@/mixins/moveNodeWorkflow';
|
||||
import { nodeHelpers } from '@/mixins/nodeHelpers';
|
||||
|
@ -366,6 +365,7 @@ import {
|
|||
import { sourceControlEventBus } from '@/event-bus/source-control';
|
||||
import { getConnectorPaintStyleData, OVERLAY_ENDPOINT_ARROW_ID } from '@/utils/nodeViewUtils';
|
||||
import { useViewStacks } from '@/components/Node/NodeCreator/composables/useViewStacks';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
interface AddNodeOptions {
|
||||
position?: XYPosition;
|
||||
|
@ -380,7 +380,6 @@ export default defineComponent({
|
|||
name: 'NodeView',
|
||||
mixins: [
|
||||
copyPaste,
|
||||
externalHooks,
|
||||
genericHelpers,
|
||||
moveNodeWorkflow,
|
||||
workflowHelpers,
|
||||
|
@ -399,7 +398,8 @@ export default defineComponent({
|
|||
CanvasControls,
|
||||
ContextMenu,
|
||||
},
|
||||
setup(props) {
|
||||
setup(props, ctx) {
|
||||
const externalHooks = useExternalHooks();
|
||||
const locale = useI18n();
|
||||
const contextMenu = useContextMenu();
|
||||
const dataSchema = useDataSchema();
|
||||
|
@ -408,6 +408,7 @@ export default defineComponent({
|
|||
locale,
|
||||
contextMenu,
|
||||
dataSchema,
|
||||
externalHooks,
|
||||
...useCanvasMouseSelect(),
|
||||
...useGlobalLinkActions(),
|
||||
...useTitleChange(),
|
||||
|
@ -416,7 +417,7 @@ export default defineComponent({
|
|||
...useUniqueNodeName(),
|
||||
...useExecutionDebugging(),
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
...workflowRun.setup?.(props),
|
||||
...workflowRun.setup?.(props, ctx),
|
||||
};
|
||||
},
|
||||
errorCaptured: (err, vm, info) => {
|
||||
|
@ -775,7 +776,7 @@ export default defineComponent({
|
|||
session_id: this.ndvStore.sessionId,
|
||||
};
|
||||
this.$telemetry.track('User clicked execute node button', telemetryPayload);
|
||||
void this.$externalHooks().run('nodeView.onRunNode', telemetryPayload);
|
||||
void this.externalHooks.run('nodeView.onRunNode', telemetryPayload);
|
||||
void this.runWorkflow({ destinationNode: nodeName, source });
|
||||
},
|
||||
async onOpenChat() {
|
||||
|
@ -783,7 +784,7 @@ export default defineComponent({
|
|||
workflow_id: this.workflowsStore.workflowId,
|
||||
};
|
||||
this.$telemetry.track('User clicked chat open button', telemetryPayload);
|
||||
void this.$externalHooks().run('nodeView.onOpenChat', telemetryPayload);
|
||||
void this.externalHooks.run('nodeView.onOpenChat', telemetryPayload);
|
||||
this.uiStore.openModal(WORKFLOW_LM_CHAT_MODAL_KEY);
|
||||
},
|
||||
async onRunWorkflow() {
|
||||
|
@ -796,7 +797,7 @@ export default defineComponent({
|
|||
),
|
||||
};
|
||||
this.$telemetry.track('User clicked execute workflow button', telemetryPayload);
|
||||
void this.$externalHooks().run('nodeView.onRunWorkflow', telemetryPayload);
|
||||
void this.externalHooks.run('nodeView.onRunWorkflow', telemetryPayload);
|
||||
});
|
||||
|
||||
await this.runWorkflow({});
|
||||
|
@ -950,7 +951,7 @@ export default defineComponent({
|
|||
await this.$nextTick();
|
||||
this.canvasStore.zoomToFit();
|
||||
this.uiStore.stateIsDirty = false;
|
||||
void this.$externalHooks().run('execution.open', {
|
||||
void this.externalHooks.run('execution.open', {
|
||||
workflowId: data.workflowData.id,
|
||||
workflowName: data.workflowData.name,
|
||||
executionId,
|
||||
|
@ -1030,7 +1031,7 @@ export default defineComponent({
|
|||
|
||||
let data: IWorkflowTemplate | undefined;
|
||||
try {
|
||||
void this.$externalHooks().run('template.requested', { templateId });
|
||||
void this.externalHooks.run('template.requested', { templateId });
|
||||
data = await this.templatesStore.getFixedWorkflowTemplate(templateId);
|
||||
|
||||
if (!data) {
|
||||
|
@ -1055,7 +1056,7 @@ export default defineComponent({
|
|||
this.canvasStore.zoomToFit();
|
||||
this.uiStore.stateIsDirty = true;
|
||||
|
||||
void this.$externalHooks().run('template.open', {
|
||||
void this.externalHooks.run('template.open', {
|
||||
templateId,
|
||||
templateName: data.name,
|
||||
workflow: data.workflow,
|
||||
|
@ -1106,7 +1107,7 @@ export default defineComponent({
|
|||
this.uiStore.stateIsDirty = false;
|
||||
}
|
||||
this.canvasStore.zoomToFit();
|
||||
void this.$externalHooks().run('workflow.open', {
|
||||
void this.externalHooks.run('workflow.open', {
|
||||
workflowId: workflow.id,
|
||||
workflowName: workflow.name,
|
||||
});
|
||||
|
@ -1191,7 +1192,7 @@ export default defineComponent({
|
|||
if (e.key === 'Escape') {
|
||||
this.createNodeActive = false;
|
||||
if (this.activeNode) {
|
||||
void this.$externalHooks().run('dataDisplay.nodeEditingFinished');
|
||||
void this.externalHooks.run('dataDisplay.nodeEditingFinished');
|
||||
this.ndvStore.activeNodeName = null;
|
||||
}
|
||||
|
||||
|
@ -2256,7 +2257,7 @@ export default defineComponent({
|
|||
workflow_id: this.workflowsStore.workflowId,
|
||||
});
|
||||
} else {
|
||||
void this.$externalHooks().run('nodeView.addNodeButton', { nodeTypeName });
|
||||
void this.externalHooks.run('nodeView.addNodeButton', { nodeTypeName });
|
||||
useSegment().trackAddedTrigger(nodeTypeName);
|
||||
const trackProperties: ITelemetryTrackProperties = {
|
||||
node_type: nodeTypeName,
|
||||
|
@ -3595,7 +3596,7 @@ export default defineComponent({
|
|||
is_welcome_note: node.name === QUICKSTART_NOTE_NAME,
|
||||
});
|
||||
} else {
|
||||
void this.$externalHooks().run('node.deleteNode', { node });
|
||||
void this.externalHooks.run('node.deleteNode', { node });
|
||||
this.$telemetry.track('User deleted node', {
|
||||
node_type: node.type,
|
||||
workflow_id: this.workflowsStore.workflowId,
|
||||
|
@ -4395,7 +4396,7 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
if (createNodeActive) this.nodeCreatorStore.setOpenSource(source);
|
||||
void this.$externalHooks().run('nodeView.createNodeActiveChanged', {
|
||||
void this.externalHooks.run('nodeView.createNodeActiveChanged', {
|
||||
source,
|
||||
mode,
|
||||
createNodeActive,
|
||||
|
@ -4644,9 +4645,7 @@ export default defineComponent({
|
|||
});
|
||||
|
||||
// TODO: This currently breaks since front-end hooks are still not updated to work with pinia store
|
||||
void this.$externalHooks()
|
||||
.run('nodeView.mount')
|
||||
.catch((e) => {});
|
||||
void this.externalHooks.run('nodeView.mount').catch((e) => {});
|
||||
|
||||
if (
|
||||
this.currentUser?.personalizationAnswers !== null &&
|
||||
|
|
|
@ -68,6 +68,7 @@ import { useUIStore } from '@/stores/ui.store';
|
|||
import { mapStores } from 'pinia';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { defineComponent } from 'vue';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
const PACKAGE_COUNT_THRESHOLD = 31;
|
||||
|
||||
|
@ -77,11 +78,14 @@ export default defineComponent({
|
|||
components: {
|
||||
CommunityPackageCard,
|
||||
},
|
||||
setup(props) {
|
||||
setup(props, ctx) {
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
return {
|
||||
externalHooks,
|
||||
...useToast(),
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
...pushConnection.setup?.(props),
|
||||
...pushConnection.setup?.(props, ctx),
|
||||
};
|
||||
},
|
||||
data() {
|
||||
|
@ -222,10 +226,7 @@ export default defineComponent({
|
|||
};
|
||||
this.$telemetry.track('user clicked cnr install button', telemetryPayload);
|
||||
|
||||
void this.$externalHooks().run(
|
||||
'settingsCommunityNodesView.openInstallModal',
|
||||
telemetryPayload,
|
||||
);
|
||||
void this.externalHooks.run('settingsCommunityNodesView.openInstallModal', telemetryPayload);
|
||||
this.uiStore.openModal(COMMUNITY_PACKAGE_INSTALL_MODAL_KEY);
|
||||
},
|
||||
},
|
||||
|
|
|
@ -8,19 +8,15 @@ import AppsRequiringCredsNotice from './AppsRequiringCredsNotice.vue';
|
|||
import SetupTemplateFormStep from './SetupTemplateFormStep.vue';
|
||||
import TemplatesView from '../TemplatesView.vue';
|
||||
import { VIEWS } from '@/constants';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
import { useTelemetry } from '@/composables/useTelemetry';
|
||||
|
||||
// Store
|
||||
const setupTemplateStore = useSetupTemplateStore();
|
||||
const i18n = useI18n();
|
||||
const $telemetry = useTelemetry();
|
||||
const $externalHooks = useExternalHooks();
|
||||
|
||||
// Router
|
||||
const route = useRoute();
|
||||
const $router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
//#region Computed
|
||||
|
||||
|
@ -31,7 +27,7 @@ const title = computed(() => setupTemplateStore.template?.name ?? 'unknown');
|
|||
const isReady = computed(() => !setupTemplateStore.isLoading);
|
||||
|
||||
const skipSetupUrl = computed(() => {
|
||||
const resolvedRoute = $router.resolve({
|
||||
const resolvedRoute = router.resolve({
|
||||
name: VIEWS.TEMPLATE_IMPORT,
|
||||
params: { id: templateId.value },
|
||||
});
|
||||
|
@ -55,9 +51,7 @@ const onSkipSetup = async (event: MouseEvent) => {
|
|||
event.preventDefault();
|
||||
|
||||
await setupTemplateStore.skipSetup({
|
||||
$externalHooks,
|
||||
$telemetry,
|
||||
$router,
|
||||
router,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -69,9 +63,7 @@ const skipIfTemplateHasNoCreds = async () => {
|
|||
|
||||
if (setupTemplateStore.credentialUsages.length === 0) {
|
||||
await setupTemplateStore.skipSetup({
|
||||
$externalHooks,
|
||||
$telemetry,
|
||||
$router,
|
||||
router,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -94,7 +86,7 @@ onMounted(async () => {
|
|||
<TemplatesView :goBackEnabled="true">
|
||||
<template #header>
|
||||
<n8n-heading v-if="isReady" tag="h1" size="2xlarge"
|
||||
>{{ $locale.baseText('templateSetup.title', { interpolate: { name: title } }) }}
|
||||
>{{ i18n.baseText('templateSetup.title', { interpolate: { name: title } }) }}
|
||||
</n8n-heading>
|
||||
<n8n-loading v-else variant="h1" />
|
||||
</template>
|
||||
|
@ -124,15 +116,15 @@ onMounted(async () => {
|
|||
|
||||
<div :class="$style.actions">
|
||||
<n8n-link :href="skipSetupUrl" :newWindow="false" @click="onSkipSetup($event)">{{
|
||||
$locale.baseText('templateSetup.skip')
|
||||
i18n.baseText('templateSetup.skip')
|
||||
}}</n8n-link>
|
||||
|
||||
<n8n-button
|
||||
v-if="isReady"
|
||||
size="large"
|
||||
:label="$locale.baseText('templateSetup.continue.button')"
|
||||
:label="i18n.baseText('templateSetup.continue.button')"
|
||||
:disabled="setupTemplateStore.isSaving"
|
||||
@click="setupTemplateStore.createWorkflow($router)"
|
||||
@click="setupTemplateStore.createWorkflow(router)"
|
||||
data-test-id="continue-button"
|
||||
/>
|
||||
<div v-else>
|
||||
|
|
|
@ -11,12 +11,10 @@ import { getAppNameFromNodeName } from '@/utils/nodeTypesUtils';
|
|||
import type { INodeCredentialsDetails, INodeTypeDescription } from 'n8n-workflow';
|
||||
import type {
|
||||
ICredentialsResponse,
|
||||
IExternalHooks,
|
||||
INodeUi,
|
||||
ITemplatesWorkflowFull,
|
||||
IWorkflowTemplateNode,
|
||||
} from '@/Interface';
|
||||
import type { Telemetry } from '@/plugins/telemetry';
|
||||
import { VIEWS } from '@/constants';
|
||||
import { createWorkflowFromTemplate } from '@/utils/templates/templateActions';
|
||||
import type {
|
||||
|
@ -28,6 +26,8 @@ import {
|
|||
keyFromCredentialTypeAndName,
|
||||
normalizeTemplateNodeCredentials,
|
||||
} from '@/utils/templates/templateTransforms';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
import { useTelemetry } from '@/composables/useTelemetry';
|
||||
|
||||
export type NodeAndType = {
|
||||
node: INodeUi;
|
||||
|
@ -300,25 +300,23 @@ export const useSetupTemplateStore = defineStore('setupTemplate', () => {
|
|||
/**
|
||||
* Skips the setup and goes directly to the workflow view.
|
||||
*/
|
||||
const skipSetup = async (opts: {
|
||||
$externalHooks: IExternalHooks;
|
||||
$telemetry: Telemetry;
|
||||
$router: Router;
|
||||
}) => {
|
||||
const { $externalHooks, $telemetry, $router } = opts;
|
||||
const skipSetup = async ({ router }: { router: Router }) => {
|
||||
const externalHooks = useExternalHooks();
|
||||
const telemetry = useTelemetry();
|
||||
|
||||
const telemetryPayload = {
|
||||
source: 'workflow',
|
||||
template_id: templateId.value,
|
||||
wf_template_repo_session_id: templatesStore.currentSessionId,
|
||||
};
|
||||
|
||||
await $externalHooks.run('templatesWorkflowView.openWorkflow', telemetryPayload);
|
||||
$telemetry.track('User inserted workflow template', telemetryPayload, {
|
||||
await externalHooks.run('templatesWorkflowView.openWorkflow', telemetryPayload);
|
||||
telemetry.track('User inserted workflow template', telemetryPayload, {
|
||||
withPostHog: true,
|
||||
});
|
||||
|
||||
// Replace the URL so back button doesn't come back to this setup view
|
||||
await $router.replace({
|
||||
await router.replace({
|
||||
name: VIEWS.TEMPLATE_IMPORT,
|
||||
params: { id: templateId.value },
|
||||
});
|
||||
|
|
|
@ -71,6 +71,7 @@ import { useTemplatesStore } from '@/stores/templates.store';
|
|||
import { usePostHog } from '@/stores/posthog.store';
|
||||
import { FeatureFlag, isFeatureFlagEnabled } from '@/utils/featureFlag';
|
||||
import { openTemplateCredentialSetup } from '@/utils/templates/templateActions';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TemplatesCollectionView',
|
||||
|
@ -80,6 +81,13 @@ export default defineComponent({
|
|||
TemplateList,
|
||||
TemplatesView,
|
||||
},
|
||||
setup() {
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
return {
|
||||
externalHooks,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapStores(useTemplatesStore, usePostHog),
|
||||
collection(): ITemplatesCollectionFull | null {
|
||||
|
@ -127,7 +135,7 @@ export default defineComponent({
|
|||
wf_template_repo_session_id: this.templatesStore.currentSessionId,
|
||||
source: 'collection',
|
||||
};
|
||||
await this.$externalHooks().run('templatesCollectionView.onUseWorkflow', telemetryPayload);
|
||||
await this.externalHooks.run('templatesCollectionView.onUseWorkflow', telemetryPayload);
|
||||
this.$telemetry.track('User inserted workflow template', telemetryPayload, {
|
||||
withPostHog: true,
|
||||
});
|
||||
|
|
|
@ -70,6 +70,7 @@ import { useTemplatesStore } from '@/stores/templates.store';
|
|||
import { usePostHog } from '@/stores/posthog.store';
|
||||
import { openTemplateCredentialSetup } from '@/utils/templates/templateActions';
|
||||
import { FeatureFlag, isFeatureFlagEnabled } from '@/utils/featureFlag';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TemplatesWorkflowView',
|
||||
|
@ -79,6 +80,13 @@ export default defineComponent({
|
|||
TemplatesView,
|
||||
WorkflowPreview,
|
||||
},
|
||||
setup() {
|
||||
const externalHooks = useExternalHooks();
|
||||
|
||||
return {
|
||||
externalHooks,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapStores(useTemplatesStore, usePostHog),
|
||||
template(): ITemplatesWorkflowFull | null {
|
||||
|
@ -109,7 +117,7 @@ export default defineComponent({
|
|||
this.$telemetry.track('User inserted workflow template', telemetryPayload, {
|
||||
withPostHog: true,
|
||||
});
|
||||
await this.$externalHooks().run('templatesWorkflowView.openWorkflow', telemetryPayload);
|
||||
await this.externalHooks.run('templatesWorkflowView.openWorkflow', telemetryPayload);
|
||||
}
|
||||
|
||||
await openTemplateCredentialSetup({
|
||||
|
|
Loading…
Reference in a new issue