mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
fix: Ensure user id for early track events (#10885)
This commit is contained in:
parent
557db9c170
commit
23c09eae42
|
@ -42,12 +42,6 @@ watch(telemetry, () => {
|
|||
init();
|
||||
});
|
||||
|
||||
watch(currentUserId, (userId) => {
|
||||
if (isTelemetryEnabled.value) {
|
||||
telemetryPlugin.identify(rootStore.instanceId, userId);
|
||||
}
|
||||
});
|
||||
|
||||
watch(isTelemetryEnabledOnRoute, (enabled) => {
|
||||
if (enabled) {
|
||||
init();
|
||||
|
|
|
@ -15,7 +15,6 @@ import { useRootStore } from '@/stores/root.store';
|
|||
import { useNDVStore } from '@/stores/ndv.store';
|
||||
import { usePostHog } from '@/stores/posthog.store';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { useTelemetryStore } from '@/stores/telemetry.store';
|
||||
import { useUIStore } from '@/stores/ui.store';
|
||||
|
||||
export class Telemetry {
|
||||
|
@ -74,7 +73,6 @@ export class Telemetry {
|
|||
configUrl: 'https://api-rs.n8n.io',
|
||||
...logging,
|
||||
});
|
||||
useTelemetryStore().init(this);
|
||||
|
||||
this.identify(instanceId, userId, versionCli, projectId);
|
||||
|
||||
|
@ -146,6 +144,10 @@ export class Telemetry {
|
|||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.rudderStack?.reset();
|
||||
}
|
||||
|
||||
flushPageEvents() {
|
||||
const queue = this.pageEventQueue;
|
||||
this.pageEventQueue = [];
|
||||
|
|
|
@ -3,11 +3,11 @@ import { usePostHog } from '@/stores/posthog.store';
|
|||
import { useUsersStore } from '@/stores/users.store';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { useRootStore } from '@/stores/root.store';
|
||||
import { useTelemetryStore } from '@/stores/telemetry.store';
|
||||
import type { FrontendSettings } from '@n8n/api-types';
|
||||
import { LOCAL_STORAGE_EXPERIMENT_OVERRIDES } from '@/constants';
|
||||
import { nextTick } from 'vue';
|
||||
import { defaultSettings } from '../../__tests__/defaults';
|
||||
import { useTelemetry } from '@/composables/useTelemetry';
|
||||
|
||||
export const DEFAULT_POSTHOG_SETTINGS: FrontendSettings['posthog'] = {
|
||||
enabled: true,
|
||||
|
@ -55,11 +55,11 @@ function setup() {
|
|||
identify: () => {},
|
||||
};
|
||||
|
||||
const telemetryStore = useTelemetryStore();
|
||||
const telemetry = useTelemetry();
|
||||
|
||||
vi.spyOn(window.posthog, 'init');
|
||||
vi.spyOn(window.posthog, 'identify');
|
||||
vi.spyOn(telemetryStore, 'track');
|
||||
vi.spyOn(telemetry, 'track');
|
||||
}
|
||||
|
||||
describe('Posthog store', () => {
|
||||
|
|
|
@ -11,8 +11,8 @@ import {
|
|||
EXPERIMENTS_TO_TRACK,
|
||||
LOCAL_STORAGE_EXPERIMENT_OVERRIDES,
|
||||
} from '@/constants';
|
||||
import { useTelemetryStore } from './telemetry.store';
|
||||
import { useDebounce } from '@/composables/useDebounce';
|
||||
import { useTelemetry } from '@/composables/useTelemetry';
|
||||
|
||||
const EVENTS = {
|
||||
IS_PART_OF_EXPERIMENT: 'User is part of experiment',
|
||||
|
@ -23,7 +23,7 @@ export type PosthogStore = ReturnType<typeof usePostHog>;
|
|||
export const usePostHog = defineStore('posthog', () => {
|
||||
const usersStore = useUsersStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const telemetryStore = useTelemetryStore();
|
||||
const telemetry = useTelemetry();
|
||||
const rootStore = useRootStore();
|
||||
const { debounce } = useDebounce();
|
||||
|
||||
|
@ -110,7 +110,7 @@ export const usePostHog = defineStore('posthog', () => {
|
|||
return;
|
||||
}
|
||||
|
||||
telemetryStore.track(EVENTS.IS_PART_OF_EXPERIMENT, {
|
||||
telemetry.track(EVENTS.IS_PART_OF_EXPERIMENT, {
|
||||
name,
|
||||
variant,
|
||||
});
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
import type { Telemetry } from '@/plugins/telemetry';
|
||||
import type { ITelemetryTrackProperties } from 'n8n-workflow';
|
||||
import { defineStore } from 'pinia';
|
||||
import type { Ref } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
export const useTelemetryStore = defineStore('telemetry', () => {
|
||||
const telemetry: Ref<Telemetry | undefined> = ref();
|
||||
|
||||
const init = (tel: Telemetry) => {
|
||||
telemetry.value = tel;
|
||||
};
|
||||
|
||||
const track = (event: string, properties?: ITelemetryTrackProperties) => {
|
||||
telemetry.value?.track(event, properties);
|
||||
};
|
||||
|
||||
return {
|
||||
init,
|
||||
track,
|
||||
};
|
||||
});
|
|
@ -60,7 +60,6 @@ import { useCloudPlanStore } from '@/stores/cloudPlan.store';
|
|||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { hasPermission } from '@/utils/rbac/permissions';
|
||||
import { useTelemetryStore } from '@/stores/telemetry.store';
|
||||
import { useUsersStore } from '@/stores/users.store';
|
||||
import { dismissBannerPermanently } from '@/api/ui';
|
||||
import type { BannerName } from 'n8n-workflow';
|
||||
|
@ -73,6 +72,7 @@ import {
|
|||
} from './ui.utils';
|
||||
import { computed, ref } from 'vue';
|
||||
import type { Connection } from '@vue-flow/core';
|
||||
import { useTelemetry } from '@/composables/useTelemetry';
|
||||
|
||||
let savedTheme: ThemeOption = 'system';
|
||||
try {
|
||||
|
@ -205,7 +205,7 @@ export const useUIStore = defineStore(STORES.UI, () => {
|
|||
const settingsStore = useSettingsStore();
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
const rootStore = useRootStore();
|
||||
const telemetryStore = useTelemetryStore();
|
||||
const telemetry = useTelemetry();
|
||||
const cloudPlanStore = useCloudPlanStore();
|
||||
const userStore = useUsersStore();
|
||||
|
||||
|
@ -564,7 +564,7 @@ export const useUIStore = defineStore(STORES.UI, () => {
|
|||
const { executionsLeft, workflowsLeft } = usageLeft;
|
||||
const deploymentType = settingsStore.deploymentType;
|
||||
|
||||
telemetryStore.track('User clicked upgrade CTA', {
|
||||
telemetry.track('User clicked upgrade CTA', {
|
||||
source,
|
||||
isTrial: userIsTrialing,
|
||||
deploymentType,
|
||||
|
|
61
packages/editor-ui/src/stores/users.store.test.ts
Normal file
61
packages/editor-ui/src/stores/users.store.test.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
import type { CurrentUserResponse } from '@/Interface';
|
||||
import { useUsersStore } from './users.store';
|
||||
import { createPinia, setActivePinia } from 'pinia';
|
||||
|
||||
const { loginCurrentUser, identify } = vi.hoisted(() => {
|
||||
return {
|
||||
loginCurrentUser: vi.fn(),
|
||||
identify: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@/api/users', () => ({
|
||||
loginCurrentUser,
|
||||
}));
|
||||
|
||||
vi.mock('@/composables/useTelemetry', () => ({
|
||||
useTelemetry: vi.fn(() => ({
|
||||
identify,
|
||||
})),
|
||||
}));
|
||||
|
||||
vi.mock('@/stores/root.store', () => ({
|
||||
useRootStore: vi.fn(() => ({
|
||||
instanceId: 'test-instance-id',
|
||||
})),
|
||||
}));
|
||||
|
||||
const mockUser: CurrentUserResponse = {
|
||||
id: '1',
|
||||
firstName: 'John Doe',
|
||||
role: 'global:owner',
|
||||
isPending: false,
|
||||
};
|
||||
|
||||
describe('users.store', () => {
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
setActivePinia(createPinia());
|
||||
});
|
||||
|
||||
describe('loginWithCookie', () => {
|
||||
it('should set current user', async () => {
|
||||
const usersStore = useUsersStore();
|
||||
|
||||
loginCurrentUser.mockResolvedValueOnce(mockUser);
|
||||
|
||||
await usersStore.loginWithCookie();
|
||||
|
||||
expect(loginCurrentUser).toHaveBeenCalled();
|
||||
expect(usersStore.currentUserId).toEqual(mockUser.id);
|
||||
expect(usersStore.currentUser).toEqual({
|
||||
...mockUser,
|
||||
fullName: `${mockUser.firstName} `,
|
||||
isDefaultUser: false,
|
||||
isPendingUser: false,
|
||||
});
|
||||
|
||||
expect(identify).toHaveBeenCalledWith('test-instance-id', mockUser.id);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -16,7 +16,7 @@ import type {
|
|||
} from '@/Interface';
|
||||
import { getPersonalizedNodeTypes } from '@/utils/userUtils';
|
||||
import { defineStore } from 'pinia';
|
||||
import { useRootStore } from './root.store';
|
||||
import { useRootStore } from '@/stores/root.store';
|
||||
import { usePostHog } from './posthog.store';
|
||||
import { useSettingsStore } from './settings.store';
|
||||
import { useUIStore } from './ui.store';
|
||||
|
@ -28,6 +28,7 @@ import type { Scope } from '@n8n/permissions';
|
|||
import * as invitationsApi from '@/api/invitation';
|
||||
import { useNpsSurveyStore } from './npsSurvey.store';
|
||||
import { computed, ref } from 'vue';
|
||||
import { useTelemetry } from '@/composables/useTelemetry';
|
||||
|
||||
const _isPendingUser = (user: IUserResponse | null) => !!user?.isPending;
|
||||
const _isInstanceOwner = (user: IUserResponse | null) => user?.role === ROLE.Owner;
|
||||
|
@ -48,6 +49,7 @@ export const useUsersStore = defineStore(STORES.USERS, () => {
|
|||
const rootStore = useRootStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const cloudPlanStore = useCloudPlanStore();
|
||||
const telemetry = useTelemetry();
|
||||
|
||||
// Composables
|
||||
|
||||
|
@ -115,6 +117,7 @@ export const useUsersStore = defineStore(STORES.USERS, () => {
|
|||
|
||||
const defaultScopes: Scope[] = [];
|
||||
RBACStore.setGlobalScopes(user.globalScopes || defaultScopes);
|
||||
telemetry.identify(rootStore.instanceId, user.id);
|
||||
postHogStore.init(user.featureFlags);
|
||||
npsSurveyStore.setupNpsSurveyOnLogin(user.id, user.settings);
|
||||
};
|
||||
|
@ -142,6 +145,7 @@ export const useUsersStore = defineStore(STORES.USERS, () => {
|
|||
const unsetCurrentUser = () => {
|
||||
currentUserId.value = null;
|
||||
currentUserCloudInfo.value = null;
|
||||
telemetry.reset();
|
||||
RBACStore.setGlobalScopes([]);
|
||||
};
|
||||
|
||||
|
@ -373,11 +377,8 @@ export const useUsersStore = defineStore(STORES.USERS, () => {
|
|||
globalRoleName,
|
||||
personalizedNodeTypes,
|
||||
addUsers,
|
||||
setCurrentUser,
|
||||
loginWithCookie,
|
||||
initialize,
|
||||
unsetCurrentUser,
|
||||
deleteUserById,
|
||||
setPersonalizationAnswers,
|
||||
loginWithCreds,
|
||||
logout,
|
||||
|
|
Loading…
Reference in a new issue