added project-labels events

This commit is contained in:
Lakhan 2024-06-05 13:28:31 +05:30
parent ffc987bcc8
commit 3f88694366
6 changed files with 105 additions and 14 deletions

View File

@ -6,13 +6,13 @@ import { Controller, useForm } from "react-hook-form";
import { ChevronDown } from "lucide-react"; import { ChevronDown } from "lucide-react";
import { Dialog, Popover, Transition } from "@headlessui/react"; import { Dialog, Popover, Transition } from "@headlessui/react";
import type { IIssueLabel, IState } from "@plane/types"; import type { IIssueLabel, IState } from "@plane/types";
// hooks
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
import { LABEL_COLOR_OPTIONS, getRandomLabelColor } from "@/constants/label";
import { useLabel } from "@/hooks/store";
// ui // ui
// types import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
// constants // constants
import { E_STATES, LABEL_CREATED } from "constants/event-tracker";
import { LABEL_COLOR_OPTIONS, getRandomLabelColor } from "@/constants/label";
// hooks
import { useLabel, useEventTracker } from "@/hooks/store";
// types // types
type Props = { type Props = {
@ -34,6 +34,7 @@ export const CreateLabelModal: React.FC<Props> = observer((props) => {
const { workspaceSlug } = router.query; const { workspaceSlug } = router.query;
// store hooks // store hooks
const { createLabel } = useLabel(); const { createLabel } = useLabel();
const { captureEvent } = useEventTracker();
// form info // form info
const { const {
formState: { errors, isSubmitting }, formState: { errors, isSubmitting },
@ -70,6 +71,13 @@ export const CreateLabelModal: React.FC<Props> = observer((props) => {
.then((res) => { .then((res) => {
onClose(); onClose();
if (onSuccess) onSuccess(res); if (onSuccess) onSuccess(res);
captureEvent(LABEL_CREATED, {
label_id: res.id,
color: res.color,
parent: res.parent,
element: E_STATES,
state: "SUCCESS",
});
}) })
.catch((error) => { .catch((error) => {
setToast({ setToast({
@ -78,6 +86,9 @@ export const CreateLabelModal: React.FC<Props> = observer((props) => {
message: error?.detail ?? "Something went wrong. Please try again later.", message: error?.detail ?? "Something went wrong. Please try again later.",
}); });
reset(formData); reset(formData);
captureEvent(LABEL_CREATED, {
state: "FAILED",
});
}); });
}; };

View File

@ -8,9 +8,10 @@ import { IIssueLabel } from "@plane/types";
// ui // ui
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui"; import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
// constants // constants
import { E_Labels, LABEL_CREATED, LABEL_UPDATED } from "constants/event-tracker";
import { getRandomLabelColor, LABEL_COLOR_OPTIONS } from "@/constants/label"; import { getRandomLabelColor, LABEL_COLOR_OPTIONS } from "@/constants/label";
// hooks // hooks
import { useLabel } from "@/hooks/store"; import { useLabel, useEventTracker } from "@/hooks/store";
// types // types
type Props = { type Props = {
@ -34,12 +35,13 @@ export const CreateUpdateLabelInline = observer(
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
// store hooks // store hooks
const { createLabel, updateLabel } = useLabel(); const { createLabel, updateLabel } = useLabel();
const { captureEvent } = useEventTracker();
// form info // form info
const { const {
handleSubmit, handleSubmit,
control, control,
reset, reset,
formState: { errors, isSubmitting }, formState: { errors, isSubmitting, dirtyFields },
watch, watch,
setValue, setValue,
setFocus, setFocus,
@ -57,7 +59,14 @@ export const CreateUpdateLabelInline = observer(
if (!workspaceSlug || !projectId || isSubmitting) return; if (!workspaceSlug || !projectId || isSubmitting) return;
await createLabel(workspaceSlug.toString(), projectId.toString(), formData) await createLabel(workspaceSlug.toString(), projectId.toString(), formData)
.then(() => { .then((res) => {
captureEvent(LABEL_CREATED, {
label_id: res.id,
color: res.color,
parent: res.parent,
element: E_Labels,
state: "SUCCESS",
});
handleClose(); handleClose();
reset(defaultValues); reset(defaultValues);
}) })
@ -76,9 +85,17 @@ export const CreateUpdateLabelInline = observer(
// eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
await updateLabel(workspaceSlug.toString(), projectId.toString(), labelToUpdate?.id!, formData) await updateLabel(workspaceSlug.toString(), projectId.toString(), labelToUpdate?.id!, formData)
.then(() => { .then((res) => {
reset(defaultValues); reset(defaultValues);
handleClose(); handleClose();
captureEvent(LABEL_UPDATED, {
label_id: res.id,
color: res.color,
parent: res.parent,
change_details: Object.keys(dirtyFields),
element: E_Labels,
state: "SUCCESS",
});
}) })
.catch((error) => { .catch((error) => {
setToast({ setToast({

View File

@ -7,8 +7,10 @@ import type { IIssueLabel } from "@plane/types";
import { TOAST_TYPE, setToast } from "@plane/ui"; import { TOAST_TYPE, setToast } from "@plane/ui";
// components // components
import { AlertModalCore } from "@/components/core"; import { AlertModalCore } from "@/components/core";
// constants
import { E_Labels, LABEL_DELETED, LABEL_GROUP_DELETED } from "constants/event-tracker";
// hooks // hooks
import { useLabel } from "@/hooks/store"; import { useLabel, useEventTracker } from "@/hooks/store";
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
@ -22,7 +24,8 @@ export const DeleteLabelModal: React.FC<Props> = observer((props) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
// store hooks // store hooks
const { deleteLabel } = useLabel(); const { deleteLabel, projectLabelsTree } = useLabel();
const { captureEvent } = useEventTracker();
// states // states
const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isDeleteLoading, setIsDeleteLoading] = useState(false);
@ -39,6 +42,21 @@ export const DeleteLabelModal: React.FC<Props> = observer((props) => {
await deleteLabel(workspaceSlug.toString(), projectId.toString(), data.id) await deleteLabel(workspaceSlug.toString(), projectId.toString(), data.id)
.then(() => { .then(() => {
handleClose(); handleClose();
const labelChildCount = projectLabelsTree?.find((label) => label.id === data.id)?.children?.length || 0;
if (labelChildCount > 0) {
captureEvent(LABEL_GROUP_DELETED, {
group_id: data.id,
children_count: labelChildCount,
element: E_Labels,
state: "SUCCESS",
});
} else {
captureEvent(LABEL_DELETED, {
label_id: data.id,
element: E_Labels,
state: "SUCCESS",
});
}
}) })
.catch((err) => { .catch((err) => {
setIsDeleteLoading(false); setIsDeleteLoading(false);

View File

@ -1,6 +1,10 @@
import { MutableRefObject, useEffect, useRef, useState } from "react"; import { MutableRefObject, useEffect, useRef, useState } from "react";
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine"; import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; import {
ElementDragPayload,
draggable,
dropTargetForElements,
} from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
import { pointerOutsideOfPreview } from "@atlaskit/pragmatic-drag-and-drop/element/pointer-outside-of-preview"; import { pointerOutsideOfPreview } from "@atlaskit/pragmatic-drag-and-drop/element/pointer-outside-of-preview";
import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview"; import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview";
import { attachInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item"; import { attachInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
@ -10,6 +14,10 @@ import { createRoot } from "react-dom/client";
import { IIssueLabel, InstructionType } from "@plane/types"; import { IIssueLabel, InstructionType } from "@plane/types";
// ui // ui
import { DropIndicator } from "@plane/ui"; import { DropIndicator } from "@plane/ui";
// constants
import { LABEL_ADDED_G, LABEL_REMOVED_G } from "@/constants/event-tracker";
// hooks
import { useEventTracker } from "@/hooks/store";
// components // components
import { LabelName } from "./label-block/label-name"; import { LabelName } from "./label-block/label-name";
import { TargetData, getCanDrop, getInstructionFromPayload } from "./label-utils"; import { TargetData, getCanDrop, getInstructionFromPayload } from "./label-utils";
@ -52,10 +60,28 @@ export const LabelDndHOC = observer((props: Props) => {
const [isDragging, setIsDragging] = useState(false); const [isDragging, setIsDragging] = useState(false);
const [instruction, setInstruction] = useState<InstructionType | undefined>(undefined); const [instruction, setInstruction] = useState<InstructionType | undefined>(undefined);
// hooks
const { captureEvent } = useEventTracker();
// refs // refs
const labelRef = useRef<HTMLDivElement | null>(null); const labelRef = useRef<HTMLDivElement | null>(null);
const dragHandleRef = useRef<HTMLButtonElement | null>(null); const dragHandleRef = useRef<HTMLButtonElement | null>(null);
const captureLabelDropEvent = (source: TargetData, destination: TargetData) => {
if (source?.parentId != destination.id) {
source?.parentId &&
captureEvent(LABEL_REMOVED_G, {
group_id: source?.parentId,
child_id: source?.id,
});
captureEvent(LABEL_ADDED_G, {
group_id: destination.id,
child_id: source?.id,
});
}
};
useEffect(() => { useEffect(() => {
const element = labelRef.current; const element = labelRef.current;
const dragHandleElement = dragHandleRef.current; const dragHandleElement = dragHandleRef.current;
@ -144,6 +170,8 @@ export const LabelDndHOC = observer((props: Props) => {
const sourceData = source.data as TargetData; const sourceData = source.data as TargetData;
if (sourceData.id) onDrop(sourceData.id as string, parentId, droppedLabelId, dropAtEndOfList); if (sourceData.id) onDrop(sourceData.id as string, parentId, droppedLabelId, dropAtEndOfList);
captureLabelDropEvent(sourceData, dropTargetData);
}, },
}) })
); );

View File

@ -4,7 +4,9 @@ import { X, Pencil } from "lucide-react";
// types // types
import { IIssueLabel } from "@plane/types"; import { IIssueLabel } from "@plane/types";
// hooks // hooks
import { useLabel } from "@/hooks/store"; import { useLabel, useEventTracker } from "@/hooks/store";
// constants
import { E_Labels, LABEL_REMOVED_G } from "@/constants/event-tracker";
// components // components
import { CreateUpdateLabelInline } from "./create-update-label-inline"; import { CreateUpdateLabelInline } from "./create-update-label-inline";
import { ICustomMenuItem, LabelItemBlock } from "./label-block/label-item-block"; import { ICustomMenuItem, LabelItemBlock } from "./label-block/label-item-block";
@ -34,6 +36,7 @@ export const ProjectSettingLabelItem: React.FC<Props> = (props) => {
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
// store hooks // store hooks
const { updateLabel } = useLabel(); const { updateLabel } = useLabel();
const { captureEvent } = useEventTracker();
const removeFromGroup = (label: IIssueLabel) => { const removeFromGroup = (label: IIssueLabel) => {
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
@ -41,6 +44,12 @@ export const ProjectSettingLabelItem: React.FC<Props> = (props) => {
updateLabel(workspaceSlug.toString(), projectId.toString(), label.id, { updateLabel(workspaceSlug.toString(), projectId.toString(), label.id, {
parent: null, parent: null,
}); });
captureEvent(LABEL_REMOVED_G, {
group_id: label.id,
child_id: label.id,
element: E_Labels,
});
}; };
const customMenuItems: ICustomMenuItem[] = [ const customMenuItems: ICustomMenuItem[] = [

View File

@ -175,6 +175,13 @@ export const ISSUE_OPENED = "Issue opened";
export const STATE_CREATED = "State created"; export const STATE_CREATED = "State created";
export const STATE_UPDATED = "State updated"; export const STATE_UPDATED = "State updated";
export const STATE_DELETED = "State deleted"; export const STATE_DELETED = "State deleted";
// Label Events
export const LABEL_CREATED = "Label created";
export const LABEL_UPDATED = "Label updated";
export const LABEL_DELETED = "Label deleted";
export const LABEL_GROUP_DELETED = "Label group deleted";
export const LABEL_ADDED_G = "Label added to group";
export const LABEL_REMOVED_G = "Label removed from group";
// Project Page Events // Project Page Events
export const PAGE_CREATED = "Page created"; export const PAGE_CREATED = "Page created";
export const PAGE_UPDATED = "Page updated"; export const PAGE_UPDATED = "Page updated";
@ -225,4 +232,5 @@ export const ARCHIVED_NOTIFICATIONS = "Archived notifications viewed";
export const GROUP_WORKSPACE = "Workspace_metrics"; export const GROUP_WORKSPACE = "Workspace_metrics";
// Elements // Elements
export const E_STATES = "Project states page"; export const E_STATES = "Project states page";
export const E_Labels = "Project labels page";