PromucFlow_constructor/app/client/src/usagePulse/index.ts
Ankita Kinger 271fe95d94
chore: Add analytics event to track telemetry is disabled & update properties for INVITE_USER event (#24042)
## Description

- Add analytics event to track telemetry is disabled
- Update properties for INVITE_USER event
- Updating `@appsmith` imports

#### PR fixes following issue(s)
Fixes [#1514](https://github.com/appsmithorg/appsmith-ee/issues/1514)
[#23754](https://github.com/appsmithorg/appsmith/issues/23754)

#### Type of change
- Chore (housekeeping or task changes that don't impact user perception)

## Testing

#### How Has This Been Tested?
- [x] Manual
- [ ] Jest
- [ ] Cypress

## Checklist:
#### Dev activity
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Test-plan-implementation#speedbreaker-features-to-consider-for-every-change)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans/_edit#areas-of-interest)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
2023-06-06 02:57:40 +05:30

156 lines
4.7 KiB
TypeScript

import {
getAppViewerPageIdFromPath,
isEditorPath,
isViewerPath,
} from "@appsmith/pages/Editor/Explorer/helpers";
import history from "utils/history";
import { fetchWithRetry, getUsagePulsePayload } from "./utils";
import {
PULSE_API_ENDPOINT,
PULSE_API_MAX_RETRY_COUNT,
PULSE_API_RETRY_TIMEOUT,
PULSE_INTERVAL,
USER_ACTIVITY_LISTENER_EVENTS,
} from "@appsmith/constants/UsagePulse";
import PageApi from "api/PageApi";
import { APP_MODE } from "entities/App";
import type { FetchApplicationResponse } from "@appsmith/api/ApplicationApi";
import type { AxiosResponse } from "axios";
import { getFirstTimeUserOnboardingIntroModalVisibility } from "utils/storage";
class UsagePulse {
static userAnonymousId: string | undefined;
static Timer: ReturnType<typeof setTimeout>;
static unlistenRouteChange: () => void;
static isTelemetryEnabled: boolean;
static isAnonymousUser: boolean;
/*
* Function to check if the given URL is trakable or not.
* app builder and viewer urls are trackable
*/
static async isTrackableUrl(path: string) {
if (isViewerPath(path)) {
if (UsagePulse.isAnonymousUser) {
/*
In App view mode for non-logged in user, first we must have to check if the app is public or not.
If it is private app with non-logged in user, we do not send pulse at this point instead we redirect to the login page.
And for login page no usage pulse is required.
*/
const response: AxiosResponse<FetchApplicationResponse, any> =
await PageApi.fetchAppAndPages({
pageId: getAppViewerPageIdFromPath(path),
mode: APP_MODE.PUBLISHED,
});
const { data } = response.data || {};
if (data?.application && !data.application.isPublic) {
return false;
}
}
return true;
} else if (isEditorPath(path)) {
/*
During onboarding we show the Intro Modal and let user use the app for the first time.
During this exploration period, we do no send usage pulse.
*/
const isFirstTimeOnboarding =
await getFirstTimeUserOnboardingIntroModalVisibility();
if (!isFirstTimeOnboarding) return true;
}
return false;
}
static sendPulse() {
const payload = getUsagePulsePayload(
UsagePulse.isTelemetryEnabled,
UsagePulse.isAnonymousUser,
);
const fetchWithRetryConfig = {
url: PULSE_API_ENDPOINT,
payload,
retries: PULSE_API_MAX_RETRY_COUNT,
retryTimeout: PULSE_API_RETRY_TIMEOUT,
};
fetchWithRetry(fetchWithRetryConfig);
}
static registerActivityListener() {
USER_ACTIVITY_LISTENER_EVENTS.forEach((event) => {
window.document.body.addEventListener(event, UsagePulse.track);
});
}
static deregisterActivityListener() {
USER_ACTIVITY_LISTENER_EVENTS.forEach((event) => {
window.document.body.removeEventListener(event, UsagePulse.track);
});
}
/*
* Function to register a history change event and trigger
* a callback and unlisten when the user goes to a trackable URL
*/
static async watchForTrackableUrl(callback: () => void) {
UsagePulse.unlistenRouteChange = history.listen(async () => {
if (await UsagePulse.isTrackableUrl(window.location.pathname)) {
UsagePulse.unlistenRouteChange();
setTimeout(callback, 0);
}
});
UsagePulse.deregisterActivityListener();
}
/*
* Function that suspends active tracking listeners
* and schedules when next listeners should be registered.
*/
static scheduleNextActivityListeners() {
UsagePulse.deregisterActivityListener();
UsagePulse.Timer = setTimeout(
UsagePulse.registerActivityListener,
PULSE_INTERVAL,
);
}
/*
* Point of entry for the user tracking
*/
static startTrackingActivity(
isTelemetryEnabled: boolean,
isAnonymousUser: boolean,
) {
UsagePulse.isTelemetryEnabled = isTelemetryEnabled;
UsagePulse.isAnonymousUser = isAnonymousUser;
UsagePulse.track();
}
/*
* triggers a pulse and schedules the pulse , if user is on a trackable url, otherwise
* registers listeners to wait for the user to go to a trackable url
*/
static async track() {
if (await UsagePulse.isTrackableUrl(window.location.pathname)) {
UsagePulse.sendPulse();
UsagePulse.scheduleNextActivityListeners();
} else {
await UsagePulse.watchForTrackableUrl(UsagePulse.track);
}
}
/*
* Function to cleanup states and listeners
*/
static stopTrackingActivity() {
UsagePulse.userAnonymousId = undefined;
clearTimeout(UsagePulse.Timer);
UsagePulse.unlistenRouteChange && UsagePulse.unlistenRouteChange();
UsagePulse.deregisterActivityListener();
}
}
export default UsagePulse;