mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
351 lines
9.4 KiB
TypeScript
351 lines
9.4 KiB
TypeScript
import { deepCopy } from 'n8n-workflow';
|
|
import type {
|
|
ExecutionError,
|
|
GenericValue,
|
|
INodeParameters,
|
|
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/n8nRoot.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<string, unknown>;
|
|
}
|
|
|
|
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: INodeParameters;
|
|
}
|
|
|
|
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<string, GenericValue>;
|
|
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;
|
|
};
|