Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Analytics util refactor #38089

Merged
merged 42 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
fe09402
chore: Make segment singleton
hetunandu Dec 11, 2024
8d28d95
fix: type error
hetunandu Dec 11, 2024
c193689
Merge branch 'release' into chore/analytics-util-refactor
hetunandu Dec 11, 2024
3795506
chore: correct split for logEvent
hetunandu Dec 11, 2024
e9090d2
Merge branch 'release' into chore/analytics-util-refactor
hetunandu Dec 11, 2024
d62d1c1
chore: correct split for identifyUser
hetunandu Dec 11, 2024
c7b34a6
fix type error
hetunandu Dec 11, 2024
8f6216d
chore: remove zipy
hetunandu Dec 11, 2024
0dc6a20
chore: Other changes to separate concerns
hetunandu Dec 12, 2024
a5fe8de
Merge branch 'release' into chore/analytics-util-refactor
hetunandu Dec 12, 2024
9a59649
fix: user source getter
hetunandu Dec 12, 2024
11034ef
Merge branch 'release' into chore/analytics-util-refactor
hetunandu Dec 12, 2024
0ef89c7
fix: TrackedUser error handling
hetunandu Dec 12, 2024
7009e5d
chore: Mask all mixpanel recordings
hetunandu Dec 13, 2024
be6a625
chore: Mixpanel should not record admin settings
hetunandu Dec 13, 2024
713cf05
chore: Improve segment anonymousId get
hetunandu Dec 13, 2024
74a1ddd
chore: AnalyticsUtil.tsx improvements
hetunandu Dec 13, 2024
a383ef3
remove other ee concerns from ce
hetunandu Dec 13, 2024
e3f8768
chore: null checks
hetunandu Dec 13, 2024
61986b2
Revert "chore: AnalyticsUtil.tsx improvements"
hetunandu Dec 13, 2024
08a0d40
chore: Fix Smartlook init
hetunandu Dec 16, 2024
864a829
Merge branch 'release' into chore/analytics-util-refactor
hetunandu Dec 16, 2024
caca6fd
chore: convert class into object
hetunandu Dec 16, 2024
6cd44a9
chore: export getEventExtraProperties
hetunandu Dec 16, 2024
cbbcc1a
verify theory
hetunandu Dec 16, 2024
0bf6f87
chore: add cypress logging
hetunandu Dec 16, 2024
1c1da03
chore: add back editor line
hetunandu Dec 16, 2024
2549d3c
Revert "chore: add cypress logging"
hetunandu Dec 16, 2024
a9c3d68
chore: segment init change
hetunandu Dec 17, 2024
949076c
chore: Try toasts
hetunandu Dec 17, 2024
250121f
avoid waiting for segment init
hetunandu Dec 17, 2024
de8acdd
Merge branch 'release' into chore/analytics-util-refactor
hetunandu Dec 17, 2024
0730a4e
chore: Better splitting
hetunandu Dec 17, 2024
fb643f5
chore: check if its the state issue
hetunandu Dec 17, 2024
719dd1e
Merge branch 'release' into chore/analytics-util-refactor
hetunandu Dec 17, 2024
071b86b
fix: Type error from latest changes
hetunandu Dec 17, 2024
414657d
Merge branch 'release' into chore/analytics-util-refactor
hetunandu Dec 18, 2024
34a639a
fix: chore test another change
hetunandu Dec 18, 2024
a79138a
chore: Updte tracked user usage
hetunandu Dec 18, 2024
25ac6ce
chore: Revert wait added in pull #19122
hetunandu Dec 18, 2024
aebbbd4
chore: Avoid adding more dependencies
hetunandu Dec 18, 2024
87d3493
Merge branch 'release' into chore/analytics-util-refactor
hetunandu Dec 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
"@redux-saga/core": "1.1.3",
"@redux-saga/types": "1.2.1",
"@reduxjs/toolkit": "^2.4.0",
"@segment/analytics-next": "^1.76.0",
"@sentry/react": "^6.2.4",
"@shared/ast": "workspace:^",
"@shared/dsl": "workspace:^",
Expand Down
16 changes: 0 additions & 16 deletions app/client/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
return result;
};
const CLOUD_HOSTING = parseConfig('{{env "APPSMITH_CLOUD_HOSTING"}}');
const ZIPY_KEY = parseConfig('{{env "APPSMITH_ZIPY_SDK_KEY"}}');
const AIRGAPPED = parseConfig('{{env "APPSMITH_AIRGAP_ENABLED"}}');
const REO_CLIENT_ID = parseConfig('{{env "APPSMITH_REO_CLIENT_ID"}}');
</script>
Expand All @@ -64,21 +63,6 @@
})()
%>
</script>
<script>
if (CLOUD_HOSTING && ZIPY_KEY) {
const script = document.createElement("script");
script.crossOrigin = "anonymous";
script.defer = true;
script.src = "https://cdn.zipy.ai/sdk/v1.0/zipy.min.umd.js";
script.onload = () => {
window.zipy && window.zipy.init(ZIPY_KEY);
};
const head = document.getElementsByTagName("head")[0];
head && head.appendChild(script);
}


</script>

<!-- Start of Reo Javascript -->
<script type="text/javascript">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type { InternalAxiosRequestConfig } from "axios";
import type { ID } from "@segment/analytics-next";

export const addAnonymousUserIdHeader = (
config: InternalAxiosRequestConfig,
options: { anonymousId?: string; segmentEnabled?: boolean },
options: { anonymousId: ID; segmentEnabled?: boolean },
) => {
const { anonymousId, segmentEnabled } = options;

Expand Down
35 changes: 6 additions & 29 deletions app/client/src/ce/sagas/analyticsSaga.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { getCurrentUser } from "selectors/usersSelectors";
import { getInstanceId } from "ee/selectors/tenantSelectors";
import { call, select } from "redux-saga/effects";
import type { APP_MODE } from "entities/App";
Expand All @@ -10,44 +9,37 @@ import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import { getAppMode } from "ee/selectors/entitiesSelector";
import type { AppState } from "ee/reducers";
import { getWidget } from "sagas/selectors";
import { getUserSource } from "ee/utils/AnalyticsUtil";
import { getCurrentApplication } from "ee/selectors/applicationSelectors";

export interface UserAndAppDetails {
export interface AppDetails {
pageId: string;
appId: string;
appMode: APP_MODE | undefined;
appName: string;
isExampleApp: boolean;
userId: string;
email: string;
source: string;
instanceId: string;
}

export function* getUserAndAppDetails() {
export function* getAppDetails() {
const appMode: ReturnType<typeof getAppMode> = yield select(getAppMode);
const currentApp: ReturnType<typeof getCurrentApplication> = yield select(
getCurrentApplication,
);
const user: ReturnType<typeof getCurrentUser> = yield select(getCurrentUser);
const instanceId: ReturnType<typeof getInstanceId> =
yield select(getInstanceId);
const pageId: ReturnType<typeof getCurrentPageId> =
yield select(getCurrentPageId);
const userAndAppDetails: UserAndAppDetails = {

const appDetails: AppDetails = {
pageId,
appId: currentApp?.id || "",
appMode,
appName: currentApp?.name || "",
isExampleApp: currentApp?.appIsExample || false,
userId: user?.username || "",
email: user?.email || "",
source: getUserSource(),
instanceId: instanceId,
};

return userAndAppDetails;
return appDetails;
}
export function* logDynamicTriggerExecution({
dynamicTrigger,
Expand All @@ -65,13 +57,10 @@ export function* logDynamicTriggerExecution({
appId,
appMode,
appName,
email,
instanceId,
isExampleApp,
pageId,
source,
userId,
}: UserAndAppDetails = yield call(getUserAndAppDetails);
}: AppDetails = yield call(getAppDetails);
const widget: ReturnType<typeof getWidget> | undefined = yield select(
(state: AppState) => getWidget(state, triggerMeta.source?.id || ""),
);
Expand All @@ -89,12 +78,6 @@ export function* logDynamicTriggerExecution({
appMode,
appName,
isExampleApp,
userData: {
userId,
email,
appId,
source,
},
widgetName: widget?.widgetName,
widgetType: widget?.type,
propertyName: triggerMeta.triggerPropertyName,
Expand All @@ -114,12 +97,6 @@ export function* logDynamicTriggerExecution({
appMode,
appName,
isExampleApp,
userData: {
userId,
email,
appId,
source,
},
widgetName: widget?.widgetName,
widgetType: widget?.type,
propertyName: triggerMeta.triggerPropertyName,
Expand Down
11 changes: 4 additions & 7 deletions app/client/src/ce/sagas/userSagas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ import {
getFirstTimeUserOnboardingApplicationIds,
getFirstTimeUserOnboardingIntroModalVisibility,
} from "utils/storage";
import { initializeAnalyticsAndTrackers } from "utils/AppsmithUtils";
import { getAppsmithConfigs } from "ee/configs";
import { getSegmentState } from "selectors/analyticsSelectors";
import {
Expand Down Expand Up @@ -134,13 +133,11 @@ export function* getCurrentUserSaga(action?: {
}

function* initTrackers(currentUser: User) {
const initializeSentry = initializeAnalyticsAndTrackers(currentUser);

const sentryInitialized: boolean = yield initializeSentry;

if (sentryInitialized) {
try {
yield call(AnalyticsUtil.initialize, currentUser);
yield put(segmentInitSuccess());
} else {
} catch (e) {
log.error(e);
yield put(segmentInitUncertain());
}
}
Expand Down
115 changes: 115 additions & 0 deletions app/client/src/ce/utils/Analytics/trackedUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { ANONYMOUS_USERNAME, type User } from "constants/userConstants";
import { getAppsmithConfigs } from "ee/configs";
import { sha256 } from "js-sha256";

interface TrackedUserProperties {
userId: string;
source: string;
email?: string;
name?: string;
emailVerified?: boolean;
}

/**
* Function to get the application id from the URL
* @param location current location object based on URL
* @returns application id
*/
export function getApplicationId(location: Location) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is technically not a user property. But because till now we have been sending this data as part of the userData object, I am not separating them to avoid breaking any charts

const pathSplit = location.pathname.split("/");
const applicationsIndex = pathSplit.findIndex(
(path) => path === "applications",
);

if (applicationsIndex === -1 || applicationsIndex + 1 >= pathSplit.length) {
return undefined;
}

return pathSplit[applicationsIndex + 1];
}

class TrackedUser {
private static instance: TrackedUser;
private readonly user: User;
private readonly userId: string;
public readonly selfHosted: boolean;

protected constructor(user: User) {
this.user = user;
const { cloudHosting, segment } = getAppsmithConfigs();

this.selfHosted = !(segment.apiKey || cloudHosting);

if (this.selfHosted) {
this.userId = sha256(user.username);
} else {
this.userId = user.username;
}
}

static init(user: User) {
if (!TrackedUser.instance) {
TrackedUser.instance = new TrackedUser(user);
}
}

static getInstance(): TrackedUser {
if (!TrackedUser.instance) {
throw new Error("TrackedUser is not initialized. Call init() first.");
}

return TrackedUser.instance;
}

protected getUserSource(): string {
return this.selfHosted ? "ce" : "cloud";
}

public getUser(): TrackedUserProperties {
if (this.selfHosted) {
return this.getAnonymousUserDetails();
} else {
return this.getAllUserDetails();
}
}

public getEventUserProperties() {
const { email, userId } = this.getUser();

if (this.userId === ANONYMOUS_USERNAME) {
return undefined;
}

const appId = getApplicationId(window.location);

return {
userId,
email,
appId: this.selfHosted ? undefined : appId,
};
}

private getAllUserDetails() {
const { email, emailVerified, name } = this.user;
const source = this.getUserSource();
ankitakinger marked this conversation as resolved.
Show resolved Hide resolved

return {
userId: this.userId,
source,
email,
name,
emailVerified,
};
}

private getAnonymousUserDetails() {
const source = this.getUserSource();
ankitakinger marked this conversation as resolved.
Show resolved Hide resolved

return {
userId: this.userId,
source,
};
}
}

export default TrackedUser;
Loading
Loading