n8n/packages/editor-ui/src/hooks/segment/getters.ts
2023-11-23 11:55:02 +01:00

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