diff --git a/packages/editor-ui/src/components/ParameterInputFull.vue b/packages/editor-ui/src/components/ParameterInputFull.vue index 3392506a96..2e6847fce5 100644 --- a/packages/editor-ui/src/components/ParameterInputFull.vue +++ b/packages/editor-ui/src/components/ParameterInputFull.vue @@ -88,7 +88,6 @@ import ParameterOptions from '@/components/ParameterOptions.vue'; import { useI18n } from '@/composables/useI18n'; import { useToast } from '@/composables/useToast'; import { useNDVStore } from '@/stores/ndv.store'; -import { useSegment } from '@/stores/segment.store'; import { getMappedResult } from '@/utils/mappingUtils'; import { hasExpressionMapping, hasOnlyListMode, isValueExpression } from '@/utils/nodeTypesUtils'; import { isResourceLocatorValue } from '@/utils/typeGuards'; @@ -272,9 +271,6 @@ function onDrop(newParamValue: string) { hasExpressionMapping(prevValue), success: true, }); - - const segment = useSegment(); - segment.track(segment.EVENTS.MAPPED_DATA); } forceShowExpression.value = false; }, 200); diff --git a/packages/editor-ui/src/composables/useCanvasOperations.ts b/packages/editor-ui/src/composables/useCanvasOperations.ts index dec5f19476..7980930e2b 100644 --- a/packages/editor-ui/src/composables/useCanvasOperations.ts +++ b/packages/editor-ui/src/composables/useCanvasOperations.ts @@ -39,7 +39,6 @@ import { useI18n } from '@/composables/useI18n'; import { useToast } from '@/composables/useToast'; import * as NodeViewUtils from '@/utils/nodeViewUtils'; import { v4 as uuid } from 'uuid'; -import { useSegment } from '@/stores/segment.store'; import type { Ref } from 'vue'; import { computed } from 'vue'; import { useCredentialsStore } from '@/stores/credentials.store'; @@ -650,7 +649,6 @@ export function useCanvasOperations({ }); } else { void externalHooks.run('nodeView.addNodeButton', { nodeTypeName: node.type }); - useSegment().trackAddedTrigger(node.type); const trackProperties: ITelemetryTrackProperties = { node_type: node.type, node_version: newNodeData.typeVersion, diff --git a/packages/editor-ui/src/composables/usePushConnection.ts b/packages/editor-ui/src/composables/usePushConnection.ts index 4cb7bf4edf..a903647171 100644 --- a/packages/editor-ui/src/composables/usePushConnection.ts +++ b/packages/editor-ui/src/composables/usePushConnection.ts @@ -32,7 +32,6 @@ import { useNodeTypesStore } from '@/stores/nodeTypes.store'; import { useCredentialsStore } from '@/stores/credentials.store'; import { useSettingsStore } from '@/stores/settings.store'; import { parse } from 'flatted'; -import { useSegment } from '@/stores/segment.store'; import { ref } from 'vue'; import { useOrchestrationStore } from '@/stores/orchestration.store'; import { usePushConnectionStore } from '@/stores/pushConnection.store'; @@ -58,7 +57,6 @@ export function usePushConnection({ router }: { router: ReturnType = { @@ -34,474 +10,4 @@ export const n8nCloudHooks: PartialDeep = { }, ], }, - nodeView: { - mount: [ - () => { - const segmentStore = useSegment(); - segmentStore.identify(); - }, - ], - createNodeActiveChanged: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = { - source: meta.source, - nodes_panel_session_id: nodesPanelSession.pushRef, - }; - - hooksResetNodesPanelSession(); - segmentStore.track('User opened nodes panel', eventData); - segmentStore.page('Cloud instance', 'Nodes panel', eventData); - }, - ], - addNodeButton: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = { - eventName: 'User added node to workflow canvas', - properties: { - node_type: meta.nodeTypeName.split('.')[1], - nodes_panel_session_id: nodesPanelSession.pushRef, - }, - }; - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - }, - main: { - routeChange: [ - (_, meta) => { - const segmentStore = useSegment(); - const splitPath = meta.to.path.split('/'); - if (meta.from.path !== '/' && splitPath[1] === 'workflow') { - const eventData = { - workflow_id: splitPath[2], - }; - - segmentStore.page('Cloud instance', 'Workflow editor', eventData); - } - }, - ], - }, - credential: { - saved: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = getUserSavedCredentialsEventData(meta); - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - }, - credentialsEdit: { - credentialTypeChanged: [ - (_, meta) => { - const segmentStore = useSegment(); - if (meta.newValue) { - const eventData = { - eventName: 'User opened Credentials modal', - properties: { - source: meta.setCredentialType === meta.credentialType ? 'node' : 'primary_menu', - new_credential: !meta.editCredentials, - credential_type: meta.credentialType, - }, - }; - - segmentStore.track(eventData.eventName, eventData.properties); - segmentStore.page('Cloud instance', 'Credentials modal', eventData.properties); - } - }, - ], - credentialModalOpened: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = { - eventName: 'User opened Credentials modal', - properties: { - source: meta.activeNode ? 'node' : 'primary_menu', - new_credential: !meta.isEditingCredential, - credential_type: meta.credentialType, - }, - }; - - segmentStore.track(eventData.eventName, eventData.properties); - segmentStore.page('Cloud instance', 'Credentials modal', eventData.properties); - }, - ], - }, - credentialsList: { - mounted: [ - () => { - const segmentStore = useSegment(); - const eventData = { - eventName: 'User opened global Credentials panel', - }; - - segmentStore.track(eventData.eventName); - segmentStore.page('Cloud instance', 'Credentials panel'); - }, - ], - dialogVisibleChanged: [ - (_, meta) => { - const segmentStore = useSegment(); - if (meta.dialogVisible) { - const eventData = { - eventName: 'User opened global Credentials panel', - }; - - segmentStore.track(eventData.eventName); - segmentStore.page('Cloud instance', 'Credentials panel'); - } - }, - ], - }, - workflowSettings: { - dialogVisibleChanged: [ - (_, meta) => { - const segmentStore = useSegment(); - if (meta.dialogVisible) { - const eventData = getOpenWorkflowSettingsEventData(); - segmentStore.track(eventData.eventName, eventData.properties); - } - }, - ], - saveSettings: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = getUpdatedWorkflowSettingsEventData(meta); - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - }, - dataDisplay: { - onDocumentationUrlClick: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = { - eventName: 'User clicked node modal docs link', - properties: { - node_type: meta.nodeType.name.split('.')[1], - docs_link: meta.documentationUrl, - }, - }; - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - nodeTypeChanged: [ - (_, meta) => { - const segmentStore = useSegment(); - const ndvStore = useNDVStore(); - const eventData = getNodeTypeChangedEventData(meta); - - segmentStore.track(eventData.eventName, eventData.properties); - segmentStore.page('Cloud instance', 'Node modal', { - node: ndvStore.activeNode?.name, - }); - }, - ], - nodeEditingFinished: [ - () => { - const segmentStore = useSegment(); - const ndvStore = useNDVStore(); - const workflowsStore = useWorkflowsStore(); - - const eventData = getNodeEditingFinishedEventData(ndvStore.activeNode); - if (eventData) { - eventData.properties!.workflow_id = workflowsStore.workflowId; - } - - if (eventData) { - segmentStore.track(eventData.eventName, eventData.properties); - } - }, - ], - }, - executionsList: { - openDialog: [ - () => { - const segmentStore = useSegment(); - const eventData = { - eventName: 'User opened Executions log', - }; - - segmentStore.track(eventData.eventName); - segmentStore.page('Cloud instance', 'Executions log'); - }, - ], - }, - showMessage: { - showError: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = { - eventName: 'Instance FE emitted error', - properties: { - error_title: meta.title, - error_description: meta.message, - error_message: meta.errorMessage, - }, - }; - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - }, - expressionEdit: { - itemSelected: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = getInsertedItemFromExpEditorEventData(meta); - - if (meta.selectedItem.variable.startsWith('Object.keys')) { - eventData.properties!.variable_type = 'Keys'; - } else if (meta.selectedItem.variable.startsWith('Object.values')) { - eventData.properties!.variable_type = 'Values'; - } else { - eventData.properties!.variable_type = 'Raw value'; - } - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - dialogVisibleChanged: [ - (_, meta) => { - const segmentStore = useSegment(); - const currentValue = meta.value?.slice(1) ?? ''; - let isValueDefault = false; - - switch (typeof meta.parameter.default) { - case 'boolean': - isValueDefault = - (currentValue === 'true' && meta.parameter.default) || - (currentValue === 'false' && !meta.parameter.default); - break; - case 'string': - isValueDefault = currentValue === meta.parameter.default; - break; - case 'number': - isValueDefault = currentValue === meta.parameter.default.toString(); - break; - } - - const eventData = getExpressionEditorEventsData(meta, isValueDefault); - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - }, - nodeSettings: { - valueChanged: [ - (_, meta) => { - const segmentStore = useSegment(); - if (meta.parameterPath !== 'authentication') { - return; - } - - const eventData = getAuthenticationModalEventData(meta); - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - credentialSelected: [ - (_, meta) => { - const segmentStore = useSegment(); - const creds = Object.keys(meta.updateInformation.properties.credentials || {}); - if (creds.length < 1) { - return; - } - - const eventData = { - eventName: 'User selected credential from node modal', - properties: { - credential_name: (meta.updateInformation.properties.credentials as IDataObject)[ - creds[0] - ], - credential_type: creds[0], - }, - }; - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - }, - workflowRun: { - runWorkflow: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = getExecutionStartedEventData(meta); - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - runError: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = { - eventName: meta.nodeName - ? 'Node execution finished' - : 'Manual workflow execution finished', - properties: { - preflight: 'true', - status: 'failed', - error_message: meta.errorMessages.join('
  - '), - error_timestamp: new Date(), - node_name: meta.nodeName, - }, - }; - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - }, - runData: { - displayModeChanged: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = getOutputModeChangedEventData(meta); - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - }, - pushConnection: { - executionFinished: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = getExecutionFinishedEventData(meta); - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - }, - node: { - deleteNode: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = getNodeRemovedEventData(meta); - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - }, - workflow: { - activeChange: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = { - eventName: (meta.active && 'User activated workflow') || 'User deactivated workflow', - properties: { - workflow_id: meta.workflowId, - source: 'workflow_modal', - }, - }; - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - activeChangeCurrent: [ - (_, meta) => { - const segmentStore = useSegment(); - const workflowsStore = useWorkflowsStore(); - - const eventData = { - eventName: (meta.active && 'User activated workflow') || 'User deactivated workflow', - properties: { - source: 'main nav', - workflow_id: meta.workflowId, - workflow_name: workflowsStore.workflowName, - workflow_nodes: workflowsStore.allNodes.map((n) => n.type.split('.')[1]), - }, - }; - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - afterUpdate: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = { - eventName: 'User saved workflow', - properties: { - workflow_id: meta.workflowData.id, - workflow_name: meta.workflowData.name, - workflow_nodes: meta.workflowData.nodes.map((n) => n.type.split('.')[1]), - }, - }; - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - }, - execution: { - open: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = { - eventName: 'User opened read-only execution', - properties: { - workflow_id: meta.workflowId, - workflow_name: meta.workflowName, - execution_id: meta.executionId, - }, - }; - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - }, - nodeCreateList: { - destroyed: [ - () => { - const segmentStore = useSegment(); - if ( - nodesPanelSession.data.nodeFilter.length > 0 && - nodesPanelSession.data.nodeFilter !== '' - ) { - const eventData = hooksGenerateNodesPanelEvent(); - - segmentStore.track(eventData.eventName, eventData.properties); - } - }, - ], - selectedTypeChanged: [ - (_, meta) => { - const segmentStore = useSegment(); - const eventData = { - eventName: 'User changed nodes panel filter', - properties: { - old_filter: meta.oldValue, - new_filter: meta.newValue, - nodes_panel_session_id: nodesPanelSession.pushRef, - }, - }; - nodesPanelSession.data.filterMode = meta.newValue; - - segmentStore.track(eventData.eventName, eventData.properties); - }, - ], - nodeFilterChanged: [ - (_, meta) => { - const segmentStore = useSegment(); - if (meta.newValue.length === 0 && nodesPanelSession.data.nodeFilter.length > 0) { - const eventData = hooksGenerateNodesPanelEvent(); - - segmentStore.track(eventData.eventName, eventData.properties); - } - - if (meta.newValue.length > meta.oldValue.length) { - nodesPanelSession.data.nodeFilter = meta.newValue; - nodesPanelSession.data.resultsNodes = meta.filteredNodes.map((node) => { - if ((node as unknown as INodeUi).name) { - return (node as unknown as INodeUi).name.split('.')[1]; - } else if (node.key) { - return node.key.split('.')[1]; - } - return ''; - }); - } - }, - ], - }, }; diff --git a/packages/editor-ui/src/hooks/segment/getters.ts b/packages/editor-ui/src/hooks/segment/getters.ts deleted file mode 100644 index 679e49b416..0000000000 --- a/packages/editor-ui/src/hooks/segment/getters.ts +++ /dev/null @@ -1,349 +0,0 @@ -import { deepCopy } from 'n8n-workflow'; -import type { - ExecutionError, - GenericValue, - INodeProperties, - ITelemetryTrackProperties, - NodeParameterValue, - INode, -} from 'n8n-workflow'; -import { useNDVStore } from '@/stores/ndv.store'; -import type { TelemetryEventData } from '@/hooks/types'; -import type { INodeUi } from '@/Interface'; -import { useWorkflowsStore } from '@/stores/workflows.store'; -import { useRootStore } from '@/stores/root.store'; - -export interface UserSavedCredentialsEventData { - credential_type: string; - credential_id: string; - is_new: boolean; -} - -export const getUserSavedCredentialsEventData = (meta: UserSavedCredentialsEventData) => { - const rootStore = useRootStore(); - const workflowsStore = useWorkflowsStore(); - - return { - eventName: 'User saved credentials', - properties: { - instance_id: rootStore.instanceId, - credential_type: meta.credential_type, - credential_id: meta.credential_id, - workflow_id: workflowsStore.workflowId, - node_type: workflowsStore.activeNode?.name, - is_new: meta.is_new, - // is_complete: true, - // is_valid: true, - // error_message: '' - }, - }; -}; - -export const getOpenWorkflowSettingsEventData = (): TelemetryEventData => { - const workflowsStore = useWorkflowsStore(); - - return { - eventName: 'User opened workflow settings', - properties: { - workflow_id: workflowsStore.workflowId, - workflow_name: workflowsStore.workflowName, - current_settings: deepCopy(workflowsStore.workflowSettings), - }, - }; -}; - -export interface UpdatedWorkflowSettingsEventData { - oldSettings: Record; -} - -export const getUpdatedWorkflowSettingsEventData = ( - meta: UpdatedWorkflowSettingsEventData, -): TelemetryEventData => { - const workflowsStore = useWorkflowsStore(); - - return { - eventName: 'User updated workflow settings', - properties: { - workflow_id: workflowsStore.workflowId, - workflow_name: workflowsStore.workflowName, - new_settings: deepCopy(workflowsStore.workflowSettings), - old_settings: meta.oldSettings, - }, - }; -}; - -export interface NodeTypeChangedEventData { - nodeSubtitle?: string; -} - -export const getNodeTypeChangedEventData = (meta: NodeTypeChangedEventData): TelemetryEventData => { - const store = useNDVStore(); - - return { - eventName: 'User opened node modal', - properties: { - node_name: store.activeNode?.name, - node_subtitle: meta.nodeSubtitle, - }, - }; -}; - -export interface InsertedItemFromExpEditorEventData { - parameter: { - displayName: string; - }; - value: string; - selectedItem: { - variable: string; - }; -} - -export const getInsertedItemFromExpEditorEventData = ( - meta: InsertedItemFromExpEditorEventData, -): TelemetryEventData => { - const store = useNDVStore(); - - return { - eventName: 'User inserted item from Expression Editor variable selector', - properties: { - node_name: store.activeNode?.name, - node_type: store.activeNode?.type.split('.')[1], - parameter_name: meta.parameter.displayName, - variable_expression: meta.selectedItem.variable, - } as ITelemetryTrackProperties, - }; -}; - -export interface ExpressionEditorEventsData { - dialogVisible: boolean; - value: string; - resolvedExpressionValue: string; - parameter: INodeProperties; -} - -export const getExpressionEditorEventsData = ( - meta: ExpressionEditorEventsData, - isValueDefault: boolean, -): TelemetryEventData => { - const store = useNDVStore(); - const eventData: TelemetryEventData = { - eventName: '', - properties: {}, - }; - - if (!meta.dialogVisible) { - eventData.eventName = 'User closed Expression Editor'; - eventData.properties = { - empty_expression: isValueDefault, - expression_value: meta.value, - expression_result: meta.resolvedExpressionValue.slice(1), - }; - } else { - eventData.eventName = 'User opened Expression Editor'; - eventData.properties = { - node_name: store.activeNode?.name, - node_type: store.activeNode?.type.split('.')[1], - parameter_name: meta.parameter.displayName, - parameter_field_type: meta.parameter.type, - new_expression: isValueDefault, - }; - } - return eventData; -}; - -export interface AuthenticationModalEventData { - parameterPath: string; - oldNodeParameters: Record; - parameters: INodeProperties[]; - newValue: NodeParameterValue; -} -export const getAuthenticationModalEventData = ( - meta: AuthenticationModalEventData, -): TelemetryEventData => { - const store = useNDVStore(); - - return { - eventName: 'User changed Authentication type from node modal', - properties: { - node_name: store.activeNode?.name, - node_type: store.activeNode?.type.split('.')[1], - old_mode: - meta.oldNodeParameters.authentication || - ( - meta.parameters.find((param) => param.name === 'authentication') || { - default: 'default', - } - ).default, - new_mode: meta.newValue, - }, - }; -}; - -export interface OutputModeChangedEventData { - oldValue: string; - newValue: string; -} - -export const getOutputModeChangedEventData = ( - meta: OutputModeChangedEventData, -): TelemetryEventData => { - const store = useNDVStore(); - - return { - eventName: 'User changed node output view mode', - properties: { - old_mode: meta.oldValue, - new_mode: meta.newValue, - node_name: store.activeNode?.name, - node_type: store.activeNode?.type.split('.')[1], - }, - }; -}; - -export interface ExecutionFinishedEventData { - runDataExecutedStartData: - | { destinationNode?: string | undefined; runNodeFilter?: string[] | undefined } - | undefined; - nodeName?: string; - errorMessage: string; - resultDataError: ExecutionError | undefined; - itemsCount: number; -} - -export const getExecutionFinishedEventData = ( - meta: ExecutionFinishedEventData, -): TelemetryEventData => { - const store = useWorkflowsStore(); - - const eventData: TelemetryEventData = { - eventName: '', - properties: { - execution_id: store.activeExecutionId, - }, - }; - - if (meta.runDataExecutedStartData?.destinationNode) { - eventData.eventName = 'Node execution finished'; - eventData.properties!.node_type = store.getNodeByName(meta.nodeName || '')?.type.split('.')[1]; - eventData.properties!.node_name = meta.nodeName; - } else { - eventData.eventName = 'Manual workflow execution finished'; - eventData.properties!.workflow_id = store.workflowId; - eventData.properties!.workflow_name = store.workflowName; - } - - if (meta.errorMessage || meta.resultDataError) { - eventData.properties!.status = 'failed'; - eventData.properties!.error_message = meta.resultDataError?.message || ''; - eventData.properties!.error_stack = meta.resultDataError?.stack || ''; - eventData.properties!.error_ui_message = meta.errorMessage || ''; - eventData.properties!.error_timestamp = new Date(); - - if (meta.resultDataError && (meta.resultDataError as unknown as { node: INodeUi })?.node) { - eventData.properties!.error_node = - typeof (meta.resultDataError as unknown as { node: string })?.node === 'string' - ? (meta.resultDataError as unknown as { node: string })?.node - : (meta.resultDataError as unknown as { node: INodeUi })?.node?.name; - } else { - eventData.properties!.error_node = meta.nodeName; - } - } else { - eventData.properties!.status = 'success'; - if (meta.runDataExecutedStartData?.destinationNode) { - // Node execution finished - eventData.properties!.items_count = meta.itemsCount || 0; - } - } - return eventData; -}; - -export interface NodeRemovedEventData { - node: INodeUi; -} - -export const getNodeRemovedEventData = (meta: NodeRemovedEventData): TelemetryEventData => { - const workflowsStore = useWorkflowsStore(); - - return { - eventName: 'User removed node from workflow canvas', - properties: { - node_name: meta.node.name, - node_type: meta.node.type, - node_disabled: meta.node.disabled, - workflow_id: workflowsStore.workflowId, - }, - }; -}; - -export const getNodeEditingFinishedEventData = ( - activeNode: INode | null, -): TelemetryEventData | undefined => { - switch (activeNode?.type) { - case 'n8n-nodes-base.httpRequest': - const domain = (activeNode.parameters.url as string).split('/')[2]; - return { - eventName: 'User finished httpRequest node editing', - properties: { - method: activeNode.parameters.method, - domain, - }, - }; - case 'n8n-nodes-base.function': - return { - eventName: 'User finished function node editing', - properties: { - node_name: activeNode.name, - code: activeNode.parameters.functionCode, - }, - }; - case 'n8n-nodes-base.functionItem': - return { - eventName: 'User finished functionItem node editing', - properties: { - node_name: activeNode.name, - code: activeNode.parameters.functionCode, - }, - }; - default: - return; - } -}; - -export interface ExecutionStartedEventData { - nodeName?: string; - source?: string; -} - -export const getExecutionStartedEventData = ( - meta: ExecutionStartedEventData, -): TelemetryEventData => { - const store = useWorkflowsStore(); - - const eventData: TelemetryEventData = { - eventName: '', - properties: { - execution_id: store.activeExecutionId, - }, - }; - - // node execution - if (meta.nodeName) { - eventData.eventName = 'User started node execution'; - eventData.properties!.source = 'unknown'; - eventData.properties!.node_type = store.getNodeByName(meta.nodeName)?.type.split('.')[1]; - eventData.properties!.node_name = meta.nodeName; - - if (meta.source === 'RunData.ExecuteNodeButton') { - eventData.properties!.source = 'node_modal'; - } else if (meta.source === 'Node.executeNode') { - eventData.properties!.source = 'workflow_canvas'; - } - } else { - // workflow execution - eventData.eventName = 'User started manual workflow execution'; - eventData.properties!.workflow_id = store.workflowId; - eventData.properties!.workflow_name = store.workflowName; - } - - return eventData; -}; diff --git a/packages/editor-ui/src/hooks/segment/index.ts b/packages/editor-ui/src/hooks/segment/index.ts deleted file mode 100644 index b2fc0d3b65..0000000000 --- a/packages/editor-ui/src/hooks/segment/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './getters'; diff --git a/packages/editor-ui/src/stores/segment.store.ts b/packages/editor-ui/src/stores/segment.store.ts deleted file mode 100644 index 9e0159685c..0000000000 --- a/packages/editor-ui/src/stores/segment.store.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { - CODE_NODE_TYPE, - HTTP_REQUEST_NODE_TYPE, - MANUAL_TRIGGER_NODE_TYPE, - SCHEDULE_TRIGGER_NODE_TYPE, - SET_NODE_TYPE, - WEBHOOK_NODE_TYPE, -} from '@/constants'; -import { defineStore } from 'pinia'; - -import { useSettingsStore } from '@/stores/settings.store'; -import type { INodeTypeDescription, IRun, ITelemetryTrackProperties } from 'n8n-workflow'; -import { useWorkflowsStore } from '@/stores/workflows.store'; -import { useNodeTypesStore } from '@/stores/nodeTypes.store'; -import { useUsersStore } from '@/stores/users.store'; - -const EVENTS = { - ADDED_MANUAL_TRIGGER: 'User added manual trigger', - ADDED_SCHEDULE_TRIGGER: 'User added schedule trigger', - ADDED_DATA_TRIGGER: 'User added data trigger', - RECEIEVED_MULTIPLE_DATA_ITEMS: 'User received multiple data items', - EXECUTED_MANUAL_TRIGGER: 'User executed manual trigger successfully', - EXECUTED_SCHEDULE_TRIGGER: 'User executed schedule trigger successfully', - EXECUTED_DATA_NODE_TRIGGER: 'User executed data node successfully', - MAPPED_DATA: 'User mapped data', -}; - -export const useSegment = defineStore('segment', () => { - const nodeTypesStore = useNodeTypesStore(); - const workflowsStore = useWorkflowsStore(); - const settingsStore = useSettingsStore(); - const usersStore = useUsersStore(); - - const track = (eventName: string, properties?: ITelemetryTrackProperties) => { - if (settingsStore.telemetry.enabled) { - window.analytics?.track(eventName, properties); - } - }; - - const page = (category: string, name: string, properties?: ITelemetryTrackProperties) => { - if (settingsStore.telemetry.enabled) { - window.analytics?.page(category, name, properties); - } - }; - - const identify = () => { - const userId = usersStore.currentUserId; - - if (settingsStore.telemetry.enabled && userId) { - window.analytics?.identify(userId); - } - }; - - const trackAddedTrigger = (nodeTypeName: string) => { - if (!nodeTypesStore.isTriggerNode(nodeTypeName)) { - return; - } - - if (nodeTypeName === MANUAL_TRIGGER_NODE_TYPE) { - track(EVENTS.ADDED_MANUAL_TRIGGER); - } else if (nodeTypeName === SCHEDULE_TRIGGER_NODE_TYPE) { - track(EVENTS.ADDED_SCHEDULE_TRIGGER); - } else { - track(EVENTS.ADDED_DATA_TRIGGER); - } - }; - - const trackSuccessfulWorkflowExecution = (runData: IRun) => { - const dataNodeTypes: Set = new Set(); - const multipleOutputNodes: Set = new Set(); - let hasManualTrigger = false; - let hasScheduleTrigger = false; - for (const nodeName of Object.keys(runData.data.resultData.runData)) { - const nodeRunData = runData.data.resultData.runData[nodeName]; - const node = workflowsStore.getNodeByName(nodeName); - const nodeTypeName = node ? node.type : 'unknown'; - if ( - nodeRunData[0].data?.main && - nodeRunData[0].data.main.some((out) => out && out?.length > 1) - ) { - multipleOutputNodes.add(nodeTypeName); - } - if (node && !node.disabled) { - const nodeType = nodeTypesStore.getNodeType(node.type, node.typeVersion); - if (isDataNodeType(nodeType)) { - dataNodeTypes.add(nodeTypeName); - } - if (isManualTriggerNode(nodeType)) { - hasManualTrigger = true; - } - if (isScheduleTriggerNode(nodeType)) { - hasScheduleTrigger = true; - } - } - } - if (multipleOutputNodes.size > 0) { - track(EVENTS.RECEIEVED_MULTIPLE_DATA_ITEMS, { - nodeTypes: Array.from(multipleOutputNodes), - }); - } - if (dataNodeTypes.size > 0) { - track(EVENTS.EXECUTED_DATA_NODE_TRIGGER, { - nodeTypes: Array.from(dataNodeTypes), - }); - } - if (hasManualTrigger) { - track(EVENTS.EXECUTED_MANUAL_TRIGGER); - } - if (hasScheduleTrigger) { - track(EVENTS.EXECUTED_SCHEDULE_TRIGGER); - } - }; - - const isManualTriggerNode = (nodeType: INodeTypeDescription | null): boolean => { - return !!nodeType && nodeType.name === MANUAL_TRIGGER_NODE_TYPE; - }; - - const isScheduleTriggerNode = (nodeType: INodeTypeDescription | null): boolean => { - return !!nodeType && nodeType.name === SCHEDULE_TRIGGER_NODE_TYPE; - }; - - const isDataNodeType = (nodeType: INodeTypeDescription | null): boolean => { - if (!nodeType) { - return false; - } - const includeCoreNodes = [ - HTTP_REQUEST_NODE_TYPE, - CODE_NODE_TYPE, - SET_NODE_TYPE, - WEBHOOK_NODE_TYPE, - ]; - return !nodeTypesStore.isCoreNodeType(nodeType) || includeCoreNodes.includes(nodeType.name); - }; - - return { - track, - trackAddedTrigger, - trackSuccessfulWorkflowExecution, - identify, - page, - EVENTS, - }; -}); diff --git a/packages/editor-ui/src/types/externalHooks.ts b/packages/editor-ui/src/types/externalHooks.ts index f71c12b483..cffc8a8c0a 100644 --- a/packages/editor-ui/src/types/externalHooks.ts +++ b/packages/editor-ui/src/types/externalHooks.ts @@ -1,24 +1,15 @@ import type { N8nInput } from 'n8n-design-system'; import type { + ExecutionError, + GenericValue, IConnections, INodeProperties, INodeTypeDescription, ITelemetryTrackProperties, + NodeParameterValue, NodeParameterValueType, } from 'n8n-workflow'; import type { RouteLocation } from 'vue-router'; -import type { - AuthenticationModalEventData, - ExecutionFinishedEventData, - ExecutionStartedEventData, - ExpressionEditorEventsData, - InsertedItemFromExpEditorEventData, - NodeRemovedEventData, - NodeTypeChangedEventData, - OutputModeChangedEventData, - UpdatedWorkflowSettingsEventData, - UserSavedCredentialsEventData, -} from '@/hooks/segment'; import type { INodeCreateElement, INodeUi, @@ -40,6 +31,62 @@ export interface ExternalHooksGenericContext { [key: string]: ExternalHooksMethod[]; } +interface UserSavedCredentialsEventData { + credential_type: string; + credential_id: string; + is_new: boolean; +} + +interface UpdatedWorkflowSettingsEventData { + oldSettings: Record; +} + +interface NodeTypeChangedEventData { + nodeSubtitle?: string; +} +interface InsertedItemFromExpEditorEventData { + parameter: { + displayName: string; + }; + value: string; + selectedItem: { + variable: string; + }; +} +interface ExpressionEditorEventsData { + dialogVisible: boolean; + value: string; + resolvedExpressionValue: string; + parameter: INodeProperties; +} +interface AuthenticationModalEventData { + parameterPath: string; + oldNodeParameters: Record; + parameters: INodeProperties[]; + newValue: NodeParameterValue; +} +interface OutputModeChangedEventData { + oldValue: string; + newValue: string; +} +interface ExecutionFinishedEventData { + runDataExecutedStartData: + | { destinationNode?: string | undefined; runNodeFilter?: string[] | undefined } + | undefined; + nodeName?: string; + errorMessage: string; + resultDataError: ExecutionError | undefined; + itemsCount: number; +} +interface NodeRemovedEventData { + node: INodeUi; +} + +interface ExecutionStartedEventData { + nodeName?: string; + source?: string; +} + export interface ExternalHooks { parameterInput: { mount: Array< diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index f1c0c79ed3..ddc4a9b9ca 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -332,7 +332,6 @@ import { useNodeCreatorStore } from '@/stores/nodeCreator.store'; import { useNodeTypesStore } from '@/stores/nodeTypes.store'; import { usePushConnectionStore } from '@/stores/pushConnection.store'; import { useRootStore } from '@/stores/root.store'; -import { useSegment } from '@/stores/segment.store'; import { useSettingsStore } from '@/stores/settings.store'; import { useTagsStore } from '@/stores/tags.store'; import { useTemplatesStore } from '@/stores/templates.store'; @@ -2697,7 +2696,6 @@ export default defineComponent({ }); } else { void this.externalHooks.run('nodeView.addNodeButton', { nodeTypeName }); - useSegment().trackAddedTrigger(nodeTypeName); const trackProperties: ITelemetryTrackProperties = { node_type: nodeTypeName, node_version: newNodeData.typeVersion,