Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8bbf853
fix: update events identity
sriramveeraghanta Dec 8, 2025
6f64e07
feat: add last_login_time field to UserMeSerializer for enhanced user…
pablohashescobar Dec 9, 2025
4d22ef2
feat: integrate enhanced new set of event trackers
JayashTripathy Dec 10, 2025
54c32f6
Merge branch 'preview' of https://github.com/makeplane/plane into cho…
JayashTripathy Dec 10, 2025
72dd432
Merge branch 'preview' of github.com:makeplane/plane into chore-event…
pablohashescobar Dec 10, 2025
f9d42df
feat: extend joinWorkspaceGroup to accept additional properties
JayashTripathy Dec 10, 2025
f958aad
feat: update joinWorkspaceGroup to utilize workspace data from usePos…
JayashTripathy Dec 10, 2025
96ccde5
Merge branch 'chore-event-updates' of github.com:makeplane/plane into…
pablohashescobar Dec 10, 2025
031fb89
refactor: simplify joinWorkspaceGroup by removing extraProperties par…
JayashTripathy Dec 10, 2025
dd0ac58
refactor: simplify joinWorkspaceGroup by removing extraProperties par…
JayashTripathy Dec 10, 2025
f8f07a6
chore: add tracking events through posthog
pablohashescobar Dec 11, 2025
6e2f0f1
Merge branch 'chore-event-updates' of github.com:makeplane/plane into…
pablohashescobar Dec 11, 2025
f14bf3b
feat: enhance event tracking for workspace invitations and joins
pablohashescobar Dec 11, 2025
a64bab7
feat: replace invitation event with user join tracking for workspace …
pablohashescobar Dec 12, 2025
9941459
refactor: reorganize imports and enhance error handling in project an…
JayashTripathy Dec 12, 2025
1f89fcd
fix: update event tracking to use created_at from response in cycle a…
JayashTripathy Dec 16, 2025
5e2f83f
fix: update event tracking to use created_at from response in pages l…
JayashTripathy Dec 16, 2025
91b421d
refactor: role extraction
JayashTripathy Dec 22, 2025
af33860
refactor: improve user role handling in event tracking functions
JayashTripathy Dec 22, 2025
889c173
fix: ensure quick add functionality correctly awaits promise resoluti…
JayashTripathy Dec 22, 2025
b4c40bb
fix: ensure quick add functionality correctly awaits promise resoluti…
JayashTripathy Dec 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/api/plane/app/serializers/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class Meta:
"is_password_autoset",
"is_email_verified",
"last_login_medium",
"last_login_time",
]
read_only_fields = fields

Expand Down
51 changes: 40 additions & 11 deletions apps/api/plane/app/views/workspace/invite.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
WorkSpaceMemberSerializer,
)
from plane.app.views.base import BaseAPIView
from plane.bgtasks.event_tracking_task import workspace_invite_event
from plane.bgtasks.event_tracking_task import workspace_invite_event, track_event
from plane.bgtasks.workspace_invitation_task import workspace_invitation
from plane.db.models import User, Workspace, WorkspaceMember, WorkspaceMemberInvite
from plane.utils.cache import invalidate_cache, invalidate_cache_directly
Expand Down Expand Up @@ -121,6 +121,19 @@ def create(self, request, slug):
current_site,
request.user.email,
)
track_event.delay(
user_id=request.user.id,
event_name="user_invited_to_workspace",
slug=slug,
event_properties={
"user_id": request.user.id,
"workspace_id": workspace.id,
"workspace_slug": workspace.slug,
"invitee_role": invitation.role,
"invited_at": str(timezone.now()),
"invitee_email": invitation.email,
},
)

return Response({"message": "Emails sent successfully"}, status=status.HTTP_200_OK)

Expand Down Expand Up @@ -186,20 +199,22 @@ def post(self, request, slug, pk):
# Set the user last_workspace_id to the accepted workspace
user.last_workspace_id = workspace_invite.workspace.id
user.save()
track_event.delay(
user_id=user.id,
event_name="user_joined_workspace",
slug=slug,
event_properties={
"user_id": user.id,
"workspace_id": workspace_invite.workspace.id,
"workspace_slug": workspace_invite.workspace.slug,
"role": workspace_invite.role,
"joined_at": str(timezone.now()),
},
)

# Delete the invitation
workspace_invite.delete()

# Send event
workspace_invite_event.delay(
user=user.id if user is not None else None,
email=email,
user_agent=request.META.get("HTTP_USER_AGENT"),
ip=get_client_ip(request=request),
event_name="MEMBER_ACCEPTED",
accepted_from="EMAIL",
)

return Response(
{"message": "Workspace Invitation Accepted"},
status=status.HTTP_200_OK,
Expand Down Expand Up @@ -252,6 +267,20 @@ def create(self, request):
is_active=True, role=invitation.role
)

# Track event
track_event.delay(
user_id=request.user.id,
event_name="user_joined_workspace",
slug=invitation.workspace.slug,
event_properties={
"user_id": request.user.id,
"workspace_id": invitation.workspace.id,
"workspace_slug": invitation.workspace.slug,
"role": invitation.role,
"joined_at": str(timezone.now()),
},
)

# Bulk create the user for all the workspaces
WorkspaceMember.objects.bulk_create(
[
Expand Down
21 changes: 21 additions & 0 deletions apps/api/plane/authentication/utils/workspace_project_join.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
# Django imports
from django.utils import timezone

Comment on lines +1 to +3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Align event name with other join events and avoid list comprehension for side effects

Two things here:

  1. Event name inconsistency

Other join flows use event_name="user_joined_workspace" (singular), but this path uses "user_joined_workspaces":

track_event.delay(
    user_id=user.id,
    event_name="user_joined_workspaces",  # plural
    ...
)

Unless you explicitly want a different event type for this code path, this will fragment analytics. To keep queries consistent, consider:

-            event_name="user_joined_workspaces",
+            event_name="user_joined_workspace",
  1. Avoid list comprehension for side effects

The comprehension:

[
    track_event.delay(...)
    for workspace_member_invite in workspace_member_invites
]

creates an unused list purely for side effects. A plain loop is clearer and avoids unnecessary allocation:

-    [
-        track_event.delay(
-            user_id=user.id,
-            event_name="user_joined_workspace",
-            slug=workspace_member_invite.workspace.slug,
-            event_properties={
-                "user_id": user.id,
-                "workspace_id": workspace_member_invite.workspace.id,
-                "workspace_slug": workspace_member_invite.workspace.slug,
-                "role": workspace_member_invite.role,
-                "joined_at": str(timezone.now()),
-            },
-        )
-        for workspace_member_invite in workspace_member_invites
-    ]
+    for workspace_member_invite in workspace_member_invites:
+        track_event.delay(
+            user_id=user.id,
+            event_name="user_joined_workspace",
+            slug=workspace_member_invite.workspace.slug,
+            event_properties={
+                "user_id": user.id,
+                "workspace_id": workspace_member_invite.workspace.id,
+                "workspace_slug": workspace_member_invite.workspace.slug,
+                "role": workspace_member_invite.role,
+                "joined_at": timezone.now().isoformat(),
+            },
+        )

(The .isoformat() change is optional but recommended for consistent timestamps.)

Also applies to: 12-12, 33-47

🤖 Prompt for AI Agents
In apps/api/plane/authentication/utils/workspace_project_join.py lines 1-3 (and
also apply to occurrences at 12-12 and 33-47), change the event_name from
"user_joined_workspaces" to "user_joined_workspace" to match other join events,
and replace the list comprehension used solely for side effects with an explicit
for-loop that calls track_event.delay(...) for each workspace_member_invite;
optionally ensure any timestamp passed is converted with .isoformat() for
consistency.

# Module imports
from plane.db.models import (
ProjectMember,
ProjectMemberInvite,
WorkspaceMember,
WorkspaceMemberInvite,
)
from plane.utils.cache import invalidate_cache_directly
from plane.bgtasks.event_tracking_task import track_event


def process_workspace_project_invitations(user):
Expand All @@ -25,6 +30,22 @@ def process_workspace_project_invitations(user):
ignore_conflicts=True,
)

[
track_event.delay(
user_id=user.id,
event_name="user_joined_workspaces",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent event name uses plural instead of singular

The event name "user_joined_workspaces" (plural) is inconsistent with the same event tracked elsewhere as "user_joined_workspace" (singular) in invite.py. This typo causes these functionally identical events to be tracked under different names in PostHog, fragmenting analytics data and making it harder to analyze all workspace join events together.

Fix in Cursor Fix in Web

slug=workspace_member_invite.workspace.slug,
event_properties={
"user_id": user.id,
"workspace_id": workspace_member_invite.workspace.id,
"workspace_slug": workspace_member_invite.workspace.slug,
"role": workspace_member_invite.role,
"joined_at": str(timezone.now()),
},
)
for workspace_member_invite in workspace_member_invites
]

[
invalidate_cache_directly(
path=f"/api/workspaces/{str(workspace_member_invite.workspace.slug)}/members/",
Expand Down
70 changes: 44 additions & 26 deletions apps/api/plane/bgtasks/event_tracking_task.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import logging
import os
import uuid
from typing import Dict, Any

# third party imports
from celery import shared_task
Expand All @@ -8,45 +10,61 @@
# module imports
from plane.license.utils.instance_value import get_configuration_value
from plane.utils.exception_logger import log_exception
from plane.db.models import Workspace


logger = logging.getLogger("plane.worker")


def posthogConfiguration():
POSTHOG_API_KEY, POSTHOG_HOST = get_configuration_value(
[
{
"key": "POSTHOG_API_KEY",
"default": os.environ.get("POSTHOG_API_KEY", None),
},
{"key": "POSTHOG_HOST", "default": os.environ.get("POSTHOG_HOST", None)},
]
)
POSTHOG_API_KEY, POSTHOG_HOST = get_configuration_value([
{
"key": "POSTHOG_API_KEY",
"default": os.environ.get("POSTHOG_API_KEY", None),
},
{"key": "POSTHOG_HOST", "default": os.environ.get("POSTHOG_HOST", None)},
])
if POSTHOG_API_KEY and POSTHOG_HOST:
return POSTHOG_API_KEY, POSTHOG_HOST
else:
return None, None


def preprocess_data_properties(
user_id: uuid.UUID, event_name: str, slug: str, data_properties: Dict[str, Any]
) -> Dict[str, Any]:
if event_name == "user_invited_to_workspace":
# Check if the current user is the workspace owner
workspace = Workspace.objects.get(slug=slug)
if str(workspace.owner_id) == str(user_id):
data_properties["role"] = "owner"
else:
data_properties["role"] = "admin"
Comment on lines +38 to +42
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function uses Workspace.objects.get(slug=slug) without error handling. If the workspace doesn't exist, this will raise a Workspace.DoesNotExist exception that will be caught by the generic exception handler in track_event, causing the event tracking to fail silently. Add proper error handling or document that the workspace must exist.

Suggested change
workspace = Workspace.objects.get(slug=slug)
if str(workspace.owner_id) == str(user_id):
data_properties["role"] = "owner"
else:
data_properties["role"] = "admin"
try:
workspace = Workspace.objects.get(slug=slug)
if str(workspace.owner_id) == str(user_id):
data_properties["role"] = "owner"
else:
data_properties["role"] = "admin"
except Workspace.DoesNotExist:
logger.error(f"Workspace with slug '{slug}' does not exist when processing event '{event_name}'.")
data_properties["role"] = "unknown"

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic assumes that if a user is not the workspace owner, they must be an admin. However, the invitee could have any role (guest, member, admin). The actual role should come from data_properties['invitee_role'] which is passed in the event properties from the workspace invite view.

Suggested change
data_properties["role"] = "admin"
data_properties["role"] = data_properties.get("invitee_role")

Copilot uses AI. Check for mistakes.

return data_properties
Comment on lines +33 to +44
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Unhandled Workspace.DoesNotExist exception can break event tracking.

Workspace.objects.get(slug=slug) will raise Workspace.DoesNotExist if the workspace doesn't exist (e.g., deleted or invalid slug). This exception propagates up to track_event, where it's caught but causes the entire event to fail silently.

Consider using filter().first() with a null check:

 def preprocess_data_properties(
     user_id: uuid.UUID, event_name: str, slug: str, data_properties: Dict[str, Any]
 ) -> Dict[str, Any]:
     if event_name == "user_invited_to_workspace":
-        # Check if the current user is the workspace owner
-        workspace = Workspace.objects.get(slug=slug)
-        if str(workspace.owner_id) == str(user_id):
-            data_properties["role"] = "owner"
-        else:
-            data_properties["role"] = "admin"
+        workspace = Workspace.objects.filter(slug=slug).first()
+        if workspace:
+            if str(workspace.owner_id) == str(user_id):
+                data_properties["role"] = "owner"
+            else:
+                data_properties["role"] = "admin"
+        else:
+            data_properties["role"] = "unknown"
 
     return data_properties
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def preprocess_data_properties(
user_id: uuid.UUID, event_name: str, slug: str, data_properties: Dict[str, Any]
) -> Dict[str, Any]:
if event_name == "user_invited_to_workspace":
# Check if the current user is the workspace owner
workspace = Workspace.objects.get(slug=slug)
if str(workspace.owner_id) == str(user_id):
data_properties["role"] = "owner"
else:
data_properties["role"] = "admin"
return data_properties
def preprocess_data_properties(
user_id: uuid.UUID, event_name: str, slug: str, data_properties: Dict[str, Any]
) -> Dict[str, Any]:
if event_name == "user_invited_to_workspace":
workspace = Workspace.objects.filter(slug=slug).first()
if workspace:
if str(workspace.owner_id) == str(user_id):
data_properties["role"] = "owner"
else:
data_properties["role"] = "admin"
else:
data_properties["role"] = "unknown"
return data_properties
🤖 Prompt for AI Agents
In apps/api/plane/bgtasks/event_tracking_task.py around lines 33-44, replace the
direct Workspace.objects.get(slug=slug) call with
Workspace.objects.filter(slug=slug).first() and add a null check so the code
does not raise Workspace.DoesNotExist; if workspace is None, leave
data_properties unchanged (or set data_properties["role"]="unknown" if a role is
required), otherwise perform the owner-id comparison and set "role" accordingly;
this prevents an exception from propagating while preserving the intended role
assignment when the workspace exists.



@shared_task
def auth_events(user, email, user_agent, ip, event_name, medium, first_time):
try:
POSTHOG_API_KEY, POSTHOG_HOST = posthogConfiguration()
def track_event(user_id: uuid.UUID, event_name: str, slug: str, event_properties: Dict[str, Any]):
POSTHOG_API_KEY, POSTHOG_HOST = posthogConfiguration()

if POSTHOG_API_KEY and POSTHOG_HOST:
posthog = Posthog(POSTHOG_API_KEY, host=POSTHOG_HOST)
posthog.capture(
email,
event=event_name,
properties={
"event_id": uuid.uuid4().hex,
"user": {"email": email, "id": str(user)},
"device_ctx": {"ip": ip, "user_agent": user_agent},
"medium": medium,
"first_time": first_time,
},
)
if not (POSTHOG_API_KEY and POSTHOG_HOST):
logger.warning("Event tracking is not configured")
return

try:
# preprocess the data properties for massaging the payload
# in the correct format for posthog
data_properties = preprocess_data_properties(user_id, event_name, slug, event_properties)
groups = {
"workspace": slug,
}
# track the event using posthog
posthog = Posthog(POSTHOG_API_KEY, host=POSTHOG_HOST)
posthog.capture(distinct_id=user_id, event=event_name, properties=data_properties, groups=groups)
except Exception as e:
log_exception(e)
return
return False
Comment on lines 47 to +67
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Type mismatch and inconsistent return value.

Two issues in the track_event function:

  1. UUID type: user_id is typed as uuid.UUID, but posthog.capture(distinct_id=...) typically expects a string. Ensure explicit conversion to avoid serialization issues.

  2. Inconsistent return: Returns False on exception (line 67) but returns None implicitly on success or when tracking is disabled. Consider consistent return behavior.

 @shared_task
-def track_event(user_id: uuid.UUID, event_name: str, slug: str, event_properties: Dict[str, Any]):
+def track_event(user_id: uuid.UUID, event_name: str, slug: str, event_properties: Dict[str, Any]) -> bool:
     POSTHOG_API_KEY, POSTHOG_HOST = posthogConfiguration()
 
     if not (POSTHOG_API_KEY and POSTHOG_HOST):
         logger.warning("Event tracking is not configured")
-        return
+        return False
 
     try:
         data_properties = preprocess_data_properties(user_id, event_name, slug, event_properties)
         groups = {
             "workspace": slug,
         }
         posthog = Posthog(POSTHOG_API_KEY, host=POSTHOG_HOST)
-        posthog.capture(distinct_id=user_id, event=event_name, properties=data_properties, groups=groups)
+        posthog.capture(distinct_id=str(user_id), event=event_name, properties=data_properties, groups=groups)
+        return True
     except Exception as e:
         log_exception(e)
         return False
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@shared_task
def auth_events(user, email, user_agent, ip, event_name, medium, first_time):
try:
POSTHOG_API_KEY, POSTHOG_HOST = posthogConfiguration()
def track_event(user_id: uuid.UUID, event_name: str, slug: str, event_properties: Dict[str, Any]):
POSTHOG_API_KEY, POSTHOG_HOST = posthogConfiguration()
if POSTHOG_API_KEY and POSTHOG_HOST:
posthog = Posthog(POSTHOG_API_KEY, host=POSTHOG_HOST)
posthog.capture(
email,
event=event_name,
properties={
"event_id": uuid.uuid4().hex,
"user": {"email": email, "id": str(user)},
"device_ctx": {"ip": ip, "user_agent": user_agent},
"medium": medium,
"first_time": first_time,
},
)
if not (POSTHOG_API_KEY and POSTHOG_HOST):
logger.warning("Event tracking is not configured")
return
try:
# preprocess the data properties for massaging the payload
# in the correct format for posthog
data_properties = preprocess_data_properties(user_id, event_name, slug, event_properties)
groups = {
"workspace": slug,
}
# track the event using posthog
posthog = Posthog(POSTHOG_API_KEY, host=POSTHOG_HOST)
posthog.capture(distinct_id=user_id, event=event_name, properties=data_properties, groups=groups)
except Exception as e:
log_exception(e)
return
return False
@shared_task
def track_event(user_id: uuid.UUID, event_name: str, slug: str, event_properties: Dict[str, Any]) -> bool:
POSTHOG_API_KEY, POSTHOG_HOST = posthogConfiguration()
if not (POSTHOG_API_KEY and POSTHOG_HOST):
logger.warning("Event tracking is not configured")
return False
try:
# preprocess the data properties for massaging the payload
# in the correct format for posthog
data_properties = preprocess_data_properties(user_id, event_name, slug, event_properties)
groups = {
"workspace": slug,
}
# track the event using posthog
posthog = Posthog(POSTHOG_API_KEY, host=POSTHOG_HOST)
posthog.capture(distinct_id=str(user_id), event=event_name, properties=data_properties, groups=groups)
return True
except Exception as e:
log_exception(e)
return False
🤖 Prompt for AI Agents
In apps/api/plane/bgtasks/event_tracking_task.py around lines 47 to 67, convert
user_id to a string before passing it to posthog.capture (e.g.,
distinct_id=str(user_id)) to avoid UUID serialization issues, and make the
function return consistently (return True on successful capture and return False
both when tracking is disabled and when an exception occurs) so callers receive
a boolean success indicator.



@shared_task
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from "react";
import { observer } from "mobx-react";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useState } from "react";
// constants
import { EPageAccess, PROJECT_PAGE_TRACKER_EVENTS, PROJECT_TRACKER_ELEMENTS } from "@plane/constants";
// plane types
Expand All @@ -12,11 +12,14 @@ import type { TPage } from "@plane/types";
import { Breadcrumbs, Header } from "@plane/ui";
// helpers
import { BreadcrumbLink } from "@/components/common/breadcrumb-link";
import { captureError, captureSuccess } from "@/helpers/event-tracker.helper";
import { captureError } from "@/helpers/event-tracker.helper";
// hooks
import { useProject } from "@/hooks/store/use-project";
// plane web imports
import { useWorkspace } from "@/hooks/store/use-workspace";
import { useUser, useUserPermissions } from "@/hooks/store/user";
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common";
import { getUserRoleString, trackPageCreated } from "@/plane-web/helpers/event-tracker-v2.helper";
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";

export const PagesListHeader = observer(function PagesListHeader() {
Expand All @@ -28,42 +31,54 @@ export const PagesListHeader = observer(function PagesListHeader() {
const searchParams = useSearchParams();
const pageType = searchParams.get("type");
// store hooks
const { getWorkspaceRoleByWorkspaceSlug } = useUserPermissions();
const { data: currentUser } = useUser();
const { currentWorkspace } = useWorkspace();
const { currentProjectDetails, loader } = useProject();
const { canCurrentUserCreatePage, createPage } = usePageStore(EPageStoreType.PROJECT);
// handle page create
const handleCreatePage = async () => {
setIsCreatingPage(true);
try {
setIsCreatingPage(true);

const payload: Partial<TPage> = {
access: pageType === "private" ? EPageAccess.PRIVATE : EPageAccess.PUBLIC,
};
const payload: Partial<TPage> = {
access: pageType === "private" ? EPageAccess.PRIVATE : EPageAccess.PUBLIC,
};

await createPage(payload)
.then((res) => {
captureSuccess({
eventName: PROJECT_PAGE_TRACKER_EVENTS.create,
payload: {
id: res?.id,
state: "SUCCESS",
},
});
const pageId = `/${workspaceSlug}/projects/${currentProjectDetails?.id}/pages/${res?.id}`;
router.push(pageId);
})
.catch((err) => {
captureError({
eventName: PROJECT_PAGE_TRACKER_EVENTS.create,
payload: {
state: "ERROR",
const pageData = await createPage(payload);
if (!pageData?.id) throw new Error("Invalid response");
if (currentWorkspace && currentUser) {
const role = getWorkspaceRoleByWorkspaceSlug(currentWorkspace.slug);
trackPageCreated(
{
id: pageData.id,
project_id: projectId,
created_at: pageData.created_at ?? "",
},
});
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: err?.data?.error || "Page could not be created. Please try again.",
});
})
.finally(() => setIsCreatingPage(false));
currentWorkspace,
currentUser,
"project",
getUserRoleString(role)
);
}
const pageId = `/${workspaceSlug}/projects/${currentProjectDetails?.id}/pages/${pageData.id}`;
router.push(pageId);
} catch (err: any) {
captureError({
eventName: PROJECT_PAGE_TRACKER_EVENTS.create,
payload: {
state: "ERROR",
error: err?.data?.error,
},
});
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: err?.data?.error || "Page could not be created. Please try again.",
});
} finally {
setIsCreatingPage(false);
}
};

return (
Expand Down
8 changes: 4 additions & 4 deletions apps/web/app/(all)/invitations/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { useAppRouter } from "@/hooks/use-app-router";
import { AuthenticationWrapper } from "@/lib/wrappers/authentication-wrapper";
// plane web services
import { WorkspaceService } from "@/plane-web/services";
import { joinWorkspaceGroup } from "@/plane-web/helpers/event-tracker-v2.helper";

const workspaceService = new WorkspaceService();

Expand Down Expand Up @@ -80,10 +81,9 @@ function UserInvitationsPage() {
const invitation = invitations?.find((i) => i.id === firstInviteId);
const redirectWorkspace = invitations?.find((i) => i.id === firstInviteId)?.workspace;
if (redirectWorkspace?.id) {
joinEventGroup(GROUP_WORKSPACE_TRACKER_EVENT, redirectWorkspace?.id, {
date: new Date().toDateString(),
workspace_id: redirectWorkspace?.id,
});
if (redirectWorkspace) {
joinWorkspaceGroup(redirectWorkspace);
}
}
captureSuccess({
eventName: MEMBER_TRACKER_EVENTS.accept,
Expand Down
Loading
Loading