fix: UsagePulse initialisation flow (#38555)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
parent
dfd7fdee97
commit
388fd81d3b
8
app/client/src/actions/analyticsActions.ts
Normal file
8
app/client/src/actions/analyticsActions.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||
|
||||
export const segmentInitSuccess = () => ({
|
||||
type: ReduxActionTypes.SEGMENT_INITIALIZED,
|
||||
});
|
||||
export const segmentInitUncertain = () => ({
|
||||
type: ReduxActionTypes.SEGMENT_INIT_UNCERTAIN,
|
||||
});
|
||||
|
|
@ -1216,6 +1216,8 @@ const TenantActionErrorTypes = {
|
|||
};
|
||||
|
||||
const AnalyticsActionTypes = {
|
||||
SEGMENT_INITIALIZED: "SEGMENT_INITIALIZED",
|
||||
SEGMENT_INIT_UNCERTAIN: "SEGMENT_INIT_UNCERTAIN",
|
||||
SET_BUILDING_BLOCK_DRAG_START_TIME: "SET_BUILDING_BLOCK_DRAG_START_TIME",
|
||||
RESET_BUILDING_BLOCK_DRAG_START_TIME: "RESET_BUILDING_BLOCK_DRAG_START_TIME",
|
||||
SEND_ANALYTICS_FOR_SIDE_BY_SIDE_HOVER:
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ import type { CanvasLevelsReduxState } from "reducers/entityReducers/autoHeightR
|
|||
import type { LintErrorsStore } from "reducers/lintingReducers/lintErrorsReducers";
|
||||
import lintErrorReducer from "reducers/lintingReducers";
|
||||
import type { AutoHeightUIState } from "reducers/uiReducers/autoHeightReducer";
|
||||
import type { AnalyticsReduxState } from "reducers/uiReducers/analyticsReducer";
|
||||
import type { MetaWidgetsReduxState } from "reducers/entityReducers/metaWidgetsReducer";
|
||||
import type { layoutConversionReduxState } from "reducers/uiReducers/layoutConversionReducer";
|
||||
import type { OneClickBindingState } from "reducers/uiReducers/oneClickBindingReducer";
|
||||
|
|
@ -94,6 +95,7 @@ export const reducerObject = {
|
|||
export interface AppState {
|
||||
ui: {
|
||||
consolidatedPageLoad: ConsolidatedPageLoadState;
|
||||
analytics: AnalyticsReduxState;
|
||||
editor: EditorReduxState;
|
||||
propertyPane: PropertyPaneReduxState;
|
||||
tableFilterPane: TableFilterPaneReduxState;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import { editorContextReducer } from "ee/reducers/uiReducers/editorContextReduce
|
|||
import libraryReducer from "reducers/uiReducers/libraryReducer";
|
||||
import appSettingsPaneReducer from "reducers/uiReducers/appSettingsPaneReducer";
|
||||
import autoHeightUIReducer from "reducers/uiReducers/autoHeightReducer";
|
||||
import analyticsReducer from "reducers/uiReducers/analyticsReducer";
|
||||
import layoutConversionReducer from "reducers/uiReducers/layoutConversionReducer";
|
||||
import oneClickBindingReducer from "reducers/uiReducers/oneClickBindingReducer";
|
||||
import activeFieldReducer from "reducers/uiReducers/activeFieldEditorReducer";
|
||||
|
|
@ -48,6 +49,7 @@ import consolidatedPageLoadReducer from "reducers/uiReducers/consolidatedPageLoa
|
|||
import { pluginActionReducer } from "PluginActionEditor/store";
|
||||
|
||||
export const uiReducerObject = {
|
||||
analytics: analyticsReducer,
|
||||
editor: editorReducer,
|
||||
errors: errorReducer,
|
||||
propertyPane: propertyPaneReducer,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,12 @@
|
|||
import { call, fork, put, select, take } from "redux-saga/effects";
|
||||
import {
|
||||
all,
|
||||
call,
|
||||
fork,
|
||||
put,
|
||||
select,
|
||||
take,
|
||||
type TakeEffect,
|
||||
} from "redux-saga/effects";
|
||||
import type {
|
||||
ReduxAction,
|
||||
ReduxActionWithPromise,
|
||||
|
|
@ -75,6 +83,11 @@ import type {
|
|||
import { selectFeatureFlags } from "ee/selectors/featureFlagsSelectors";
|
||||
import { getFromServerWhenNoPrefetchedResult } from "sagas/helper";
|
||||
import type { SessionRecordingConfig } from "utils/Analytics/mixpanel";
|
||||
import {
|
||||
segmentInitSuccess,
|
||||
segmentInitUncertain,
|
||||
} from "actions/analyticsActions";
|
||||
import { getSegmentState } from "selectors/analyticsSelectors";
|
||||
|
||||
export function* getCurrentUserSaga(action?: {
|
||||
payload?: { userProfile?: ApiResponse };
|
||||
|
|
@ -139,44 +152,82 @@ function* getSessionRecordingConfig() {
|
|||
|
||||
function* initTrackers(currentUser: User) {
|
||||
try {
|
||||
const isFFFetched: boolean = yield select(getFeatureFlagsFetched);
|
||||
|
||||
if (!isFFFetched) {
|
||||
yield take(ReduxActionTypes.FETCH_FEATURE_FLAGS_SUCCESS);
|
||||
}
|
||||
|
||||
const sessionRecordingConfig: SessionRecordingConfig = yield call(
|
||||
getSessionRecordingConfig,
|
||||
);
|
||||
|
||||
yield call(AnalyticsUtil.initialize, currentUser, sessionRecordingConfig);
|
||||
yield put(segmentInitSuccess());
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
yield put(segmentInitUncertain());
|
||||
}
|
||||
}
|
||||
|
||||
function* waitForInitialization() {
|
||||
const currentUser: User = yield select(getCurrentUser);
|
||||
// Dependents for starting tracking
|
||||
const isFFFetched: boolean = yield select(getFeatureFlagsFetched);
|
||||
const isSegmentInitialized: string | undefined =
|
||||
yield select(getSegmentState);
|
||||
|
||||
const waits: TakeEffect[] = [];
|
||||
|
||||
// FF is required to know if GAC is enabled for the user
|
||||
if (!isFFFetched) {
|
||||
yield fork(fetchFeatureFlagsInit);
|
||||
waits.push(take(ReduxActionTypes.FETCH_FEATURE_FLAGS_SUCCESS));
|
||||
}
|
||||
|
||||
// If the user is anonymous, we need to wait for the editor or viewer to initialize
|
||||
if (currentUser?.isAnonymous) {
|
||||
waits.push(
|
||||
take([
|
||||
ReduxActionTypes.INITIALIZE_EDITOR_SUCCESS,
|
||||
ReduxActionTypes.INITIALIZE_PAGE_VIEWER_SUCCESS,
|
||||
]),
|
||||
);
|
||||
|
||||
// If the user is anonymous, we need to wait for the segment to initialize
|
||||
// As it will provide the anonymous id
|
||||
if (isSegmentInitialized === undefined) {
|
||||
waits.push(
|
||||
take([
|
||||
ReduxActionTypes.SEGMENT_INITIALIZED,
|
||||
ReduxActionTypes.SEGMENT_INIT_UNCERTAIN,
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Only wait for actions that are still pending
|
||||
yield all(waits);
|
||||
}
|
||||
|
||||
function* restartUserTracking() {
|
||||
const currentUser: User = yield select(getCurrentUser);
|
||||
const { enableTelemetry } = currentUser;
|
||||
const isAirgappedInstance = isAirgapped();
|
||||
|
||||
const isFFFetched: boolean = yield select(getFeatureFlagsFetched);
|
||||
|
||||
if (!isFFFetched) {
|
||||
yield call(fetchFeatureFlagsInit);
|
||||
yield take(ReduxActionTypes.FETCH_FEATURE_FLAGS_SUCCESS);
|
||||
}
|
||||
|
||||
const featureFlags: FeatureFlags = yield select(selectFeatureFlags);
|
||||
|
||||
const isGACEnabled = featureFlags?.license_gac_enabled;
|
||||
|
||||
const isFreeLicense = !isGACEnabled;
|
||||
|
||||
if (!isAirgappedInstance) {
|
||||
// We need to stop and start tracking activity to ensure that the tracking from previous session is not carried forward
|
||||
// We need to stop and start tracking activity to ensure that the tracking
|
||||
// from previous session is not carried forward
|
||||
yield call(UsagePulse.stopTrackingActivity);
|
||||
|
||||
if (currentUser?.isAnonymous) {
|
||||
yield take([
|
||||
ReduxActionTypes.INITIALIZE_EDITOR_SUCCESS,
|
||||
ReduxActionTypes.INITIALIZE_PAGE_VIEWER_SUCCESS,
|
||||
]);
|
||||
}
|
||||
// Wait for any items that are required for tracking
|
||||
yield call(waitForInitialization);
|
||||
|
||||
const featureFlags: FeatureFlags = yield select(selectFeatureFlags);
|
||||
|
||||
const isGACEnabled = featureFlags?.license_gac_enabled;
|
||||
|
||||
const isFreeLicense = !isGACEnabled;
|
||||
|
||||
yield call(
|
||||
UsagePulse.startTrackingActivity,
|
||||
|
|
@ -191,12 +242,14 @@ export function* runUserSideEffectsSaga() {
|
|||
const currentUser: User = yield select(getCurrentUser);
|
||||
const { enableTelemetry } = currentUser;
|
||||
|
||||
yield fork(restartUserTracking);
|
||||
|
||||
if (enableTelemetry) {
|
||||
yield fork(initTrackers, currentUser);
|
||||
} else {
|
||||
yield put(segmentInitSuccess());
|
||||
}
|
||||
|
||||
yield fork(restartUserTracking);
|
||||
|
||||
if (currentUser.emptyInstance) {
|
||||
history.replace(SETUP);
|
||||
}
|
||||
|
|
|
|||
35
app/client/src/reducers/uiReducers/analyticsReducer.ts
Normal file
35
app/client/src/reducers/uiReducers/analyticsReducer.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||
import { createReducer } from "utils/ReducerUtils";
|
||||
|
||||
export type SegmentState = "INIT_SUCCESS" | "INIT_UNCERTAIN";
|
||||
export const initialState: AnalyticsReduxState = {
|
||||
telemetry: {},
|
||||
};
|
||||
|
||||
export interface AnalyticsReduxState {
|
||||
telemetry: {
|
||||
segmentState?: SegmentState;
|
||||
};
|
||||
}
|
||||
|
||||
export const handlers = {
|
||||
[ReduxActionTypes.SEGMENT_INITIALIZED]: (
|
||||
state: AnalyticsReduxState,
|
||||
): AnalyticsReduxState => ({
|
||||
...state,
|
||||
telemetry: {
|
||||
...state.telemetry,
|
||||
segmentState: "INIT_SUCCESS",
|
||||
},
|
||||
}),
|
||||
[ReduxActionTypes.SEGMENT_INIT_UNCERTAIN]: (
|
||||
state: AnalyticsReduxState,
|
||||
): AnalyticsReduxState => ({
|
||||
...state,
|
||||
telemetry: {
|
||||
...state.telemetry,
|
||||
segmentState: "INIT_UNCERTAIN",
|
||||
},
|
||||
}),
|
||||
};
|
||||
export default createReducer(initialState, handlers);
|
||||
4
app/client/src/selectors/analyticsSelectors.ts
Normal file
4
app/client/src/selectors/analyticsSelectors.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import type { AppState } from "ee/reducers";
|
||||
|
||||
export const getSegmentState = (state: AppState) =>
|
||||
state.ui.analytics.telemetry.segmentState;
|
||||
Loading…
Reference in New Issue
Block a user