Compare commits

...

1 Commits

Author SHA1 Message Date
gakshita
55d6841f9a chore: workspace events 2025-07-08 18:05:03 +05:30
11 changed files with 198 additions and 21 deletions

View File

@@ -1,6 +1,7 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { Pen, Trash } from "lucide-react";
import { PROJECT_SETTINGS_TRACKER_ELEMENTS } from "@plane/constants";
import { Tooltip } from "@plane/ui";
// components
import { ProIcon } from "@/components/common";
@@ -29,13 +30,17 @@ export const EstimateListItemButtons: FC<TEstimateListItem> = observer((props) =
}
position="top"
>
<button className="relative flex-shrink-0 w-6 h-6 flex justify-center items-center rounded cursor-pointer transition-colors overflow-hidden hover:bg-custom-background-80">
<button
className="relative flex-shrink-0 w-6 h-6 flex justify-center items-center rounded cursor-pointer transition-colors overflow-hidden hover:bg-custom-background-80"
data-ph-element={PROJECT_SETTINGS_TRACKER_ELEMENTS.ESTIMATES_LIST_ITEM}
>
<Pen size={12} />
</button>
</Tooltip>
<button
className="relative flex-shrink-0 w-6 h-6 flex justify-center items-center rounded cursor-pointer transition-colors overflow-hidden hover:bg-custom-background-80"
onClick={() => onDeleteClick && onDeleteClick(estimateId)}
data-ph-element={PROJECT_SETTINGS_TRACKER_ELEMENTS.ESTIMATES_LIST_ITEM}
>
<Trash size={12} />
</button>

View File

@@ -5,7 +5,13 @@ import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { ArchiveRestore } from "lucide-react";
// types
import { PROJECT_AUTOMATION_MONTHS, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import {
PROJECT_AUTOMATION_MONTHS,
EUserPermissions,
EUserPermissionsLevel,
PROJECT_SETTINGS_TRACKER_ELEMENTS,
PROJECT_SETTINGS_TRACKER_EVENTS,
} from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { IProject } from "@plane/types";
// ui
@@ -14,6 +20,7 @@ import { CustomSelect, Loader, ToggleSwitch } from "@plane/ui";
import { SelectMonthModal } from "@/components/automation";
// constants
// hooks
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
import { useProject, useUserPermissions } from "@/hooks/store";
type Props = {
@@ -39,7 +46,7 @@ export const AutoArchiveAutomation: React.FC<Props> = observer((props) => {
EUserPermissionsLevel.PROJECT,
workspaceSlug?.toString(),
currentProjectDetails?.id
);
);
return (
<>
@@ -65,11 +72,22 @@ export const AutoArchiveAutomation: React.FC<Props> = observer((props) => {
</div>
<ToggleSwitch
value={currentProjectDetails?.archive_in !== 0}
onChange={() =>
currentProjectDetails?.archive_in === 0
? handleChange({ archive_in: 1 })
: handleChange({ archive_in: 0 })
}
onChange={() => {
if (currentProjectDetails?.archive_in === 0) {
handleChange({ archive_in: 1 });
} else {
handleChange({ archive_in: 0 });
}
captureElementAndEvent({
element: {
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.AUTOMATIONS_ARCHIVE_TOGGLE_BUTTON,
},
event: {
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.auto_archive_workitems,
state: "SUCCESS",
},
});
}}
size="sm"
disabled={!isAdmin}
/>

View File

@@ -6,7 +6,14 @@ import { useParams } from "next/navigation";
// icons
import { ArchiveX } from "lucide-react";
// types
import { PROJECT_AUTOMATION_MONTHS, EUserPermissions, EUserPermissionsLevel, EIconSize } from "@plane/constants";
import {
PROJECT_AUTOMATION_MONTHS,
EUserPermissions,
EUserPermissionsLevel,
EIconSize,
PROJECT_SETTINGS_TRACKER_ELEMENTS,
PROJECT_SETTINGS_TRACKER_EVENTS,
} from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { IProject } from "@plane/types";
// ui
@@ -15,6 +22,7 @@ import { CustomSelect, CustomSearchSelect, ToggleSwitch, StateGroupIcon, DoubleC
import { SelectMonthModal } from "@/components/automation";
// constants
// hooks
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
import { useProject, useProjectState, useUserPermissions } from "@/hooks/store";
type Props = {
@@ -91,11 +99,22 @@ export const AutoCloseAutomation: React.FC<Props> = observer((props) => {
</div>
<ToggleSwitch
value={currentProjectDetails?.close_in !== 0}
onChange={() =>
currentProjectDetails?.close_in === 0
? handleChange({ close_in: 1, default_state: defaultState })
: handleChange({ close_in: 0, default_state: null })
}
onChange={() => {
if (currentProjectDetails?.close_in === 0) {
handleChange({ close_in: 1, default_state: defaultState });
} else {
handleChange({ close_in: 0, default_state: null });
}
captureElementAndEvent({
element: {
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.AUTOMATIONS_CLOSE_TOGGLE_BUTTON,
},
event: {
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.auto_close_workitems,
state: "SUCCESS",
},
});
}}
size="sm"
disabled={!isAdmin}
/>

View File

@@ -3,8 +3,10 @@
import { FC, useState } from "react";
import { observer } from "mobx-react";
// ui
import { PROJECT_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
import { Button, EModalPosition, EModalWidth, ModalCore, TOAST_TYPE, setToast } from "@plane/ui";
// hooks
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
import { useEstimate, useProject, useProjectEstimates } from "@/hooks/store";
type TDeleteEstimateModal = {
@@ -35,6 +37,12 @@ export const DeleteEstimateModal: FC<TDeleteEstimateModal> = observer((props) =>
await updateProject(workspaceSlug, projectId, { estimate: null });
}
setButtonLoader(false);
captureSuccess({
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.estimate_deleted,
payload: {
id: estimateId,
},
});
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Estimate deleted",
@@ -43,6 +51,12 @@ export const DeleteEstimateModal: FC<TDeleteEstimateModal> = observer((props) =>
handleClose();
} catch (error) {
setButtonLoader(false);
captureError({
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.estimate_deleted,
payload: {
id: estimateId,
},
});
setToast({
type: TOAST_TYPE.ERROR,
title: "Estimate creation failed",

View File

@@ -2,8 +2,10 @@
import { FC } from "react";
import { useTheme } from "next-themes";
import { PROJECT_SETTINGS_TRACKER_ELEMENTS, PROJECT_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
// public images
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
import { DetailedEmptyState } from "../empty-state";
type TEstimateEmptyScreen = {
@@ -26,7 +28,18 @@ export const EstimateEmptyScreen: FC<TEstimateEmptyScreen> = (props) => {
className="w-full !px-0 !py-0"
primaryButton={{
text: t("project_settings.empty_state.estimates.primary_button"),
onClick: onButtonClick,
onClick: () => {
onButtonClick();
captureElementAndEvent({
element: {
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.ESTIMATES_EMPTY_STATE_CREATE_BUTTON,
},
event: {
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.estimate_created,
state: "SUCCESS",
},
});
},
}}
/>
);

View File

@@ -2,9 +2,11 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { PROJECT_SETTINGS_TRACKER_ELEMENTS, PROJECT_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { TOAST_TYPE, ToggleSwitch, setToast } from "@plane/ui";
// hooks
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
import { useProject, useProjectEstimates } from "@/hooks/store";
// i18n
type TEstimateDisableSwitch = {
@@ -30,6 +32,15 @@ export const EstimateDisableSwitch: FC<TEstimateDisableSwitch> = observer((props
await updateProject(workspaceSlug, projectId, {
estimate: currentProjectActiveEstimate ? null : currentActiveEstimateId,
});
captureElementAndEvent({
element: {
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.ESTIMATES_TOGGLE_BUTTON,
},
event: {
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.estimates_toggle,
state: "SUCCESS",
},
});
setToast({
type: TOAST_TYPE.SUCCESS,
title: currentProjectActiveEstimate
@@ -40,6 +51,15 @@ export const EstimateDisableSwitch: FC<TEstimateDisableSwitch> = observer((props
: t("project_settings.estimates.toasts.enabled.success.message"),
});
} catch (err) {
captureElementAndEvent({
element: {
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.ESTIMATES_TOGGLE_BUTTON,
},
event: {
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.estimates_toggle,
state: "ERROR",
},
});
setToast({
type: TOAST_TYPE.ERROR,
title: t("project_settings.estimates.toasts.disabled.error.title"),

View File

@@ -3,6 +3,7 @@
import { MutableRefObject, useRef, useState } from "react";
import { LucideIcon, X } from "lucide-react";
// plane helpers
import { PROJECT_SETTINGS_TRACKER_ELEMENTS, PROJECT_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
import { useOutsideClickDetector } from "@plane/hooks";
// types
import { IIssueLabel } from "@plane/types";
@@ -11,6 +12,7 @@ import { CustomMenu, DragHandle } from "@plane/ui";
// helpers
import { cn } from "@plane/utils";
// components
import { captureSuccess } from "@/helpers/event-tracker.helper";
import { LabelName } from "./label-name";
export interface ICustomMenuItem {
@@ -90,7 +92,16 @@ export const LabelItemBlock = (props: ILabelItemBlock) => {
<div className="py-0.5">
<button
className="flex size-5 items-center justify-center rounded hover:bg-custom-background-80"
onClick={() => handleLabelDelete(label)}
onClick={() => {
handleLabelDelete(label);
captureSuccess({
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.label_deleted,
payload: {
id: label?.id,
},
});
}}
data-ph-element={PROJECT_SETTINGS_TRACKER_ELEMENTS.LABELS_DELETE_BUTTON}
>
<X className="size-3.5 flex-shrink-0 text-custom-sidebar-text-300" />
</button>

View File

@@ -2,8 +2,10 @@ import React, { Dispatch, SetStateAction, useState } from "react";
import { useParams } from "next/navigation";
import { X, Pencil } from "lucide-react";
// types
import { PROJECT_SETTINGS_TRACKER_ELEMENTS, PROJECT_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
import { IIssueLabel } from "@plane/types";
// hooks
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
import { useLabel } from "@/hooks/store";
// components
import { CreateUpdateLabelInline, TLabelOperationsCallbacks } from "./create-update-label-inline";
@@ -67,6 +69,16 @@ export const ProjectSettingLabelItem: React.FC<Props> = (props) => {
onClick: () => {
setEditLabelForm(true);
setIsUpdating(true);
captureElementAndEvent({
element: {
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.LABELS_CONTEXT_MENU,
},
event: {
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.label_updated,
payload: { id: label?.id },
state: "SUCCESS",
},
});
},
isVisible: true,
text: "Edit label",

View File

@@ -4,10 +4,15 @@ import React, { useState, useRef } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// plane imports
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import {
EUserPermissions,
EUserPermissionsLevel,
PROJECT_SETTINGS_TRACKER_ELEMENTS,
PROJECT_SETTINGS_TRACKER_EVENTS,
} from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { IIssueLabel } from "@plane/types";
import { Button, Loader } from "@plane/ui";
import { Loader } from "@plane/ui";
import { DetailedEmptyState } from "@/components/empty-state";
import {
CreateUpdateLabelInline,
@@ -17,6 +22,7 @@ import {
TLabelOperationsCallbacks,
} from "@/components/labels";
// hooks
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
import { useLabel, useUserPermissions } from "@/hooks/store";
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
import { SettingsHeading } from "../settings";
@@ -81,7 +87,18 @@ export const ProjectSettingsLabelList: React.FC = observer(() => {
description={t("project_settings.labels.description")}
button={{
label: t("common.add_label"),
onClick: newLabel,
onClick: () => {
newLabel();
captureElementAndEvent({
element: {
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.LABELS_HEADER_CREATE_BUTTON,
},
event: {
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.label_created,
state: "SUCCESS",
},
});
},
}}
showButton={isEditable}
/>
@@ -110,7 +127,18 @@ export const ProjectSettingsLabelList: React.FC = observer(() => {
description={""}
primaryButton={{
text: "Create your first label",
onClick: newLabel,
onClick: () => {
newLabel();
captureElementAndEvent({
element: {
elementName: PROJECT_SETTINGS_TRACKER_ELEMENTS.LABELS_EMPTY_STATE_CREATE_BUTTON,
},
event: {
eventName: PROJECT_SETTINGS_TRACKER_EVENTS.label_created,
state: "SUCCESS",
},
});
},
}}
assetPath={resolvedPath}
className="w-full !px-0 !py-0"

View File

@@ -2,12 +2,13 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { PROJECT_TRACKER_ELEMENTS } from "@plane/constants";
import { PROJECT_TRACKER_ELEMENTS, PROJECT_TRACKER_EVENTS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { IProject } from "@plane/types";
import { ToggleSwitch, Tooltip, setPromiseToast } from "@plane/ui";
// hooks
import { SettingsHeading } from "@/components/settings";
import { captureSuccess } from "@/helpers/event-tracker.helper";
import { useProject, useUser } from "@/hooks/store";
// plane web components
import { UpgradeBadge } from "@/plane-web/components/workspace";
@@ -37,6 +38,7 @@ export const ProjectFeaturesList: FC<Props> = observer((props) => {
[featureProperty]: !currentProjectDetails?.[featureProperty as keyof IProject],
};
const updateProjectPromise = updateProject(workspaceSlug, projectId, settingsPayload);
setPromiseToast(updateProjectPromise, {
loading: "Updating project feature...",
success: {
@@ -48,6 +50,14 @@ export const ProjectFeaturesList: FC<Props> = observer((props) => {
message: () => "Something went wrong while updating project feature. Please try again.",
},
});
updateProjectPromise.then(() => {
captureSuccess({
eventName: PROJECT_TRACKER_EVENTS.feature_toggled,
payload: {
feature_key: featureKey,
},
});
});
};
if (!currentUser) return <></>;

View File

@@ -26,6 +26,7 @@ export const PROJECT_TRACKER_EVENTS = {
create: "project_created",
update: "project_updated",
delete: "project_deleted",
feature_toggled: "feature_toggled",
};
export const PROJECT_TRACKER_ELEMENTS = {
EXTENDED_SIDEBAR_ADD_BUTTON: "extended_sidebar_add_project_button",
@@ -268,3 +269,29 @@ export const SIDEBAR_TRACKER_ELEMENTS = {
USER_MENU_ITEM: "sidenav_user_menu_item",
CREATE_WORK_ITEM_BUTTON: "sidebar_create_work_item_button",
};
export const PROJECT_SETTINGS_TRACKER_ELEMENTS = {
LABELS_EMPTY_STATE_CREATE_BUTTON: "labels_empty_state_create_button",
LABELS_HEADER_CREATE_BUTTON: "labels_header_create_button",
LABELS_CONTEXT_MENU: "labels_context_menu",
LABELS_DELETE_BUTTON: "labels_delete_button",
ESTIMATES_TOGGLE_BUTTON: "estimates_toggle_button",
ESTIMATES_EMPTY_STATE_CREATE_BUTTON: "estimates_empty_state_create_button",
ESTIMATES_LIST_ITEM: "estimates_list_item",
AUTOMATIONS_ARCHIVE_TOGGLE_BUTTON: "automations_archive_toggle_button",
AUTOMATIONS_CLOSE_TOGGLE_BUTTON: "automations_close_toggle_button",
};
export const PROJECT_SETTINGS_TRACKER_EVENTS = {
// labels
label_created: "label_created",
label_updated: "label_updated",
label_deleted: "label_deleted",
// estimates
estimate_created: "estimate_created",
estimate_updated: "estimate_updated",
estimate_deleted: "estimate_deleted",
estimates_toggle: "estimates_toggled",
// automations
auto_close_workitems: "auto_close_workitems",
auto_archive_workitems: "auto_archive_workitems",
};