feat: Remove PostHog event calls (#6915)

This commit is contained in:
Ricardo Espinoza 2023-08-17 11:39:32 -04:00 committed by GitHub
parent 41c3cc89ca
commit 270946a93b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 86 additions and 53 deletions

View file

@ -124,7 +124,6 @@ export class InternalHooks implements IInternalHooksClass {
return this.telemetry.track(
'User responded to personalization questions',
personalizationSurveyData,
{ withPostHog: true },
);
}
@ -190,9 +189,7 @@ export class InternalHooks implements IInternalHooksClass {
workflowName: workflow.name,
},
}),
this.telemetry.track(
'User saved workflow',
{
this.telemetry.track('User saved workflow', {
user_id: user.id,
workflow_id: workflow.id,
node_graph_string: JSON.stringify(nodeGraph),
@ -202,9 +199,7 @@ export class InternalHooks implements IInternalHooksClass {
num_tags: workflow.tags?.length ?? 0,
public_api: publicApi,
sharing_role: userRole,
},
{ withPostHog: true },
),
}),
]);
}
@ -415,11 +410,7 @@ export class InternalHooks implements IInternalHooksClass {
node_id: nodeGraphResult.nameIndices[runData.data.startData?.destinationNode],
};
promises.push(
this.telemetry.track('Manual node exec finished', telemetryPayload, {
withPostHog: true,
}),
);
promises.push(this.telemetry.track('Manual node exec finished', telemetryPayload));
} else {
nodeGraphResult.webhookNodeNames.forEach((name: string) => {
const execJson = runData.data.resultData.runData[name]?.[0]?.data?.main?.[0]?.[0]
@ -432,9 +423,7 @@ export class InternalHooks implements IInternalHooksClass {
});
promises.push(
this.telemetry.track('Manual workflow exec finished', manualExecEventProperties, {
withPostHog: true,
}),
this.telemetry.track('Manual workflow exec finished', manualExecEventProperties),
);
}
}
@ -484,7 +473,7 @@ export class InternalHooks implements IInternalHooksClass {
user_id_list: userList,
};
return this.telemetry.track('User updated workflow sharing', properties, { withPostHog: true });
return this.telemetry.track('User updated workflow sharing', properties);
}
async onN8nStop(): Promise<void> {
@ -1017,7 +1006,7 @@ export class InternalHooks implements IInternalHooksClass {
user_id: string;
workflow_id: string;
}): Promise<void> {
return this.telemetry.track('Workflow first prod success', data, { withPostHog: true });
return this.telemetry.track('Workflow first prod success', data);
}
async onFirstWorkflowDataLoad(data: {
@ -1028,7 +1017,7 @@ export class InternalHooks implements IInternalHooksClass {
credential_type?: string;
credential_id?: string;
}): Promise<void> {
return this.telemetry.track('Workflow first data fetched', data, { withPostHog: true });
return this.telemetry.track('Workflow first data fetched', data);
}
/**

View file

@ -490,7 +490,7 @@ export class Server extends AbstractServer {
const controllers: object[] = [
new EventBusController(),
new AuthController({ config, internalHooks, repositories, logger, postHog }),
new OwnerController({ config, internalHooks, repositories, logger }),
new OwnerController({ config, internalHooks, repositories, logger, postHog }),
new MeController({ externalHooks, internalHooks, repositories, logger }),
new NodeTypesController({ config, nodeTypes }),
new PasswordResetController({

View file

@ -762,7 +762,7 @@ export const schema = {
externalFrontendHooksUrls: {
doc: 'URLs to external frontend hooks files, ; separated',
format: String,
default: 'https://public.n8n.cloud/posthog-hooks.js',
default: '',
env: 'EXTERNAL_FRONTEND_HOOKS_URLS',
},

View file

@ -6,6 +6,7 @@ import {
hashPassword,
sanitizeUser,
validatePassword,
withFeatureFlags,
} from '@/UserManagement/UserManagementHelper';
import { issueCookie } from '@/auth/jwt';
import { Response } from 'express';
@ -14,6 +15,7 @@ import type { Config } from '@/config';
import { OwnerRequest } from '@/requests';
import type { IDatabaseCollections, IInternalHooksClass } from '@/Interfaces';
import type { SettingsRepository, UserRepository } from '@db/repositories';
import type { PostHogClient } from '@/posthog';
@Authorized(['global', 'owner'])
@RestController('/owner')
@ -28,22 +30,27 @@ export class OwnerController {
private readonly settingsRepository: SettingsRepository;
private readonly postHog?: PostHogClient;
constructor({
config,
logger,
internalHooks,
repositories,
postHog,
}: {
config: Config;
logger: ILogger;
internalHooks: IInternalHooksClass;
repositories: Pick<IDatabaseCollections, 'User' | 'Settings'>;
postHog?: PostHogClient;
}) {
this.config = config;
this.logger = logger;
this.internalHooks = internalHooks;
this.userRepository = repositories.User;
this.settingsRepository = repositories.Settings;
this.postHog = postHog;
}
/**
@ -122,7 +129,7 @@ export class OwnerController {
void this.internalHooks.onInstanceOwnerSetup({ user_id: userId });
return sanitizeUser(owner);
return withFeatureFlags(this.postHog, sanitizeUser(owner));
}
@Post('/dismiss-banner')

View file

@ -95,15 +95,11 @@ export class Telemetry {
return sum > 0;
})
.map(async (workflowId) => {
const promise = this.track(
'Workflow execution count',
{
const promise = this.track('Workflow execution count', {
event_version: '2',
workflow_id: workflowId,
...this.executionCountsBuffer[workflowId],
},
{ withPostHog: true },
);
});
return promise;
});

View file

@ -78,6 +78,12 @@ declare global {
reset?(resetDeviceId?: boolean): void;
onFeatureFlags?(callback: (keys: string[], map: FeatureFlags) => void): void;
reloadFeatureFlags?(): void;
capture?(event: string, properties: IDataObject): void;
register?(metadata: IDataObject): void;
people?: {
set?(metadata: IDataObject): void;
};
debug?(): void;
};
analytics?: {
track(event: string, proeprties?: ITelemetryTrackProperties): void;

View file

@ -28,7 +28,7 @@ export async function logout(context: IRestApiContext): Promise<void> {
export async function setupOwner(
context: IRestApiContext,
params: { firstName: string; lastName: string; email: string; password: string },
): Promise<IUserResponse> {
): Promise<CurrentUserResponse> {
return makeRestApiRequest(context, 'POST', '/owner/setup', params as unknown as IDataObject);
}

View file

@ -138,6 +138,7 @@ import { useSettingsStore } from '@/stores/settings.store';
import { useRootStore } from '@/stores/n8nRoot.store';
import { useUsersStore } from '@/stores/users.store';
import { createEventBus } from 'n8n-design-system/utils';
import { usePostHog } from '@/stores';
export default defineComponent({
name: 'PersonalizationModal',
@ -166,7 +167,7 @@ export default defineComponent({
};
},
computed: {
...mapStores(useRootStore, useSettingsStore, useUIStore, useUsersStore),
...mapStores(useRootStore, useSettingsStore, useUIStore, useUsersStore, usePostHog),
survey() {
const survey: IFormInputs = [
{
@ -645,6 +646,8 @@ export default defineComponent({
await this.usersStore.submitPersonalizationSurvey(survey as IPersonalizationLatestVersion);
this.posthogStore.setMetadata(survey, 'user');
if (Object.keys(values).length === 0) {
this.closeDialog();
}

View file

@ -8,6 +8,7 @@ import { useSettingsStore } from '@/stores/settings.store';
import { useRootStore } from '@/stores/n8nRoot.store';
import { useTelemetryStore } from '@/stores/telemetry.store';
import { SLACK_NODE_TYPE } from '@/constants';
import { usePostHog } from '@/stores/posthog.store';
export class Telemetry {
constructor(
@ -72,7 +73,11 @@ export class Telemetry {
}
}
track(event: string, properties?: ITelemetryTrackProperties) {
track(
event: string,
properties?: ITelemetryTrackProperties,
{ withPostHog } = { withPostHog: false },
) {
if (!this.rudderStack) return;
const updatedProperties = {
@ -81,6 +86,10 @@ export class Telemetry {
};
this.rudderStack.track(event, updatedProperties);
if (withPostHog) {
usePostHog().capture(event, updatedProperties);
}
}
page(route: Route) {
@ -119,7 +128,7 @@ export class Telemetry {
properties.session_id = useRootStore().sessionId;
switch (event) {
case 'askAi.generationFinished':
this.track('Ai code generation finished', properties);
this.track('Ai code generation finished', properties, { withPostHog: true });
case 'ask.generationClicked':
this.track('User clicked on generate code button', properties);
default:
@ -189,7 +198,7 @@ export class Telemetry {
this.track('User viewed node category', properties);
break;
case 'nodeView.addNodeButton':
this.track('User added node to workflow canvas', properties);
this.track('User added node to workflow canvas', properties, { withPostHog: true });
break;
case 'nodeView.addSticky':
this.track('User inserted workflow note', properties);

View file

@ -4,7 +4,7 @@ import { defineStore } from 'pinia';
import { useUsersStore } from '@/stores/users.store';
import { useRootStore } from '@/stores/n8nRoot.store';
import { useSettingsStore } from '@/stores/settings.store';
import type { FeatureFlags } from 'n8n-workflow';
import type { FeatureFlags, IDataObject } from 'n8n-workflow';
import { EXPERIMENTS_TO_TRACK, LOCAL_STORAGE_EXPERIMENT_OVERRIDES } from '@/constants';
import { useTelemetryStore } from './telemetry.store';
import { debounce } from 'lodash-es';
@ -161,10 +161,29 @@ export const usePostHog = defineStore('posthog', () => {
trackedDemoExp.value[name] = variant;
};
const capture = (event: string, properties: IDataObject) => {
if (typeof window.posthog?.capture === 'function') {
window.posthog.capture(event, properties);
}
};
const setMetadata = (metadata: IDataObject, target: 'user' | 'events') => {
if (typeof window.posthog?.people?.set !== 'function') return;
if (typeof window.posthog?.register !== 'function') return;
if (target === 'user') {
window.posthog?.people?.set(metadata);
} else if (target === 'events') {
window.posthog?.register(metadata);
}
};
return {
init,
isVariantEnabled,
getVariant,
reset,
capture,
setMetadata,
};
});

View file

@ -200,6 +200,7 @@ export const useUsersStore = defineStore(STORES.USERS, {
this.addUsers([user]);
this.currentUserId = user.id;
settingsStore.stopShowingSetupPage();
usePostHog().init(user.featureFlags);
}
},
async validateSignupToken(params: {
@ -221,9 +222,8 @@ export const useUsersStore = defineStore(STORES.USERS, {
if (user) {
this.addUsers([user]);
this.currentUserId = user.id;
}
usePostHog().init(user.featureFlags);
}
},
async sendForgotPasswordEmail(params: { email: string }): Promise<void> {
const rootStore = useRootStore();

View file

@ -68,6 +68,7 @@ import type {
import { setPageTitle } from '@/utils';
import { VIEWS } from '@/constants';
import { useTemplatesStore } from '@/stores/templates.store';
import { usePostHog } from '@/stores/posthog.store';
export default defineComponent({
name: 'TemplatesCollectionView',
@ -78,7 +79,7 @@ export default defineComponent({
TemplatesView,
},
computed: {
...mapStores(useTemplatesStore),
...mapStores(useTemplatesStore, usePostHog),
collection(): null | ITemplatesCollectionFull {
return this.templatesStore.getCollectionById(this.collectionId);
},
@ -122,8 +123,9 @@ export default defineComponent({
source: 'collection',
};
void this.$externalHooks().run('templatesCollectionView.onUseWorkflow', telemetryPayload);
this.$telemetry.track('User inserted workflow template', telemetryPayload);
this.$telemetry.track('User inserted workflow template', telemetryPayload, {
withPostHog: true,
});
this.navigateTo(event, VIEWS.TEMPLATE_IMPORT, id);
},
navigateTo(e: MouseEvent, page: string, id: string) {

View file

@ -67,6 +67,7 @@ import { workflowHelpers } from '@/mixins/workflowHelpers';
import { setPageTitle } from '@/utils';
import { VIEWS } from '@/constants';
import { useTemplatesStore } from '@/stores/templates.store';
import { usePostHog } from '@/stores/posthog.store';
export default defineComponent({
name: 'TemplatesWorkflowView',
@ -77,7 +78,7 @@ export default defineComponent({
WorkflowPreview,
},
computed: {
...mapStores(useTemplatesStore),
...mapStores(useTemplatesStore, usePostHog),
template(): ITemplatesWorkflow | ITemplatesWorkflowFull {
return this.templatesStore.getTemplateById(this.templateId);
},
@ -101,8 +102,9 @@ export default defineComponent({
};
void this.$externalHooks().run('templatesWorkflowView.openWorkflow', telemetryPayload);
this.$telemetry.track('User inserted workflow template', telemetryPayload);
this.$telemetry.track('User inserted workflow template', telemetryPayload, {
withPostHog: true,
});
if (e.metaKey || e.ctrlKey) {
const route = this.$router.resolve({ name: VIEWS.TEMPLATE_IMPORT, params: { id } });
window.open(route.href, '_blank');