feat: Add events to enable onboarding checklist (#5536)
* feat: Add new event hooks * fix: update event * feat: Add more functionality for webhooks * ⚡ Not sending onboarding checklist event from templates page * 🔥 Removing quotes added by mistake * ⚡ Added rest of events needed for onboarding checklist * 💄 Hiding appcues checklist inside iframes * 💄 Updating appcues selector * fix: remove unnessary fix * fix: fix schedule node * refactor: bake events into segment store * refactor: rename store * refactor: use node keys * refactor: remove unnessary * chore: clean up store * refactor: add key for event * fix: allow tracking on template pages * chore: remove comment * fix: buidl * refactor: block event if in iframe * fix: fix tracking nodes * refactor: track experiments once * fix: ensure tracking works * chore: remove comment * fix: lint * fix: lint --------- Co-authored-by: Milorad Filipovic <milorad@n8n.io>
This commit is contained in:
133
packages/editor-ui/src/stores/segment.ts
Normal file
133
packages/editor-ui/src/stores/segment.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
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 { ITelemetryTrackProperties } from 'n8n-workflow';
|
||||
import { defineStore } from 'pinia';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { INodeTypeDescription, IRun } from 'n8n-workflow';
|
||||
import { useWorkflowsStore } from '@/stores/workflows';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes';
|
||||
|
||||
const EVENTS = {
|
||||
SHOW_CHECKLIST: 'Show checklist',
|
||||
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 track = (eventName: string, properties?: ITelemetryTrackProperties) => {
|
||||
if (settingsStore.telemetry.enabled) {
|
||||
window.analytics?.track(eventName, properties);
|
||||
}
|
||||
};
|
||||
|
||||
const showAppCuesChecklist = () => {
|
||||
const isInIframe = window.location !== window.parent.location;
|
||||
if (isInIframe) {
|
||||
return;
|
||||
}
|
||||
|
||||
track(EVENTS.SHOW_CHECKLIST);
|
||||
};
|
||||
|
||||
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<string> = new Set<string>();
|
||||
const multipleOutputNodes: Set<string> = new Set<string>();
|
||||
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 && 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 {
|
||||
showAppCuesChecklist,
|
||||
track,
|
||||
trackAddedTrigger,
|
||||
trackSuccessfulWorkflowExecution,
|
||||
EVENTS,
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user