[WEB-4423] refactor: event trackers (#7289)

* feat: event tracker helper

* feat: track click events for `data-ph-element`

* fix: handled click events

* fix: handled name

* chore: tracker element updates

* chore: remove export

* chore: tracker element type

* chore: track element and event helper.

* chore: minor improvements

* chore: minor refactors

* fix: workspace events

* fix: added slug

* fix: changes nomenclature

* fix: nomenclature

* chore: update event tracker helper types

* fix: data id

* refactor: cycle events (#7290)

* chore: update event tracker helper types

* refactor: cycle events

* refactor: cycle events

* refactor: cycle event tracker

* chore: update tracker elements

* chore: check for closest element with data-ph-element attribute

---------

Co-authored-by: Prateek Shourya <prateekshourya@Prateeks-MacBook-Pro.local>

* Refactor module events (#7291)

* chore: update event tracker helper types

* refactor: cycle events

* refactor: cycle events

* refactor: cycle event tracker

* refactor: module tracker event and element

* chore: update tracker element

* chore: revert unnecessary changes

---------

Co-authored-by: Prateek Shourya <prateekshourya@Prateeks-MacBook-Pro.local>

* refactor: global views, product tour, notifications, onboarding, users and sidebar related events

* chore: member tracker events (#7302)

* chore: member-tracker-events

* fix: constants

* refactor: update event tracker constants

* refactor: auth related event trackers (#7306)

* Chore: state events (#7307)

* chore: state events

* fix: refactor

* chore: project events (#7305)

* chore: project-events

* fix: refactor

* fix: removed hardcoded values

* fix: github redirection event

* chore: project page tracker events (#7304)

* added events for most page events

* refactor: simplify lock button event handling in PageLockControl

---------

Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com>
Co-authored-by: M. Palanikannan <73993394+Palanikannan1437@users.noreply.github.com>

* chore: minor cleanup and import fixes

* refactor: added tracker elements for buttons (#7308)

Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>

* fix: event type

* refactor: posthog group event

* chore: removed instances of event tracker (#7309)

* refactor: remove event tracker stores and hooks

* refactor: remove event tracker store

* fix: build errors

* clean up event tracker payloads

* fix: coderabbit suggestions

---------

Co-authored-by: Prateek Shourya <prateekshourya@Prateeks-MacBook-Pro.local>
Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com>
Co-authored-by: M. Palanikannan <73993394+Palanikannan1437@users.noreply.github.com>
Co-authored-by: Vamsi Krishna <46787868+vamsikrishnamathala@users.noreply.github.com>
This commit is contained in:
Akshita Goyal 2025-07-02 15:23:18 +05:30 committed by GitHub
parent fa9c63716c
commit cfe169c6d7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
139 changed files with 2095 additions and 1888 deletions

View file

@ -2,13 +2,13 @@
import { FC, useState } from "react";
import { observer } from "mobx-react";
import { EventProps, STATE_TRACKER_EVENTS, STATE_GROUPS } from "@plane/constants";
import { STATE_TRACKER_EVENTS, STATE_GROUPS } from "@plane/constants";
import { IState, TStateGroups, TStateOperationsCallbacks } from "@plane/types";
import { TOAST_TYPE, setToast } from "@plane/ui";
// components
import { StateForm } from "@/components/project-states";
// hooks
import { useEventTracker } from "@/hooks/store";
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
type TStateCreate = {
groupKey: TStateGroups;
@ -19,17 +19,10 @@ type TStateCreate = {
export const StateCreate: FC<TStateCreate> = observer((props) => {
const { groupKey, shouldTrackEvents, createStateCallback, handleClose } = props;
// hooks
const { captureProjectStateEvent, setTrackElement } = useEventTracker();
// states
const [loader, setLoader] = useState(false);
const captureEventIfEnabled = (props: EventProps) => {
if (shouldTrackEvents) {
captureProjectStateEvent(props);
}
};
const onCancel = () => {
setLoader(false);
handleClose();
@ -38,19 +31,16 @@ export const StateCreate: FC<TStateCreate> = observer((props) => {
const onSubmit = async (formData: Partial<IState>) => {
if (!groupKey) return { status: "error" };
if (shouldTrackEvents) {
setTrackElement("PROJECT_SETTINGS_STATE_PAGE");
}
try {
const stateResponse = await createStateCallback({ ...formData, group: groupKey });
captureEventIfEnabled({
eventName: STATE_TRACKER_EVENTS.create,
payload: {
...stateResponse,
state: "SUCCESS",
element: "Project settings states page",
},
});
const response = await createStateCallback({ ...formData, group: groupKey });
if (shouldTrackEvents)
captureSuccess({
eventName: STATE_TRACKER_EVENTS.create,
payload: {
state_group: groupKey,
id: response.id,
},
});
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success!",
@ -60,14 +50,13 @@ export const StateCreate: FC<TStateCreate> = observer((props) => {
return { status: "success" };
} catch (error) {
const errorStatus = error as unknown as { status: number; data: { error: string } };
captureEventIfEnabled({
eventName: STATE_TRACKER_EVENTS.create,
payload: {
...formData,
state: "FAILED",
element: "Project settings states page",
},
});
if (shouldTrackEvents)
captureError({
eventName: STATE_TRACKER_EVENTS.create,
payload: {
state_group: groupKey,
},
});
if (errorStatus?.status === 400) {
setToast({
type: TOAST_TYPE.ERROR,

View file

@ -2,13 +2,13 @@
import { FC, useState } from "react";
import { observer } from "mobx-react";
import { EventProps, STATE_TRACKER_EVENTS } from "@plane/constants";
import { STATE_TRACKER_EVENTS } from "@plane/constants";
import { IState, TStateOperationsCallbacks } from "@plane/types";
import { TOAST_TYPE, setToast } from "@plane/ui";
// components
import { StateForm } from "@/components/project-states";
// hooks
import { useEventTracker } from "@/hooks/store";
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
type TStateUpdate = {
state: IState;
@ -19,8 +19,6 @@ type TStateUpdate = {
export const StateUpdate: FC<TStateUpdate> = observer((props) => {
const { state, updateStateCallback, shouldTrackEvents, handleClose } = props;
// hooks
const { captureProjectStateEvent, setTrackElement } = useEventTracker();
// states
const [loader, setLoader] = useState(false);
@ -29,28 +27,20 @@ export const StateUpdate: FC<TStateUpdate> = observer((props) => {
handleClose();
};
const captureEventIfEnabled = (props: EventProps) => {
if (shouldTrackEvents) {
captureProjectStateEvent(props);
}
};
const onSubmit = async (formData: Partial<IState>) => {
if (!state.id) return { status: "error" };
if (shouldTrackEvents) {
setTrackElement("PROJECT_SETTINGS_STATE_PAGE");
}
try {
const stateResponse = await updateStateCallback(state.id, formData);
captureEventIfEnabled({
eventName: STATE_TRACKER_EVENTS.update,
payload: {
...stateResponse,
state: "SUCCESS",
element: "Project settings states page",
},
});
await updateStateCallback(state.id, formData);
if (shouldTrackEvents) {
captureSuccess({
eventName: STATE_TRACKER_EVENTS.update,
payload: {
state_group: state.group,
id: state.id,
},
});
}
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success!",
@ -73,14 +63,15 @@ export const StateUpdate: FC<TStateUpdate> = observer((props) => {
title: "Error!",
message: "State could not be updated. Please try again.",
});
captureEventIfEnabled({
eventName: STATE_TRACKER_EVENTS.update,
payload: {
...formData,
state: "FAILED",
element: "Project settings states page",
},
});
if (shouldTrackEvents) {
captureError({
eventName: STATE_TRACKER_EVENTS.update,
payload: {
state_group: state.group,
id: state.id,
},
});
}
return { status: "error" };
}
}

View file

@ -4,7 +4,7 @@ import { FC, useState, useRef } from "react";
import { observer } from "mobx-react";
import { ChevronDown, Plus } from "lucide-react";
// plane imports
import { EIconSize } from "@plane/constants";
import { EIconSize, STATE_TRACKER_ELEMENTS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { IState, TStateGroups, TStateOperationsCallbacks } from "@plane/types";
import { StateGroupIcon } from "@plane/ui";
@ -81,6 +81,7 @@ export const GroupItem: FC<TGroupItem> = observer((props) => {
</div>
<button
type="button"
data-ph-element={STATE_TRACKER_ELEMENTS.STATE_GROUP_ADD_BUTTON}
className={cn(
"flex-shrink-0 w-6 h-6 rounded flex justify-center items-center overflow-hidden transition-colors hover:bg-custom-background-80 cursor-pointer text-custom-primary-100/80 hover:text-custom-primary-100",
(!isEditable || createState) && "cursor-not-allowed text-custom-text-400 hover:text-custom-text-400"

View file

@ -4,12 +4,12 @@ import { FC, useState } from "react";
import { observer } from "mobx-react";
import { Loader, X } from "lucide-react";
// plane imports
import { EventProps, STATE_TRACKER_EVENTS } from "@plane/constants";
import { STATE_TRACKER_EVENTS, STATE_TRACKER_ELEMENTS } from "@plane/constants";
import { IState, TStateOperationsCallbacks } from "@plane/types";
import { AlertModalCore, TOAST_TYPE, Tooltip, setToast } from "@plane/ui";
import { cn } from "@plane/utils";
// hooks
import { useEventTracker } from "@/hooks/store";
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
import { usePlatformOS } from "@/hooks/use-platform-os";
type TStateDelete = {
@ -23,45 +23,39 @@ export const StateDelete: FC<TStateDelete> = observer((props) => {
const { totalStates, state, deleteStateCallback, shouldTrackEvents } = props;
// hooks
const { isMobile } = usePlatformOS();
const { captureProjectStateEvent, setTrackElement } = useEventTracker();
// states
const [isDeleteModal, setIsDeleteModal] = useState(false);
const [isDelete, setIsDelete] = useState(false);
// derived values
const isDeleteDisabled = state.default ? true : totalStates === 1 ? true : false;
const captureEventIfEnabled = (props: EventProps) => {
if (shouldTrackEvents) {
captureProjectStateEvent(props);
}
};
const handleDeleteState = async () => {
if (isDeleteDisabled) return;
if (shouldTrackEvents) {
setTrackElement("PROJECT_SETTINGS_STATE_PAGE");
}
setIsDelete(true);
try {
await deleteStateCallback(state.id);
captureEventIfEnabled({
eventName: STATE_TRACKER_EVENTS.delete,
payload: {
...state,
state: "SUCCESS",
},
});
if (shouldTrackEvents) {
captureSuccess({
eventName: STATE_TRACKER_EVENTS.delete,
payload: {
id: state.id,
},
});
}
setIsDelete(false);
} catch (error) {
const errorStatus = error as unknown as { status: number; data: { error: string } };
captureEventIfEnabled({
eventName: STATE_TRACKER_EVENTS.delete,
payload: {
...state,
state: "FAILED",
},
});
if (shouldTrackEvents) {
captureError({
eventName: STATE_TRACKER_EVENTS.delete,
payload: {
id: state.id,
},
});
}
if (errorStatus.status === 400) {
setToast({
type: TOAST_TYPE.ERROR,
@ -107,6 +101,7 @@ export const StateDelete: FC<TStateDelete> = observer((props) => {
)}
disabled={isDeleteDisabled}
onClick={() => setIsDeleteModal(true)}
data-ph-element={STATE_TRACKER_ELEMENTS.STATE_LIST_DELETE_BUTTON}
>
<Tooltip
tooltipContent={

View file

@ -10,7 +10,8 @@ import type { IState } from "@plane/types";
import { AlertModalCore, TOAST_TYPE, setToast } from "@plane/ui";
// constants
// hooks
import { useEventTracker, useProjectState } from "@/hooks/store";
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
import { useProjectState } from "@/hooks/store";
type TStateDeleteModal = {
isOpen: boolean;
@ -24,8 +25,6 @@ export const StateDeleteModal: React.FC<TStateDeleteModal> = observer((props) =>
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
// router
const { workspaceSlug } = useParams();
// store hooks
const { captureProjectStateEvent } = useEventTracker();
const { deleteState } = useProjectState();
const handleClose = () => {
@ -40,11 +39,10 @@ export const StateDeleteModal: React.FC<TStateDeleteModal> = observer((props) =>
await deleteState(workspaceSlug.toString(), data.project_id, data.id)
.then(() => {
captureProjectStateEvent({
captureSuccess({
eventName: STATE_TRACKER_EVENTS.delete,
payload: {
...data,
state: "SUCCESS",
id: data.id,
},
});
handleClose();
@ -63,11 +61,10 @@ export const StateDeleteModal: React.FC<TStateDeleteModal> = observer((props) =>
title: "Error!",
message: "State could not be deleted. Please try again.",
});
captureProjectStateEvent({
captureError({
eventName: STATE_TRACKER_EVENTS.delete,
payload: {
...data,
state: "FAILED",
id: data.id,
},
});
})

View file

@ -2,7 +2,7 @@ import { SetStateAction } from "react";
import { observer } from "mobx-react";
import { GripVertical, Pencil } from "lucide-react";
// plane imports
import { EIconSize } from "@plane/constants";
import { EIconSize, STATE_TRACKER_ELEMENTS } from "@plane/constants";
import { IState, TStateOperationsCallbacks } from "@plane/types";
import { StateGroupIcon } from "@plane/ui";
// local imports
@ -70,6 +70,7 @@ export const StateItemTitle = observer((props: TStateItemTitleProps) => {
<button
className="flex-shrink-0 w-5 h-5 rounded flex justify-center items-center overflow-hidden transition-colors hover:bg-custom-background-80 cursor-pointer text-custom-text-200 hover:text-custom-text-100"
onClick={() => setUpdateStateModal(true)}
data-ph-element={STATE_TRACKER_ELEMENTS.STATE_LIST_EDIT_BUTTON}
>
<Pencil className="w-3 h-3" />
</button>