forked from github/plane
fix: track events updated, extra parameters added, added events for issues, pages, states, cycles (#2875)
* fix: event tracking method updated to store, chore: updated and added events for workspace, projects and create issue * fix: posthog auth event tracking --------- Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
This commit is contained in:
parent
2980c7b00d
commit
11d57a5bf0
@ -35,7 +35,7 @@ from plane.settings.redis import redis_instance
|
|||||||
from plane.bgtasks.magic_link_code_task import magic_link
|
from plane.bgtasks.magic_link_code_task import magic_link
|
||||||
from plane.license.models import InstanceConfiguration
|
from plane.license.models import InstanceConfiguration
|
||||||
from plane.license.utils.instance_value import get_configuration_value
|
from plane.license.utils.instance_value import get_configuration_value
|
||||||
|
from plane.bgtasks.event_tracking_task import auth_events
|
||||||
|
|
||||||
def get_tokens_for_user(user):
|
def get_tokens_for_user(user):
|
||||||
refresh = RefreshToken.for_user(user)
|
refresh = RefreshToken.for_user(user)
|
||||||
@ -162,30 +162,17 @@ class SignUpEndpoint(BaseAPIView):
|
|||||||
workspace_member_invites.delete()
|
workspace_member_invites.delete()
|
||||||
project_member_invites.delete()
|
project_member_invites.delete()
|
||||||
|
|
||||||
try:
|
# Send event
|
||||||
# Send Analytics
|
if settings.POSTHOG_API_KEY and settings.POSTHOG_HOST:
|
||||||
if settings.ANALYTICS_BASE_API:
|
auth_events.delay(
|
||||||
_ = requests.post(
|
user=user.id,
|
||||||
settings.ANALYTICS_BASE_API,
|
email=email,
|
||||||
headers={
|
user_agent=request.META.get("HTTP_USER_AGENT"),
|
||||||
"Content-Type": "application/json",
|
ip=request.META.get("REMOTE_ADDR"),
|
||||||
"X-Auth-Token": settings.ANALYTICS_SECRET_KEY,
|
event_name="SIGN_IN",
|
||||||
},
|
medium="EMAIL",
|
||||||
json={
|
first_time=True
|
||||||
"event_id": uuid.uuid4().hex,
|
)
|
||||||
"event_data": {
|
|
||||||
"medium": "email",
|
|
||||||
},
|
|
||||||
"user": {"email": email, "id": str(user.id)},
|
|
||||||
"device_ctx": {
|
|
||||||
"ip": request.META.get("REMOTE_ADDR"),
|
|
||||||
"user_agent": request.META.get("HTTP_USER_AGENT"),
|
|
||||||
},
|
|
||||||
"event_type": "SIGN_UP",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
except RequestException as e:
|
|
||||||
capture_exception(e)
|
|
||||||
|
|
||||||
access_token, refresh_token = get_tokens_for_user(user)
|
access_token, refresh_token = get_tokens_for_user(user)
|
||||||
|
|
||||||
@ -305,30 +292,17 @@ class SignInEndpoint(BaseAPIView):
|
|||||||
# Delete all the invites
|
# Delete all the invites
|
||||||
workspace_member_invites.delete()
|
workspace_member_invites.delete()
|
||||||
project_member_invites.delete()
|
project_member_invites.delete()
|
||||||
try:
|
# Send event
|
||||||
# Send Analytics
|
if settings.POSTHOG_API_KEY and settings.POSTHOG_HOST:
|
||||||
if settings.ANALYTICS_BASE_API:
|
auth_events.delay(
|
||||||
_ = requests.post(
|
user=user.id,
|
||||||
settings.ANALYTICS_BASE_API,
|
email=email,
|
||||||
headers={
|
user_agent=request.META.get("HTTP_USER_AGENT"),
|
||||||
"Content-Type": "application/json",
|
ip=request.META.get("REMOTE_ADDR"),
|
||||||
"X-Auth-Token": settings.ANALYTICS_SECRET_KEY,
|
event_name="SIGN_IN",
|
||||||
},
|
medium="EMAIL",
|
||||||
json={
|
first_time=False
|
||||||
"event_id": uuid.uuid4().hex,
|
)
|
||||||
"event_data": {
|
|
||||||
"medium": "email",
|
|
||||||
},
|
|
||||||
"user": {"email": email, "id": str(user.id)},
|
|
||||||
"device_ctx": {
|
|
||||||
"ip": request.META.get("REMOTE_ADDR"),
|
|
||||||
"user_agent": request.META.get("HTTP_USER_AGENT"),
|
|
||||||
},
|
|
||||||
"event_type": "SIGN_IN",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
except RequestException as e:
|
|
||||||
capture_exception(e)
|
|
||||||
|
|
||||||
access_token, refresh_token = get_tokens_for_user(user)
|
access_token, refresh_token = get_tokens_for_user(user)
|
||||||
data = {
|
data = {
|
||||||
@ -476,32 +450,25 @@ class MagicSignInEndpoint(BaseAPIView):
|
|||||||
if str(token) == str(user_token):
|
if str(token) == str(user_token):
|
||||||
if User.objects.filter(email=email).exists():
|
if User.objects.filter(email=email).exists():
|
||||||
user = User.objects.get(email=email)
|
user = User.objects.get(email=email)
|
||||||
try:
|
if not user.is_active:
|
||||||
# Send event to Jitsu for tracking
|
return Response(
|
||||||
if settings.ANALYTICS_BASE_API:
|
{
|
||||||
_ = requests.post(
|
"error": "Your account has been deactivated. Please contact your site administrator."
|
||||||
settings.ANALYTICS_BASE_API,
|
},
|
||||||
headers={
|
status=status.HTTP_403_FORBIDDEN,
|
||||||
"Content-Type": "application/json",
|
)
|
||||||
"X-Auth-Token": settings.ANALYTICS_SECRET_KEY,
|
# Send event
|
||||||
},
|
if settings.POSTHOG_API_KEY and settings.POSTHOG_HOST:
|
||||||
json={
|
auth_events.delay(
|
||||||
"event_id": uuid.uuid4().hex,
|
user=user.id,
|
||||||
"event_data": {
|
email=email,
|
||||||
"medium": "code",
|
user_agent=request.META.get("HTTP_USER_AGENT"),
|
||||||
},
|
ip=request.META.get("REMOTE_ADDR"),
|
||||||
"user": {"email": email, "id": str(user.id)},
|
event_name="SIGN_IN",
|
||||||
"device_ctx": {
|
medium="MAGIC_LINK",
|
||||||
"ip": request.META.get("REMOTE_ADDR"),
|
first_time=False
|
||||||
"user_agent": request.META.get(
|
)
|
||||||
"HTTP_USER_AGENT"
|
|
||||||
),
|
|
||||||
},
|
|
||||||
"event_type": "SIGN_IN",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
except RequestException as e:
|
|
||||||
capture_exception(e)
|
|
||||||
else:
|
else:
|
||||||
user = User.objects.create(
|
user = User.objects.create(
|
||||||
email=email,
|
email=email,
|
||||||
@ -509,32 +476,18 @@ class MagicSignInEndpoint(BaseAPIView):
|
|||||||
password=make_password(uuid.uuid4().hex),
|
password=make_password(uuid.uuid4().hex),
|
||||||
is_password_autoset=True,
|
is_password_autoset=True,
|
||||||
)
|
)
|
||||||
try:
|
|
||||||
# Send event to Jitsu for tracking
|
# Send event
|
||||||
if settings.ANALYTICS_BASE_API:
|
if settings.POSTHOG_API_KEY and settings.POSTHOG_HOST:
|
||||||
_ = requests.post(
|
auth_events.delay(
|
||||||
settings.ANALYTICS_BASE_API,
|
user=user.id,
|
||||||
headers={
|
email=email,
|
||||||
"Content-Type": "application/json",
|
user_agent=request.META.get("HTTP_USER_AGENT"),
|
||||||
"X-Auth-Token": settings.ANALYTICS_SECRET_KEY,
|
ip=request.META.get("REMOTE_ADDR"),
|
||||||
},
|
event_name="SIGN_IN",
|
||||||
json={
|
medium="MAGIC_LINK",
|
||||||
"event_id": uuid.uuid4().hex,
|
first_time=True
|
||||||
"event_data": {
|
)
|
||||||
"medium": "code",
|
|
||||||
},
|
|
||||||
"user": {"email": email, "id": str(user.id)},
|
|
||||||
"device_ctx": {
|
|
||||||
"ip": request.META.get("REMOTE_ADDR"),
|
|
||||||
"user_agent": request.META.get(
|
|
||||||
"HTTP_USER_AGENT"
|
|
||||||
),
|
|
||||||
},
|
|
||||||
"event_type": "SIGN_UP",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
except RequestException as e:
|
|
||||||
capture_exception(e)
|
|
||||||
|
|
||||||
user.is_active = True
|
user.is_active = True
|
||||||
user.last_active = timezone.now()
|
user.last_active = timezone.now()
|
||||||
|
@ -29,6 +29,7 @@ from plane.db.models import (
|
|||||||
ProjectMemberInvite,
|
ProjectMemberInvite,
|
||||||
ProjectMember,
|
ProjectMember,
|
||||||
)
|
)
|
||||||
|
from plane.bgtasks.event_tracking_task import auth_events
|
||||||
from .base import BaseAPIView
|
from .base import BaseAPIView
|
||||||
from plane.license.models import InstanceConfiguration
|
from plane.license.models import InstanceConfiguration
|
||||||
from plane.license.utils.instance_value import get_configuration_value
|
from plane.license.utils.instance_value import get_configuration_value
|
||||||
@ -285,29 +286,18 @@ class OauthEndpoint(BaseAPIView):
|
|||||||
"last_login_at": timezone.now(),
|
"last_login_at": timezone.now(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
try:
|
|
||||||
if settings.ANALYTICS_BASE_API:
|
# Send event
|
||||||
_ = requests.post(
|
if settings.POSTHOG_API_KEY and settings.POSTHOG_HOST:
|
||||||
settings.ANALYTICS_BASE_API,
|
auth_events.delay(
|
||||||
headers={
|
user=user.id,
|
||||||
"Content-Type": "application/json",
|
email=email,
|
||||||
"X-Auth-Token": settings.ANALYTICS_SECRET_KEY,
|
user_agent=request.META.get("HTTP_USER_AGENT"),
|
||||||
},
|
ip=request.META.get("REMOTE_ADDR"),
|
||||||
json={
|
event_name="SIGN_IN",
|
||||||
"event_id": uuid.uuid4().hex,
|
medium=medium.upper(),
|
||||||
"event_data": {
|
first_time=False
|
||||||
"medium": f"oauth-{medium}",
|
)
|
||||||
},
|
|
||||||
"user": {"email": email, "id": str(user.id)},
|
|
||||||
"device_ctx": {
|
|
||||||
"ip": request.META.get("REMOTE_ADDR"),
|
|
||||||
"user_agent": request.META.get("HTTP_USER_AGENT"),
|
|
||||||
},
|
|
||||||
"event_type": "SIGN_IN",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
except RequestException as e:
|
|
||||||
capture_exception(e)
|
|
||||||
|
|
||||||
access_token, refresh_token = get_tokens_for_user(user)
|
access_token, refresh_token = get_tokens_for_user(user)
|
||||||
|
|
||||||
@ -428,29 +418,17 @@ class OauthEndpoint(BaseAPIView):
|
|||||||
workspace_member_invites.delete()
|
workspace_member_invites.delete()
|
||||||
project_member_invites.delete()
|
project_member_invites.delete()
|
||||||
|
|
||||||
try:
|
# Send event
|
||||||
if settings.ANALYTICS_BASE_API:
|
if settings.POSTHOG_API_KEY and settings.POSTHOG_HOST:
|
||||||
_ = requests.post(
|
auth_events.delay(
|
||||||
settings.ANALYTICS_BASE_API,
|
user=user.id,
|
||||||
headers={
|
email=email,
|
||||||
"Content-Type": "application/json",
|
user_agent=request.META.get("HTTP_USER_AGENT"),
|
||||||
"X-Auth-Token": settings.ANALYTICS_SECRET_KEY,
|
ip=request.META.get("REMOTE_ADDR"),
|
||||||
},
|
event_name="SIGN_IN",
|
||||||
json={
|
medium=medium.upper(),
|
||||||
"event_id": uuid.uuid4().hex,
|
first_time=True
|
||||||
"event_data": {
|
)
|
||||||
"medium": f"oauth-{medium}",
|
|
||||||
},
|
|
||||||
"user": {"email": email, "id": str(user.id)},
|
|
||||||
"device_ctx": {
|
|
||||||
"ip": request.META.get("REMOTE_ADDR"),
|
|
||||||
"user_agent": request.META.get("HTTP_USER_AGENT"),
|
|
||||||
},
|
|
||||||
"event_type": "SIGN_UP",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
except RequestException as e:
|
|
||||||
capture_exception(e)
|
|
||||||
|
|
||||||
SocialLoginConnection.objects.update_or_create(
|
SocialLoginConnection.objects.update_or_create(
|
||||||
medium=medium,
|
medium=medium,
|
||||||
|
31
apiserver/plane/bgtasks/event_tracking_task.py
Normal file
31
apiserver/plane/bgtasks/event_tracking_task.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import uuid
|
||||||
|
|
||||||
|
from posthog import Posthog
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
#third party imports
|
||||||
|
from celery import shared_task
|
||||||
|
from sentry_sdk import capture_exception
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task
|
||||||
|
def auth_events(user, email, user_agent, ip, event_name, medium, first_time):
|
||||||
|
print(user, email, user_agent, ip, event_name, medium, first_time)
|
||||||
|
try:
|
||||||
|
posthog = Posthog(settings.POSTHOG_API_KEY, host=settings.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
|
||||||
|
}
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
capture_exception(e)
|
@ -322,4 +322,8 @@ ANALYTICS_SECRET_KEY = os.environ.get("ANALYTICS_SECRET_KEY", False)
|
|||||||
ANALYTICS_BASE_API = os.environ.get("ANALYTICS_BASE_API", False)
|
ANALYTICS_BASE_API = os.environ.get("ANALYTICS_BASE_API", False)
|
||||||
|
|
||||||
# Use Minio settings
|
# Use Minio settings
|
||||||
USE_MINIO = int(os.environ.get("USE_MINIO", 0)) == 1
|
USE_MINIO = int(os.environ.get("USE_MINIO", 0)) == 1
|
||||||
|
|
||||||
|
# Posthog settings
|
||||||
|
POSTHOG_API_KEY = os.environ.get("POSTHOG_API_KEY", False)
|
||||||
|
POSTHOG_HOST = os.environ.get("POSTHOG_HOST", False)
|
@ -36,3 +36,4 @@ scout-apm==2.26.1
|
|||||||
openpyxl==3.1.2
|
openpyxl==3.1.2
|
||||||
beautifulsoup4==4.12.2
|
beautifulsoup4==4.12.2
|
||||||
dj-database-url==2.1.0
|
dj-database-url==2.1.0
|
||||||
|
posthog==3.0.2
|
@ -14,6 +14,7 @@ export const CommandPaletteProjectActions: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
commandPalette: { toggleCreateCycleModal, toggleCreateModuleModal, toggleCreatePageModal, toggleCreateViewModal },
|
commandPalette: { toggleCreateCycleModal, toggleCreateModuleModal, toggleCreatePageModal, toggleCreateViewModal },
|
||||||
|
trackEvent: { setTrackElement }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -22,6 +23,7 @@ export const CommandPaletteProjectActions: React.FC<Props> = (props) => {
|
|||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
closePalette();
|
closePalette();
|
||||||
|
setTrackElement("COMMAND_PALETTE")
|
||||||
toggleCreateCycleModal(true);
|
toggleCreateCycleModal(true);
|
||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
|
@ -62,6 +62,7 @@ export const CommandModal: React.FC = observer(() => {
|
|||||||
toggleCreateIssueModal,
|
toggleCreateIssueModal,
|
||||||
toggleCreateProjectModal,
|
toggleCreateProjectModal,
|
||||||
},
|
},
|
||||||
|
trackEvent: { setTrackElement }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
// router
|
// router
|
||||||
@ -273,6 +274,7 @@ export const CommandModal: React.FC = observer(() => {
|
|||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
closePalette();
|
closePalette();
|
||||||
|
setTrackElement("COMMAND_PALETTE");
|
||||||
toggleCreateIssueModal(true);
|
toggleCreateIssueModal(true);
|
||||||
}}
|
}}
|
||||||
className="focus:bg-custom-background-80"
|
className="focus:bg-custom-background-80"
|
||||||
@ -290,6 +292,7 @@ export const CommandModal: React.FC = observer(() => {
|
|||||||
<Command.Item
|
<Command.Item
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
closePalette();
|
closePalette();
|
||||||
|
setTrackElement("COMMAND_PALETTE");
|
||||||
toggleCreateProjectModal(true);
|
toggleCreateProjectModal(true);
|
||||||
}}
|
}}
|
||||||
className="focus:outline-none"
|
className="focus:outline-none"
|
||||||
|
@ -33,6 +33,7 @@ export const CommandPalette: FC = observer(() => {
|
|||||||
commandPalette,
|
commandPalette,
|
||||||
theme: { toggleSidebar },
|
theme: { toggleSidebar },
|
||||||
user: { currentUser },
|
user: { currentUser },
|
||||||
|
trackEvent: { setTrackElement }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
const {
|
const {
|
||||||
toggleCommandPaletteModal,
|
toggleCommandPaletteModal,
|
||||||
@ -112,8 +113,10 @@ export const CommandPalette: FC = observer(() => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (keyPressed === "c") {
|
if (keyPressed === "c") {
|
||||||
|
setTrackElement("SHORTCUT_KEY");
|
||||||
toggleCreateIssueModal(true);
|
toggleCreateIssueModal(true);
|
||||||
} else if (keyPressed === "p") {
|
} else if (keyPressed === "p") {
|
||||||
|
setTrackElement("SHORTCUT_KEY");
|
||||||
toggleCreateProjectModal(true);
|
toggleCreateProjectModal(true);
|
||||||
} else if (keyPressed === "h") {
|
} else if (keyPressed === "h") {
|
||||||
toggleShortcutModal(true);
|
toggleShortcutModal(true);
|
||||||
|
@ -33,7 +33,7 @@ export interface ICyclesBoardCard {
|
|||||||
export const CyclesBoardCard: FC<ICyclesBoardCard> = (props) => {
|
export const CyclesBoardCard: FC<ICyclesBoardCard> = (props) => {
|
||||||
const { cycle, workspaceSlug, projectId } = props;
|
const { cycle, workspaceSlug, projectId } = props;
|
||||||
// store
|
// store
|
||||||
const { cycle: cycleStore } = useMobxStore();
|
const { cycle: cycleStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
// toast
|
// toast
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
// states
|
// states
|
||||||
@ -119,6 +119,7 @@ export const CyclesBoardCard: FC<ICyclesBoardCard> = (props) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setDeleteModal(true);
|
setDeleteModal(true);
|
||||||
|
setTrackElement("CYCLE_PAGE_BOARD_LAYOUT");
|
||||||
};
|
};
|
||||||
|
|
||||||
const openCycleOverview = (e: MouseEvent<HTMLButtonElement>) => {
|
const openCycleOverview = (e: MouseEvent<HTMLButtonElement>) => {
|
||||||
@ -252,7 +253,7 @@ export const CyclesBoardCard: FC<ICyclesBoardCard> = (props) => {
|
|||||||
<CustomMenu.MenuItem onClick={handleDeleteCycle}>
|
<CustomMenu.MenuItem onClick={handleDeleteCycle}>
|
||||||
<span className="flex items-center justify-start gap-2">
|
<span className="flex items-center justify-start gap-2">
|
||||||
<Trash2 className="h-3 w-3" />
|
<Trash2 className="h-3 w-3" />
|
||||||
<span>Delete module</span>
|
<span>Delete cycle</span>
|
||||||
</span>
|
</span>
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
</>
|
</>
|
||||||
|
@ -38,7 +38,7 @@ type TCyclesListItem = {
|
|||||||
export const CyclesListItem: FC<TCyclesListItem> = (props) => {
|
export const CyclesListItem: FC<TCyclesListItem> = (props) => {
|
||||||
const { cycle, workspaceSlug, projectId } = props;
|
const { cycle, workspaceSlug, projectId } = props;
|
||||||
// store
|
// store
|
||||||
const { cycle: cycleStore } = useMobxStore();
|
const { cycle: cycleStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
// toast
|
// toast
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
// states
|
// states
|
||||||
@ -119,6 +119,7 @@ export const CyclesListItem: FC<TCyclesListItem> = (props) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setDeleteModal(true);
|
setDeleteModal(true);
|
||||||
|
setTrackElement("CYCLE_PAGE_LIST_LAYOUT");
|
||||||
};
|
};
|
||||||
|
|
||||||
const openCycleOverview = (e: MouseEvent<HTMLButtonElement>) => {
|
const openCycleOverview = (e: MouseEvent<HTMLButtonElement>) => {
|
||||||
|
@ -19,7 +19,7 @@ export interface ICyclesList {
|
|||||||
export const CyclesList: FC<ICyclesList> = observer((props) => {
|
export const CyclesList: FC<ICyclesList> = observer((props) => {
|
||||||
const { cycles, filter, workspaceSlug, projectId } = props;
|
const { cycles, filter, workspaceSlug, projectId } = props;
|
||||||
|
|
||||||
const { commandPalette: commandPaletteStore } = useMobxStore();
|
const { commandPalette: commandPaletteStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -57,7 +57,11 @@ export const CyclesList: FC<ICyclesList> = observer((props) => {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="text-custom-primary-100 text-sm outline-none"
|
className="text-custom-primary-100 text-sm outline-none"
|
||||||
onClick={() => commandPaletteStore.toggleCreateCycleModal(true)}
|
onClick={() => {
|
||||||
|
setTrackElement("CYCLES_PAGE_EMPTY-STATE");
|
||||||
|
commandPaletteStore.toggleCreateCycleModal(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Create a new cycle
|
Create a new cycle
|
||||||
</button>
|
</button>
|
||||||
|
@ -24,7 +24,7 @@ interface ICycleDelete {
|
|||||||
export const CycleDeleteModal: React.FC<ICycleDelete> = observer((props) => {
|
export const CycleDeleteModal: React.FC<ICycleDelete> = observer((props) => {
|
||||||
const { isOpen, handleClose, cycle, workspaceSlug, projectId } = props;
|
const { isOpen, handleClose, cycle, workspaceSlug, projectId } = props;
|
||||||
// store
|
// store
|
||||||
const { cycle: cycleStore } = useMobxStore();
|
const { cycle: cycleStore, trackEvent: { postHogEventTracker } } = useMobxStore();
|
||||||
// toast
|
// toast
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
// states
|
// states
|
||||||
@ -36,11 +36,25 @@ export const CycleDeleteModal: React.FC<ICycleDelete> = observer((props) => {
|
|||||||
setLoader(true);
|
setLoader(true);
|
||||||
if (cycle?.id)
|
if (cycle?.id)
|
||||||
try {
|
try {
|
||||||
await cycleStore.removeCycle(workspaceSlug, projectId, cycle?.id);
|
await cycleStore.removeCycle(workspaceSlug, projectId, cycle?.id).then((res) => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Cycle deleted successfully.",
|
message: "Cycle deleted successfully.",
|
||||||
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
"CYCLE_DELETE",
|
||||||
|
{
|
||||||
|
state: "SUCCESS"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}).catch((error) => {
|
||||||
|
postHogEventTracker(
|
||||||
|
"CYCLE_DELETE",
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (cycleId) router.replace(`/${workspaceSlug}/projects/${projectId}/cycles`);
|
if (cycleId) router.replace(`/${workspaceSlug}/projects/${projectId}/cycles`);
|
||||||
|
@ -24,7 +24,7 @@ const cycleService = new CycleService();
|
|||||||
export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
|
export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
|
||||||
const { isOpen, handleClose, data, workspaceSlug, projectId } = props;
|
const { isOpen, handleClose, data, workspaceSlug, projectId } = props;
|
||||||
// store
|
// store
|
||||||
const { cycle: cycleStore } = useMobxStore();
|
const { cycle: cycleStore, trackEvent: { postHogEventTracker } } = useMobxStore();
|
||||||
// states
|
// states
|
||||||
const [activeProject, setActiveProject] = useState<string>(projectId);
|
const [activeProject, setActiveProject] = useState<string>(projectId);
|
||||||
// toast
|
// toast
|
||||||
@ -35,12 +35,19 @@ export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
|
|||||||
const selectedProjectId = payload.project ?? projectId.toString();
|
const selectedProjectId = payload.project ?? projectId.toString();
|
||||||
await cycleStore
|
await cycleStore
|
||||||
.createCycle(workspaceSlug, selectedProjectId, payload)
|
.createCycle(workspaceSlug, selectedProjectId, payload)
|
||||||
.then(() => {
|
.then((res) => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Cycle created successfully.",
|
message: "Cycle created successfully.",
|
||||||
});
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
"CYCLE_CREATE",
|
||||||
|
{
|
||||||
|
...res,
|
||||||
|
state: "SUCCESS",
|
||||||
|
}
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -48,6 +55,12 @@ export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
|
|||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Error in creating cycle. Please try again.",
|
message: "Error in creating cycle. Please try again.",
|
||||||
});
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
"CYCLE_CREATE",
|
||||||
|
{
|
||||||
|
state: "FAILED",
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, peekCycle } = router.query;
|
const { workspaceSlug, projectId, peekCycle } = router.query;
|
||||||
|
|
||||||
const { cycle: cycleDetailsStore } = useMobxStore();
|
const { cycle: cycleDetailsStore, trackEvent: { setTrackElement, postHogEventTracker } } = useMobxStore();
|
||||||
|
|
||||||
const cycleDetails = cycleDetailsStore.cycle_details[cycleId] ?? undefined;
|
const cycleDetails = cycleDetailsStore.cycle_details[cycleId] ?? undefined;
|
||||||
|
|
||||||
@ -74,8 +74,27 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
cycleService
|
cycleService
|
||||||
.patchCycle(workspaceSlug as string, projectId as string, cycleId as string, data)
|
.patchCycle(workspaceSlug as string, projectId as string, cycleId as string, data)
|
||||||
.then(() => mutate(CYCLE_DETAILS(cycleId as string)))
|
.then((res) => {
|
||||||
.catch((e) => console.log(e));
|
mutate(CYCLE_DETAILS(cycleId as string));
|
||||||
|
postHogEventTracker(
|
||||||
|
"CYCLE_UPDATE",
|
||||||
|
{
|
||||||
|
...res,
|
||||||
|
state: "SUCCESS"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
postHogEventTracker(
|
||||||
|
"CYCLE_UPDATE",
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCopyText = () => {
|
const handleCopyText = () => {
|
||||||
@ -284,10 +303,10 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
cycleDetails.total_issues === 0
|
cycleDetails.total_issues === 0
|
||||||
? "0 Issue"
|
? "0 Issue"
|
||||||
: cycleDetails.total_issues === cycleDetails.completed_issues
|
: cycleDetails.total_issues === cycleDetails.completed_issues
|
||||||
? cycleDetails.total_issues > 1
|
? cycleDetails.total_issues > 1
|
||||||
? `${cycleDetails.total_issues}`
|
? `${cycleDetails.total_issues}`
|
||||||
: `${cycleDetails.total_issues}`
|
: `${cycleDetails.total_issues}`
|
||||||
: `${cycleDetails.completed_issues}/${cycleDetails.total_issues}`;
|
: `${cycleDetails.completed_issues}/${cycleDetails.total_issues}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -317,7 +336,11 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
</button>
|
</button>
|
||||||
{!isCompleted && (
|
{!isCompleted && (
|
||||||
<CustomMenu width="lg" placement="bottom-end" ellipsis>
|
<CustomMenu width="lg" placement="bottom-end" ellipsis>
|
||||||
<CustomMenu.MenuItem onClick={() => setCycleDeleteModal(true)}>
|
<CustomMenu.MenuItem onClick={() => {
|
||||||
|
setTrackElement("CYCLE_PAGE_SIDEBAR");
|
||||||
|
setCycleDeleteModal(true)
|
||||||
|
}
|
||||||
|
}>
|
||||||
<span className="flex items-center justify-start gap-2">
|
<span className="flex items-center justify-start gap-2">
|
||||||
<Trash2 className="h-3 w-3" />
|
<Trash2 className="h-3 w-3" />
|
||||||
<span>Delete cycle</span>
|
<span>Delete cycle</span>
|
||||||
@ -367,6 +390,7 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
value={watch("start_date") ? watch("start_date") : cycleDetails?.start_date}
|
value={watch("start_date") ? watch("start_date") : cycleDetails?.start_date}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
|
setTrackElement("CYCLE_PAGE_SIDEBAR_START_DATE_BUTTON");
|
||||||
handleStartDateChange(val);
|
handleStartDateChange(val);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@ -402,6 +426,7 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
value={watch("end_date") ? watch("end_date") : cycleDetails?.end_date}
|
value={watch("end_date") ? watch("end_date") : cycleDetails?.end_date}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
|
setTrackElement("CYCLE_PAGE_SIDEBAR_END_DATE_BUTTON");
|
||||||
handleEndDateChange(val);
|
handleEndDateChange(val);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -40,7 +40,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
|
|||||||
projectLabel: { projectLabels },
|
projectLabel: { projectLabels },
|
||||||
projectState: projectStateStore,
|
projectState: projectStateStore,
|
||||||
commandPalette: commandPaletteStore,
|
commandPalette: commandPaletteStore,
|
||||||
|
trackEvent: { setTrackElement },
|
||||||
cycleIssuesFilter: { issueFilters, updateFilters },
|
cycleIssuesFilter: { issueFilters, updateFilters },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
@ -190,7 +190,11 @@ export const CycleIssuesHeader: React.FC = observer(() => {
|
|||||||
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
|
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
|
||||||
Analytics
|
Analytics
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => commandPaletteStore.toggleCreateIssueModal(true)} size="sm" prependIcon={<Plus />}>
|
<Button onClick={() => {
|
||||||
|
setTrackElement("CYCLE_PAGE_HEADER")
|
||||||
|
commandPaletteStore.toggleCreateIssueModal(true)
|
||||||
|
}
|
||||||
|
} size="sm" prependIcon={<Plus />}>
|
||||||
Add Issue
|
Add Issue
|
||||||
</Button>
|
</Button>
|
||||||
<button
|
<button
|
||||||
|
@ -14,7 +14,7 @@ export const CyclesHeader: FC = observer(() => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
// store
|
// store
|
||||||
const { project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
|
const { project: projectStore, commandPalette: commandPaletteStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
const { currentProjectDetails } = projectStore;
|
const { currentProjectDetails } = projectStore;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -51,7 +51,11 @@ export const CyclesHeader: FC = observer(() => {
|
|||||||
variant="primary"
|
variant="primary"
|
||||||
size="sm"
|
size="sm"
|
||||||
prependIcon={<Plus />}
|
prependIcon={<Plus />}
|
||||||
onClick={() => commandPaletteStore.toggleCreateCycleModal(true)}
|
onClick={() => {
|
||||||
|
setTrackElement("CYCLES_PAGE_HEADER");
|
||||||
|
commandPaletteStore.toggleCreateCycleModal(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Add Cycle
|
Add Cycle
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -38,6 +38,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
|||||||
projectMember: { projectMembers },
|
projectMember: { projectMembers },
|
||||||
projectState: projectStateStore,
|
projectState: projectStateStore,
|
||||||
commandPalette: commandPaletteStore,
|
commandPalette: commandPaletteStore,
|
||||||
|
trackEvent: { setTrackElement },
|
||||||
projectLabel: { projectLabels },
|
projectLabel: { projectLabels },
|
||||||
moduleIssuesFilter: { issueFilters, updateFilters },
|
moduleIssuesFilter: { issueFilters, updateFilters },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
@ -190,7 +191,11 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
|||||||
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
|
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
|
||||||
Analytics
|
Analytics
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => commandPaletteStore.toggleCreateIssueModal(true)} size="sm" prependIcon={<Plus />}>
|
<Button onClick={() => {
|
||||||
|
setTrackElement("MODULE_PAGE_HEADER")
|
||||||
|
commandPaletteStore.toggleCreateIssueModal(true)
|
||||||
|
}
|
||||||
|
} size="sm" prependIcon={<Plus />}>
|
||||||
Add Issue
|
Add Issue
|
||||||
</Button>
|
</Button>
|
||||||
<button
|
<button
|
||||||
|
@ -31,6 +31,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
|
|||||||
projectState: projectStateStore,
|
projectState: projectStateStore,
|
||||||
inbox: inboxStore,
|
inbox: inboxStore,
|
||||||
commandPalette: commandPaletteStore,
|
commandPalette: commandPaletteStore,
|
||||||
|
trackEvent: { setTrackElement },
|
||||||
// issue filters
|
// issue filters
|
||||||
projectIssuesFilter: { issueFilters, updateFilters },
|
projectIssuesFilter: { issueFilters, updateFilters },
|
||||||
projectIssues: {},
|
projectIssues: {},
|
||||||
@ -198,7 +199,11 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
|
|||||||
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
|
<Button onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
|
||||||
Analytics
|
Analytics
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => commandPaletteStore.toggleCreateIssueModal(true)} size="sm" prependIcon={<Plus />}>
|
<Button onClick={() => {
|
||||||
|
setTrackElement("PROJECT_PAGE_HEADER");
|
||||||
|
commandPaletteStore.toggleCreateIssueModal(true)
|
||||||
|
}
|
||||||
|
} size="sm" prependIcon={<Plus />}>
|
||||||
Add Issue
|
Add Issue
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,7 +11,7 @@ export const ProjectsHeader = observer(() => {
|
|||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
// store
|
// store
|
||||||
const { project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
|
const { project: projectStore, commandPalette: commandPaletteStore, trackEvent: {setTrackElement} } = useMobxStore();
|
||||||
|
|
||||||
const projectsList = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : [];
|
const projectsList = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : [];
|
||||||
|
|
||||||
@ -41,7 +41,10 @@ export const ProjectsHeader = observer(() => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Button prependIcon={<Plus />} size="sm" onClick={() => commandPaletteStore.toggleCreateProjectModal(true)}>
|
<Button prependIcon={<Plus />} size="sm" onClick={() => {
|
||||||
|
setTrackElement("PROJECTS_PAGE_HEADER");
|
||||||
|
commandPaletteStore.toggleCreateProjectModal(true)
|
||||||
|
}}>
|
||||||
Add Project
|
Add Project
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,9 +8,11 @@ import githubWhiteImage from "/public/logos/github-white.png";
|
|||||||
// components
|
// components
|
||||||
import { ProductUpdatesModal } from "components/common";
|
import { ProductUpdatesModal } from "components/common";
|
||||||
import { Breadcrumbs } from "@plane/ui";
|
import { Breadcrumbs } from "@plane/ui";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
export const WorkspaceDashboardHeader = () => {
|
export const WorkspaceDashboardHeader = () => {
|
||||||
const [isProductUpdatesModalOpen, setIsProductUpdatesModalOpen] = useState(false);
|
const [isProductUpdatesModalOpen, setIsProductUpdatesModalOpen] = useState(false);
|
||||||
|
const { trackEvent: { postHogEventTracker } } = useMobxStore();
|
||||||
// theme
|
// theme
|
||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, inboxId } = router.query;
|
const { workspaceSlug, projectId, inboxId } = router.query;
|
||||||
|
|
||||||
const { inboxIssueDetails: inboxIssueDetailsStore } = useMobxStore();
|
const { inboxIssueDetails: inboxIssueDetailsStore, trackEvent: { postHogEventTracker } } = useMobxStore();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@ -70,6 +70,21 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
|
|||||||
router.push(`/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}?inboxIssueId=${res.issue_inbox[0].id}`);
|
router.push(`/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}?inboxIssueId=${res.issue_inbox[0].id}`);
|
||||||
handleClose();
|
handleClose();
|
||||||
} else reset(defaultValues);
|
} else reset(defaultValues);
|
||||||
|
postHogEventTracker(
|
||||||
|
"ISSUE_CREATE",
|
||||||
|
{
|
||||||
|
...res,
|
||||||
|
state: "SUCCESS"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
postHogEventTracker(
|
||||||
|
"ISSUE_CREATE",
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -172,7 +187,7 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
|
|||||||
onClick={() => setCreateMore((prevData) => !prevData)}
|
onClick={() => setCreateMore((prevData) => !prevData)}
|
||||||
>
|
>
|
||||||
<span className="text-xs">Create more</span>
|
<span className="text-xs">Create more</span>
|
||||||
<ToggleSwitch value={createMore} onChange={() => {}} size="md" />
|
<ToggleSwitch value={createMore} onChange={() => { }} size="md" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Button variant="neutral-primary" size="sm" onClick={() => handleClose()}>
|
<Button variant="neutral-primary" size="sm" onClick={() => handleClose()}>
|
||||||
|
@ -16,7 +16,7 @@ export const JiraGetImportDetail: React.FC = observer(() => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
const { project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
|
const { project: projectStore, commandPalette: commandPaletteStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined;
|
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : undefined;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -190,7 +190,10 @@ export const JiraGetImportDetail: React.FC = observer(() => {
|
|||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => commandPaletteStore.toggleCreateProjectModal(true)}
|
onClick={() => {
|
||||||
|
setTrackElement("JIRA_IMPORT_DETAIL");
|
||||||
|
commandPaletteStore.toggleCreateProjectModal(true)
|
||||||
|
}}
|
||||||
className="flex cursor-pointer select-none items-center space-x-2 truncate rounded px-1 py-1.5 text-custom-text-200"
|
className="flex cursor-pointer select-none items-center space-x-2 truncate rounded px-1 py-1.5 text-custom-text-200"
|
||||||
>
|
>
|
||||||
<Plus className="h-4 w-4 text-custom-text-200" />
|
<Plus className="h-4 w-4 text-custom-text-200" />
|
||||||
|
@ -26,7 +26,7 @@ export const CycleEmptyState: React.FC<Props> = observer((props) => {
|
|||||||
// states
|
// states
|
||||||
const [cycleIssuesListModal, setCycleIssuesListModal] = useState(false);
|
const [cycleIssuesListModal, setCycleIssuesListModal] = useState(false);
|
||||||
|
|
||||||
const { cycleIssue: cycleIssueStore, commandPalette: commandPaletteStore } = useMobxStore();
|
const { cycleIssue: cycleIssueStore, commandPalette: commandPaletteStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
@ -62,7 +62,10 @@ export const CycleEmptyState: React.FC<Props> = observer((props) => {
|
|||||||
primaryButton={{
|
primaryButton={{
|
||||||
text: "New issue",
|
text: "New issue",
|
||||||
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
||||||
onClick: () => commandPaletteStore.toggleCreateIssueModal(true),
|
onClick: () => {
|
||||||
|
setTrackElement("CYCLE_EMPTY_STATE")
|
||||||
|
commandPaletteStore.toggleCreateIssueModal(true)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
secondaryButton={
|
secondaryButton={
|
||||||
<Button
|
<Button
|
||||||
|
@ -15,7 +15,7 @@ export const GlobalViewEmptyState: React.FC = observer(() => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
const { commandPalette: commandPaletteStore, project: projectStore } = useMobxStore();
|
const { commandPalette: commandPaletteStore, project: projectStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
|
|
||||||
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : null;
|
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : null;
|
||||||
|
|
||||||
@ -29,7 +29,10 @@ export const GlobalViewEmptyState: React.FC = observer(() => {
|
|||||||
primaryButton={{
|
primaryButton={{
|
||||||
icon: <Plus className="h-4 w-4" />,
|
icon: <Plus className="h-4 w-4" />,
|
||||||
text: "New Project",
|
text: "New Project",
|
||||||
onClick: () => commandPaletteStore.toggleCreateProjectModal(true),
|
onClick: () => {
|
||||||
|
setTrackElement("ALL_ISSUES_EMPTY_STATE")
|
||||||
|
commandPaletteStore.toggleCreateProjectModal(true)
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@ -40,7 +43,10 @@ export const GlobalViewEmptyState: React.FC = observer(() => {
|
|||||||
primaryButton={{
|
primaryButton={{
|
||||||
text: "New issue",
|
text: "New issue",
|
||||||
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
||||||
onClick: () => commandPaletteStore.toggleCreateIssueModal(true),
|
onClick: () => {
|
||||||
|
setTrackElement("ALL_ISSUES_EMPTY_STATE")
|
||||||
|
commandPaletteStore.toggleCreateIssueModal(true)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -22,7 +22,7 @@ export const ModuleEmptyState: React.FC<Props> = observer((props) => {
|
|||||||
// states
|
// states
|
||||||
const [moduleIssuesListModal, setModuleIssuesListModal] = useState(false);
|
const [moduleIssuesListModal, setModuleIssuesListModal] = useState(false);
|
||||||
|
|
||||||
const { moduleIssue: moduleIssueStore, commandPalette: commandPaletteStore } = useMobxStore();
|
const { moduleIssue: moduleIssueStore, commandPalette: commandPaletteStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
@ -58,7 +58,10 @@ export const ModuleEmptyState: React.FC<Props> = observer((props) => {
|
|||||||
primaryButton={{
|
primaryButton={{
|
||||||
text: "New issue",
|
text: "New issue",
|
||||||
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
||||||
onClick: () => commandPaletteStore.toggleCreateIssueModal(true),
|
onClick: () => {
|
||||||
|
setTrackElement("MODULE_EMPTY_STATE");
|
||||||
|
commandPaletteStore.toggleCreateIssueModal(true)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
secondaryButton={
|
secondaryButton={
|
||||||
<Button
|
<Button
|
||||||
|
@ -8,7 +8,7 @@ import { EmptyState } from "components/common";
|
|||||||
import emptyIssue from "public/empty-state/issue.svg";
|
import emptyIssue from "public/empty-state/issue.svg";
|
||||||
|
|
||||||
export const ProjectViewEmptyState: React.FC = observer(() => {
|
export const ProjectViewEmptyState: React.FC = observer(() => {
|
||||||
const { commandPalette: commandPaletteStore } = useMobxStore();
|
const { commandPalette: commandPaletteStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full w-full grid place-items-center">
|
<div className="h-full w-full grid place-items-center">
|
||||||
@ -19,7 +19,10 @@ export const ProjectViewEmptyState: React.FC = observer(() => {
|
|||||||
primaryButton={{
|
primaryButton={{
|
||||||
text: "New issue",
|
text: "New issue",
|
||||||
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
||||||
onClick: () => commandPaletteStore.toggleCreateIssueModal(true),
|
onClick: () => {
|
||||||
|
setTrackElement("VIEW_EMPTY_STATE");
|
||||||
|
commandPaletteStore.toggleCreateIssueModal(true)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,7 +8,7 @@ import { EmptyState } from "components/common";
|
|||||||
import emptyIssue from "public/empty-state/issue.svg";
|
import emptyIssue from "public/empty-state/issue.svg";
|
||||||
|
|
||||||
export const ProjectEmptyState: React.FC = observer(() => {
|
export const ProjectEmptyState: React.FC = observer(() => {
|
||||||
const { commandPalette: commandPaletteStore } = useMobxStore();
|
const { commandPalette: commandPaletteStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full w-full grid place-items-center">
|
<div className="h-full w-full grid place-items-center">
|
||||||
@ -19,7 +19,10 @@ export const ProjectEmptyState: React.FC = observer(() => {
|
|||||||
primaryButton={{
|
primaryButton={{
|
||||||
text: "New issue",
|
text: "New issue",
|
||||||
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
||||||
onClick: () => commandPaletteStore.toggleCreateIssueModal(true),
|
onClick: () => {
|
||||||
|
setTrackElement("PROJECT_EMPTY_STATE");
|
||||||
|
commandPaletteStore.toggleCreateIssueModal(true)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -72,6 +72,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
cycleIssue: cycleIssueStore,
|
cycleIssue: cycleIssueStore,
|
||||||
moduleIssue: moduleIssueStore,
|
moduleIssue: moduleIssueStore,
|
||||||
user: userStore,
|
user: userStore,
|
||||||
|
trackEvent: { postHogEventTracker }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
const user = userStore.currentUser;
|
const user = userStore.currentUser;
|
||||||
@ -208,16 +209,27 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Issue created successfully.",
|
message: "Issue created successfully.",
|
||||||
});
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
"ISSUE_CREATE",
|
||||||
|
{
|
||||||
|
...res,
|
||||||
|
state: "SUCCESS"
|
||||||
|
}
|
||||||
|
);
|
||||||
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
|
if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent));
|
||||||
}
|
}
|
||||||
})
|
}).catch(() => {
|
||||||
.catch(() => {
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "error",
|
type: "error",
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Issue could not be created. Please try again.",
|
message: "Issue could not be created. Please try again.",
|
||||||
});
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
"ISSUE_CREATE",
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!createMore) onFormSubmitClose();
|
if (!createMore) onFormSubmitClose();
|
||||||
@ -232,13 +244,12 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
|
|
||||||
await issueDraftService
|
await issueDraftService
|
||||||
.createDraftIssue(workspaceSlug as string, activeProject ?? "", payload)
|
.createDraftIssue(workspaceSlug as string, activeProject ?? "", payload)
|
||||||
.then(() => {
|
.then((res) => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Draft Issue created successfully.",
|
message: "Draft Issue created successfully.",
|
||||||
});
|
});
|
||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
setActiveProject(null);
|
setActiveProject(null);
|
||||||
setFormDirtyState(null);
|
setFormDirtyState(null);
|
||||||
@ -262,7 +273,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
|
|
||||||
await issueDetailStore
|
await issueDetailStore
|
||||||
.updateIssue(workspaceSlug.toString(), activeProject, data.id, payload)
|
.updateIssue(workspaceSlug.toString(), activeProject, data.id, payload)
|
||||||
.then(() => {
|
.then((res) => {
|
||||||
if (!createMore) onFormSubmitClose();
|
if (!createMore) onFormSubmitClose();
|
||||||
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -270,6 +281,13 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Issue updated successfully.",
|
message: "Issue updated successfully.",
|
||||||
});
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
"ISSUE_UPDATE",
|
||||||
|
{
|
||||||
|
...res,
|
||||||
|
state: "SUCCESS"
|
||||||
|
}
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -277,6 +295,12 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Issue could not be updated. Please try again.",
|
message: "Issue could not be updated. Please try again.",
|
||||||
});
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
"ISSUE_UPDATE",
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { CheckCircle2, Search } from "lucide-react";
|
|
||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
import { trackEvent } from "helpers/event-tracker.helper";
|
|
||||||
// components
|
// components
|
||||||
import { Button, Loader } from "@plane/ui";
|
import { Button, Loader } from "@plane/ui";
|
||||||
|
|
||||||
@ -17,6 +15,8 @@ import { USER_WORKSPACES, USER_WORKSPACE_INVITATIONS } from "constants/fetch-key
|
|||||||
import { ROLE } from "constants/workspace";
|
import { ROLE } from "constants/workspace";
|
||||||
// types
|
// types
|
||||||
import { IWorkspaceMemberInvitation } from "types";
|
import { IWorkspaceMemberInvitation } from "types";
|
||||||
|
// icons
|
||||||
|
import { CheckCircle2, Search } from "lucide-react";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
handleNextStep: () => void;
|
handleNextStep: () => void;
|
||||||
@ -32,6 +32,7 @@ const Invitations: React.FC<Props> = (props) => {
|
|||||||
const {
|
const {
|
||||||
workspace: workspaceStore,
|
workspace: workspaceStore,
|
||||||
user: { currentUser, updateCurrentUser },
|
user: { currentUser, updateCurrentUser },
|
||||||
|
trackEvent: { postHogEventTracker }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -63,14 +64,17 @@ const Invitations: React.FC<Props> = (props) => {
|
|||||||
await workspaceService
|
await workspaceService
|
||||||
.joinWorkspaces({ invitations: invitationsRespond })
|
.joinWorkspaces({ invitations: invitationsRespond })
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
trackEvent("WORKSPACE_USER_INVITE_ACCEPT", res);
|
postHogEventTracker("WORKSPACE_USER_INVITE_ACCEPT", { ...res, state: "SUCCESS" });
|
||||||
await mutateInvitations();
|
await mutateInvitations();
|
||||||
await workspaceStore.fetchWorkspaces();
|
await workspaceStore.fetchWorkspaces();
|
||||||
await mutate(USER_WORKSPACES);
|
await mutate(USER_WORKSPACES);
|
||||||
await updateLastWorkspace();
|
await updateLastWorkspace();
|
||||||
await handleNextStep();
|
await handleNextStep();
|
||||||
})
|
})
|
||||||
.finally(() => setIsJoiningWorkspaces(false));
|
.catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
postHogEventTracker("WORKSPACE_USER_INVITE_ACCEPT", { state: "FAILED" });
|
||||||
|
}).finally(() => setIsJoiningWorkspaces(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
return invitations && invitations.length > 0 ? (
|
return invitations && invitations.length > 0 ? (
|
||||||
@ -85,11 +89,10 @@ const Invitations: React.FC<Props> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={invitation.id}
|
key={invitation.id}
|
||||||
className={`flex cursor-pointer items-center gap-2 border p-3.5 rounded ${
|
className={`flex cursor-pointer items-center gap-2 border p-3.5 rounded ${isSelected
|
||||||
isSelected
|
? "border-custom-primary-100"
|
||||||
? "border-custom-primary-100"
|
: "border-onboarding-border-200 hover:bg-onboarding-background-300/30"
|
||||||
: "border-onboarding-border-200 hover:bg-onboarding-background-300/30"
|
}`}
|
||||||
}`}
|
|
||||||
onClick={() => handleInvitation(invitation, isSelected ? "withdraw" : "accepted")}
|
onClick={() => handleInvitation(invitation, isSelected ? "withdraw" : "accepted")}
|
||||||
>
|
>
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
|
@ -166,8 +166,7 @@ const InviteMemberForm: React.FC<InviteMemberFormProps> = (props) => {
|
|||||||
key={key}
|
key={key}
|
||||||
value={parseInt(key)}
|
value={parseInt(key)}
|
||||||
className={({ active, selected }) =>
|
className={({ active, selected }) =>
|
||||||
`cursor-pointer select-none truncate rounded px-1 py-1.5 ${
|
`cursor-pointer select-none truncate rounded px-1 py-1.5 ${active || selected ? "bg-onboarding-background-400/40" : ""
|
||||||
active || selected ? "bg-onboarding-background-400/40" : ""
|
|
||||||
} ${selected ? "text-onboarding-text-100" : "text-custom-text-200"}`
|
} ${selected ? "text-onboarding-text-100" : "text-custom-text-200"}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -79,7 +79,7 @@ export const TourRoot: React.FC<Props> = observer((props) => {
|
|||||||
// states
|
// states
|
||||||
const [step, setStep] = useState<TTourSteps>("welcome");
|
const [step, setStep] = useState<TTourSteps>("welcome");
|
||||||
|
|
||||||
const { user: userStore, commandPalette: commandPaletteStore } = useMobxStore();
|
const { user: userStore, commandPalette: commandPaletteStore, trackEvent: {setTrackElement} } = useMobxStore();
|
||||||
const user = userStore.currentUser;
|
const user = userStore.currentUser;
|
||||||
|
|
||||||
const currentStepIndex = TOUR_STEPS.findIndex((tourStep) => tourStep.key === step);
|
const currentStepIndex = TOUR_STEPS.findIndex((tourStep) => tourStep.key === step);
|
||||||
@ -157,6 +157,7 @@ export const TourRoot: React.FC<Props> = observer((props) => {
|
|||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onComplete();
|
onComplete();
|
||||||
|
setTrackElement("ONBOARDING_TOUR")
|
||||||
commandPaletteStore.toggleCreateProjectModal(true);
|
commandPaletteStore.toggleCreateProjectModal(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -19,7 +19,7 @@ export const WorkspaceDashboardView = observer(() => {
|
|||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
// store
|
// store
|
||||||
|
|
||||||
const { user: userStore, project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
|
const { user: userStore, project: projectStore, commandPalette: commandPaletteStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
|
|
||||||
const user = userStore.currentUser;
|
const user = userStore.currentUser;
|
||||||
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : null;
|
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : null;
|
||||||
@ -69,7 +69,11 @@ export const WorkspaceDashboardView = observer(() => {
|
|||||||
<div className="p-5 md:p-8 pr-0">
|
<div className="p-5 md:p-8 pr-0">
|
||||||
<h5 className="text-xl font-semibold">Create a project</h5>
|
<h5 className="text-xl font-semibold">Create a project</h5>
|
||||||
<p className="mt-2 mb-5">Manage your projects by creating issues, cycles, modules, views and pages.</p>
|
<p className="mt-2 mb-5">Manage your projects by creating issues, cycles, modules, views and pages.</p>
|
||||||
<Button variant="primary" size="sm" onClick={() => commandPaletteStore.toggleCreateProjectModal(true)}>
|
<Button variant="primary" size="sm" onClick={() => {
|
||||||
|
setTrackElement("DASHBOARD_PAGE");
|
||||||
|
commandPaletteStore.toggleCreateProjectModal(true)
|
||||||
|
}
|
||||||
|
}>
|
||||||
Create Project
|
Create Project
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,7 +18,7 @@ export interface IProjectCardList {
|
|||||||
export const ProjectCardList: FC<IProjectCardList> = observer((props) => {
|
export const ProjectCardList: FC<IProjectCardList> = observer((props) => {
|
||||||
const { workspaceSlug } = props;
|
const { workspaceSlug } = props;
|
||||||
// store
|
// store
|
||||||
const { project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
|
const { project: projectStore, commandPalette: commandPaletteStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
|
|
||||||
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : null;
|
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : null;
|
||||||
|
|
||||||
@ -57,7 +57,10 @@ export const ProjectCardList: FC<IProjectCardList> = observer((props) => {
|
|||||||
primaryButton={{
|
primaryButton={{
|
||||||
icon: <Plus className="h-4 w-4" />,
|
icon: <Plus className="h-4 w-4" />,
|
||||||
text: "Start something new",
|
text: "Start something new",
|
||||||
onClick: () => commandPaletteStore.toggleCreateProjectModal(true),
|
onClick: () => {
|
||||||
|
setTrackElement("PROJECTS_EMPTY_STATE");
|
||||||
|
commandPaletteStore.toggleCreateProjectModal(true)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -20,8 +20,6 @@ import { getRandomEmoji, renderEmoji } from "helpers/emoji.helper";
|
|||||||
import { IWorkspaceMember } from "types";
|
import { IWorkspaceMember } from "types";
|
||||||
// constants
|
// constants
|
||||||
import { NETWORK_CHOICES, PROJECT_UNSPLASH_COVERS } from "constants/project";
|
import { NETWORK_CHOICES, PROJECT_UNSPLASH_COVERS } from "constants/project";
|
||||||
// track events
|
|
||||||
import { trackEvent } from "helpers/event-tracker.helper";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -68,6 +66,7 @@ export const CreateProjectModal: FC<Props> = observer((props) => {
|
|||||||
const {
|
const {
|
||||||
project: projectStore,
|
project: projectStore,
|
||||||
workspaceMember: { workspaceMembers },
|
workspaceMember: { workspaceMembers },
|
||||||
|
trackEvent: { postHogEventTracker }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
// states
|
// states
|
||||||
const [isChangeInIdentifierRequired, setIsChangeInIdentifierRequired] = useState(true);
|
const [isChangeInIdentifierRequired, setIsChangeInIdentifierRequired] = useState(true);
|
||||||
@ -132,11 +131,11 @@ export const CreateProjectModal: FC<Props> = observer((props) => {
|
|||||||
.createProject(workspaceSlug.toString(), payload)
|
.createProject(workspaceSlug.toString(), payload)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const newPayload = {
|
const newPayload = {
|
||||||
...payload,
|
...res,
|
||||||
id: res.id
|
state: "SUCCESS"
|
||||||
}
|
}
|
||||||
trackEvent(
|
postHogEventTracker(
|
||||||
"CREATE_PROJECT",
|
"PROJECT_CREATE",
|
||||||
newPayload,
|
newPayload,
|
||||||
)
|
)
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -150,12 +149,19 @@ export const CreateProjectModal: FC<Props> = observer((props) => {
|
|||||||
handleClose();
|
handleClose();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
Object.keys(err.data).map((key) =>
|
Object.keys(err.data).map((key) => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "error",
|
type: "error",
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err.data[key],
|
message: err.data[key],
|
||||||
})
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
"PROJECT_CREATE",
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -380,7 +386,7 @@ export const CreateProjectModal: FC<Props> = observer((props) => {
|
|||||||
control={control}
|
control={control}
|
||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<WorkspaceMemberSelect
|
<WorkspaceMemberSelect
|
||||||
value={workspaceMembers?.filter((member: IWorkspaceMember) => member.member.id ===value)[0]}
|
value={workspaceMembers?.filter((member: IWorkspaceMember) => member.member.id === value)[0]}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
options={workspaceMembers || []}
|
options={workspaceMembers || []}
|
||||||
placeholder="Select Lead"
|
placeholder="Select Lead"
|
||||||
|
@ -16,7 +16,6 @@ import { ProjectService } from "services/project";
|
|||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import { trackEvent } from "helpers/event-tracker.helper";
|
|
||||||
|
|
||||||
export interface IProjectDetailsForm {
|
export interface IProjectDetailsForm {
|
||||||
project: IProject;
|
project: IProject;
|
||||||
@ -29,7 +28,7 @@ const projectService = new ProjectService();
|
|||||||
export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
|
export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
|
||||||
const { project, workspaceSlug, isAdmin } = props;
|
const { project, workspaceSlug, isAdmin } = props;
|
||||||
// store
|
// store
|
||||||
const { project: projectStore } = useMobxStore();
|
const { project: projectStore, trackEvent: { postHogEventTracker } } = useMobxStore();
|
||||||
// toast
|
// toast
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
// form data
|
// form data
|
||||||
@ -63,7 +62,10 @@ export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
|
|||||||
return projectStore
|
return projectStore
|
||||||
.updateProject(workspaceSlug.toString(), project.id, payload)
|
.updateProject(workspaceSlug.toString(), project.id, payload)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
trackEvent("UPDATE_PROJECT", res);
|
postHogEventTracker(
|
||||||
|
'PROJECT_UPDATE',
|
||||||
|
{...res, state: "SUCCESS"}
|
||||||
|
);
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
@ -71,7 +73,12 @@ export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
trackEvent("UPDATE_PROJECT/FAIL");
|
postHogEventTracker(
|
||||||
|
'PROJECT_UPDATE',
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
}
|
||||||
|
);
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "error",
|
type: "error",
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
|
@ -37,6 +37,7 @@ export const LeaveProjectModal: FC<ILeaveProjectModal> = observer((props) => {
|
|||||||
// store
|
// store
|
||||||
const {
|
const {
|
||||||
user: { leaveProject },
|
user: { leaveProject },
|
||||||
|
trackEvent: { postHogEventTracker }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
// toast
|
// toast
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
@ -63,6 +64,12 @@ export const LeaveProjectModal: FC<ILeaveProjectModal> = observer((props) => {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
handleClose();
|
handleClose();
|
||||||
router.push(`/${workspaceSlug}/projects`);
|
router.push(`/${workspaceSlug}/projects`);
|
||||||
|
postHogEventTracker(
|
||||||
|
"PROJECT_MEMBER_LEAVE",
|
||||||
|
{
|
||||||
|
state: "SUCCESS"
|
||||||
|
}
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -70,6 +77,12 @@ export const LeaveProjectModal: FC<ILeaveProjectModal> = observer((props) => {
|
|||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Something went wrong please try again later.",
|
message: "Something went wrong please try again later.",
|
||||||
});
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
"PROJECT_MEMBER_LEAVE",
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
|
@ -19,6 +19,7 @@ export const ProjectMemberList: React.FC = observer(() => {
|
|||||||
// store
|
// store
|
||||||
const {
|
const {
|
||||||
projectMember: { projectMembers, fetchProjectMembers },
|
projectMember: { projectMembers, fetchProjectMembers },
|
||||||
|
trackEvent: { setTrackElement }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
// states
|
// states
|
||||||
@ -56,7 +57,12 @@ export const ProjectMemberList: React.FC = observer(() => {
|
|||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button variant="primary" onClick={() => setInviteModal(true)}>
|
<Button variant="primary" onClick={() => {
|
||||||
|
setTrackElement("PROJECT_SETTINGS_MEMBERS_PAGE_HEADER");
|
||||||
|
setInviteModal(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
Add Member
|
Add Member
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,6 +58,7 @@ export const SendProjectInvitationModal: React.FC<Props> = observer((props) => {
|
|||||||
const {
|
const {
|
||||||
user: { currentProjectRole },
|
user: { currentProjectRole },
|
||||||
workspaceMember: { workspaceMembers },
|
workspaceMember: { workspaceMembers },
|
||||||
|
trackEvent: { postHogEventTracker }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -85,18 +86,30 @@ export const SendProjectInvitationModal: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
await projectMemberService
|
await projectMemberService
|
||||||
.bulkAddMembersToProject(workspaceSlug.toString(), projectId.toString(), payload)
|
.bulkAddMembersToProject(workspaceSlug.toString(), projectId.toString(), payload)
|
||||||
.then(() => {
|
.then((res) => {
|
||||||
onSuccess();
|
onSuccess();
|
||||||
onClose();
|
onClose();
|
||||||
trackEvent("PROJECT_MEMBER_INVITE");
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
title: "Success",
|
title: "Success",
|
||||||
type: "success",
|
type: "success",
|
||||||
message: "Member added successfully",
|
message: "Member added successfully",
|
||||||
});
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
'PROJECT_MEMBER_INVITE',
|
||||||
|
{
|
||||||
|
...res,
|
||||||
|
state: "SUCCESS"
|
||||||
|
}
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
postHogEventTracker(
|
||||||
|
'PROJECT_MEMBER_INVITE',
|
||||||
|
{
|
||||||
|
state: "FAILED",
|
||||||
|
}
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
reset(defaultValues);
|
reset(defaultValues);
|
||||||
|
@ -51,8 +51,10 @@ export const ProjectFeaturesList: FC<Props> = observer(() => {
|
|||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
// store
|
// store
|
||||||
const {
|
const {
|
||||||
|
workspace: { currentWorkspace },
|
||||||
project: { currentProjectDetails, updateProject },
|
project: { currentProjectDetails, updateProject },
|
||||||
user: { currentUser, currentProjectRole },
|
user: { currentUser, currentProjectRole },
|
||||||
|
trackEvent: { setTrackElement, postHogEventTracker },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
const isAdmin = currentProjectRole === 20;
|
const isAdmin = currentProjectRole === 20;
|
||||||
// hooks
|
// hooks
|
||||||
@ -87,6 +89,16 @@ export const ProjectFeaturesList: FC<Props> = observer(() => {
|
|||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
value={currentProjectDetails?.[feature.property as keyof IProject]}
|
value={currentProjectDetails?.[feature.property as keyof IProject]}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
|
console.log(currentProjectDetails?.[feature.property as keyof IProject]);
|
||||||
|
setTrackElement("PROJECT_SETTINGS_FEATURES_PAGE");
|
||||||
|
postHogEventTracker(`TOGGLE_${feature.title.toUpperCase()}`, {
|
||||||
|
workspace_id: currentWorkspace?.id,
|
||||||
|
workspace_slug: currentWorkspace?.slug,
|
||||||
|
project_id: currentProjectDetails?.id,
|
||||||
|
project_name: currentProjectDetails?.name,
|
||||||
|
project_identifier: currentProjectDetails?.identifier,
|
||||||
|
enabled: !currentProjectDetails?.[feature.property as keyof IProject]
|
||||||
|
});
|
||||||
handleSubmit({
|
handleSubmit({
|
||||||
[feature.property]: !currentProjectDetails?.[feature.property as keyof IProject],
|
[feature.property]: !currentProjectDetails?.[feature.property as keyof IProject],
|
||||||
});
|
});
|
||||||
|
@ -75,7 +75,7 @@ export const ProjectSidebarListItem: React.FC<Props> = observer((props) => {
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { project, provided, snapshot, handleCopyText, shortContextMenu = false } = props;
|
const { project, provided, snapshot, handleCopyText, shortContextMenu = false } = props;
|
||||||
// store
|
// store
|
||||||
const { project: projectStore, theme: themeStore } = useMobxStore();
|
const { project: projectStore, theme: themeStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
@ -118,6 +118,7 @@ export const ProjectSidebarListItem: React.FC<Props> = observer((props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleLeaveProject = () => {
|
const handleLeaveProject = () => {
|
||||||
|
setTrackElement("APP_SIDEBAR_PROJECT_DROPDOWN");
|
||||||
setLeaveProjectModal(true);
|
setLeaveProjectModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ export const ProjectSidebarList: FC = observer(() => {
|
|||||||
theme: { sidebarCollapsed },
|
theme: { sidebarCollapsed },
|
||||||
project: { joinedProjects, favoriteProjects, orderProjectsWithSortOrder, updateProjectView },
|
project: { joinedProjects, favoriteProjects, orderProjectsWithSortOrder, updateProjectView },
|
||||||
commandPalette: { toggleCreateProjectModal },
|
commandPalette: { toggleCreateProjectModal },
|
||||||
|
trackEvent: { setTrackElement }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -111,9 +112,8 @@ export const ProjectSidebarList: FC = observer(() => {
|
|||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
className={`h-full overflow-y-auto px-4 space-y-2 ${
|
className={`h-full overflow-y-auto px-4 space-y-2 ${isScrolled ? "border-t border-custom-sidebar-border-300" : ""
|
||||||
isScrolled ? "border-t border-custom-sidebar-border-300" : ""
|
}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
<Droppable droppableId="favorite-projects">
|
<Droppable droppableId="favorite-projects">
|
||||||
@ -140,6 +140,7 @@ export const ProjectSidebarList: FC = observer(() => {
|
|||||||
<button
|
<button
|
||||||
className="group-hover:opacity-100 opacity-0"
|
className="group-hover:opacity-100 opacity-0"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
setTrackElement("APP_SIDEBAR_FAVORITES_BLOCK")
|
||||||
setIsFavoriteProjectCreate(true);
|
setIsFavoriteProjectCreate(true);
|
||||||
setIsProjectModalOpen(true);
|
setIsProjectModalOpen(true);
|
||||||
}}
|
}}
|
||||||
@ -262,7 +263,11 @@ export const ProjectSidebarList: FC = observer(() => {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex w-full items-center gap-2 px-3 text-sm text-custom-sidebar-text-200"
|
className="flex w-full items-center gap-2 px-3 text-sm text-custom-sidebar-text-200"
|
||||||
onClick={() => toggleCreateProjectModal(true)}
|
onClick={() => {
|
||||||
|
setTrackElement("APP_SIDEBAR");
|
||||||
|
toggleCreateProjectModal(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Plus className="h-5 w-5" />
|
<Plus className="h-5 w-5" />
|
||||||
{!isCollapsed && "Add Project"}
|
{!isCollapsed && "Add Project"}
|
||||||
|
@ -18,7 +18,7 @@ import type { IState } from "types";
|
|||||||
import { STATES_LIST } from "constants/fetch-keys";
|
import { STATES_LIST } from "constants/fetch-keys";
|
||||||
// constants
|
// constants
|
||||||
import { GROUP_CHOICES } from "constants/project";
|
import { GROUP_CHOICES } from "constants/project";
|
||||||
import { trackEvent } from "helpers/event-tracker.helper";
|
import { stat } from "fs";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
data: IState | null;
|
data: IState | null;
|
||||||
@ -44,7 +44,7 @@ export const CreateUpdateStateInline: React.FC<Props> = observer((props) => {
|
|||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
// store
|
// store
|
||||||
const { projectState: projectStateStore } = useMobxStore();
|
const { projectState: projectStateStore, trackEvent: { postHogEventTracker, setTrackElement } } = useMobxStore();
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
@ -90,15 +90,18 @@ export const CreateUpdateStateInline: React.FC<Props> = observer((props) => {
|
|||||||
.createState(workspaceSlug.toString(), projectId.toString(), formData)
|
.createState(workspaceSlug.toString(), projectId.toString(), formData)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
handleClose();
|
handleClose();
|
||||||
trackEvent(
|
|
||||||
'STATE_CREATE',
|
|
||||||
res
|
|
||||||
)
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "State created successfully.",
|
message: "State created successfully.",
|
||||||
});
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
'STATE_CREATE',
|
||||||
|
{
|
||||||
|
...res,
|
||||||
|
state: "SUCCESS"
|
||||||
|
}
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (error.status === 400)
|
if (error.status === 400)
|
||||||
@ -113,6 +116,12 @@ export const CreateUpdateStateInline: React.FC<Props> = observer((props) => {
|
|||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "State could not be created. Please try again.",
|
message: "State could not be created. Please try again.",
|
||||||
});
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
'STATE_CREATE',
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -124,10 +133,13 @@ export const CreateUpdateStateInline: React.FC<Props> = observer((props) => {
|
|||||||
.then((res) => {
|
.then((res) => {
|
||||||
mutate(STATES_LIST(projectId.toString()));
|
mutate(STATES_LIST(projectId.toString()));
|
||||||
handleClose();
|
handleClose();
|
||||||
trackEvent(
|
postHogEventTracker(
|
||||||
'STATE_UPDATE',
|
'STATE_UPDATE',
|
||||||
res
|
{
|
||||||
)
|
...res,
|
||||||
|
state: "SUCCESS",
|
||||||
|
}
|
||||||
|
);
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
@ -147,6 +159,12 @@ export const CreateUpdateStateInline: React.FC<Props> = observer((props) => {
|
|||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "State could not be updated. Please try again.",
|
message: "State could not be updated. Please try again.",
|
||||||
});
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
'STATE_UPDATE',
|
||||||
|
{
|
||||||
|
state: "FAILED",
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -274,7 +292,10 @@ export const CreateUpdateStateInline: React.FC<Props> = observer((props) => {
|
|||||||
<Button variant="neutral-primary" onClick={handleClose}>
|
<Button variant="neutral-primary" onClick={handleClose}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="primary" type="submit" loading={isSubmitting}>
|
<Button variant="primary" type="submit" loading={isSubmitting} onClick={() => {
|
||||||
|
setTrackElement("PROJECT_SETTINGS_STATE_PAGE");
|
||||||
|
}
|
||||||
|
}>
|
||||||
{isSubmitting ? (data ? "Updating..." : "Creating...") : data ? "Update" : "Create"}
|
{isSubmitting ? (data ? "Updating..." : "Creating...") : data ? "Update" : "Create"}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -13,7 +13,6 @@ import useToast from "hooks/use-toast";
|
|||||||
import { Button } from "@plane/ui";
|
import { Button } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import type { IState } from "types";
|
import type { IState } from "types";
|
||||||
import { trackEvent } from "helpers/event-tracker.helper";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -29,7 +28,7 @@ export const DeleteStateModal: React.FC<Props> = observer((props) => {
|
|||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
// store
|
// store
|
||||||
const { projectState: projectStateStore } = useMobxStore();
|
const { projectState: projectStateStore, trackEvent: { postHogEventTracker } } = useMobxStore();
|
||||||
|
|
||||||
// states
|
// states
|
||||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||||
@ -49,9 +48,12 @@ export const DeleteStateModal: React.FC<Props> = observer((props) => {
|
|||||||
await projectStateStore
|
await projectStateStore
|
||||||
.deleteState(workspaceSlug.toString(), data.project, data.id)
|
.deleteState(workspaceSlug.toString(), data.project, data.id)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
trackEvent(
|
postHogEventTracker(
|
||||||
'STATE_DELETE',
|
'STATE_DELETE',
|
||||||
)
|
{
|
||||||
|
state: "SUCCESS"
|
||||||
|
}
|
||||||
|
);
|
||||||
handleClose();
|
handleClose();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@ -68,6 +70,12 @@ export const DeleteStateModal: React.FC<Props> = observer((props) => {
|
|||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "State could not be deleted. Please try again.",
|
message: "State could not be deleted. Please try again.",
|
||||||
});
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
'STATE_DELETE',
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
setIsDeleteLoading(false);
|
setIsDeleteLoading(false);
|
||||||
|
@ -30,6 +30,7 @@ export const ProjectSettingListItem: React.FC<Props> = observer((props) => {
|
|||||||
// store
|
// store
|
||||||
const {
|
const {
|
||||||
projectState: { markStateAsDefault, moveStatePosition },
|
projectState: { markStateAsDefault, moveStatePosition },
|
||||||
|
trackEvent: { setTrackElement }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
// states
|
// states
|
||||||
@ -107,7 +108,12 @@ export const ProjectSettingListItem: React.FC<Props> = observer((props) => {
|
|||||||
className={`group-hover:opacity-100 opacity-0 ${
|
className={`group-hover:opacity-100 opacity-0 ${
|
||||||
state.default || groupLength === 1 ? "cursor-not-allowed" : ""
|
state.default || groupLength === 1 ? "cursor-not-allowed" : ""
|
||||||
} grid place-items-center`}
|
} grid place-items-center`}
|
||||||
onClick={handleDeleteState}
|
onClick={
|
||||||
|
() => {
|
||||||
|
setTrackElement("PROJECT_SETTINGS_STATE_PAGE");
|
||||||
|
handleDeleteState()
|
||||||
|
}
|
||||||
|
}
|
||||||
disabled={state.default || groupLength === 1}
|
disabled={state.default || groupLength === 1}
|
||||||
>
|
>
|
||||||
{state.default ? (
|
{state.default ? (
|
||||||
|
@ -23,6 +23,7 @@ export const ProjectSettingStateList: React.FC = observer(() => {
|
|||||||
// store
|
// store
|
||||||
const {
|
const {
|
||||||
projectState: { groupedProjectStates, projectStates, fetchProjectStates },
|
projectState: { groupedProjectStates, projectStates, fetchProjectStates },
|
||||||
|
trackEvent: { setTrackElement }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
// state
|
// state
|
||||||
const [activeGroup, setActiveGroup] = useState<StateGroup>(null);
|
const [activeGroup, setActiveGroup] = useState<StateGroup>(null);
|
||||||
@ -58,7 +59,11 @@ export const ProjectSettingStateList: React.FC = observer(() => {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex items-center gap-2 text-custom-primary-100 px-2 hover:text-custom-primary-200 outline-none"
|
className="flex items-center gap-2 text-custom-primary-100 px-2 hover:text-custom-primary-200 outline-none"
|
||||||
onClick={() => setActiveGroup(group as keyof StateGroup)}
|
onClick={() => {
|
||||||
|
setTrackElement("PROJECT_SETTINGS_STATES_PAGE");
|
||||||
|
setActiveGroup(group as keyof StateGroup)
|
||||||
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Plus className="h-4 w-4" />
|
<Plus className="h-4 w-4" />
|
||||||
</button>
|
</button>
|
||||||
|
@ -51,7 +51,7 @@ export const CreateWorkspaceForm: FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { workspace: workspaceStore } = useMobxStore();
|
const { workspace: workspaceStore, trackEvent: { postHogEventTracker } } = useMobxStore();
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
@ -73,15 +73,12 @@ export const CreateWorkspaceForm: FC<Props> = observer((props) => {
|
|||||||
await workspaceStore
|
await workspaceStore
|
||||||
.createWorkspace(formData)
|
.createWorkspace(formData)
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
const payload = {
|
postHogEventTracker(
|
||||||
name: formData.name,
|
"WORKSPACE_CREATE",
|
||||||
slug: formData.slug,
|
{
|
||||||
workspace_url: formData.url,
|
...res,
|
||||||
organization_size: formData.organization_size
|
state: "SUCCESS"
|
||||||
};
|
},
|
||||||
trackEvent(
|
|
||||||
"CREATE_WORKSPACE",
|
|
||||||
payload
|
|
||||||
)
|
)
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
@ -92,11 +89,19 @@ export const CreateWorkspaceForm: FC<Props> = observer((props) => {
|
|||||||
if (onSubmit) await onSubmit(res);
|
if (onSubmit) await onSubmit(res);
|
||||||
})
|
})
|
||||||
.catch(() =>
|
.catch(() =>
|
||||||
|
{
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "error",
|
type: "error",
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Workspace could not be created. Please try again.",
|
message: "Workspace could not be created. Please try again.",
|
||||||
})
|
})
|
||||||
|
postHogEventTracker(
|
||||||
|
"WORKSPACE_CREATE",
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
);
|
);
|
||||||
} else setSlugError(true);
|
} else setSlugError(true);
|
||||||
})
|
})
|
||||||
@ -106,6 +111,12 @@ export const CreateWorkspaceForm: FC<Props> = observer((props) => {
|
|||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Some error occurred while creating workspace. Please try again.",
|
message: "Some error occurred while creating workspace. Please try again.",
|
||||||
});
|
});
|
||||||
|
postHogEventTracker(
|
||||||
|
"WORKSPACE_CREATE",
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
},
|
||||||
|
)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ import useToast from "hooks/use-toast";
|
|||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import type { IWorkspace } from "types";
|
import type { IWorkspace } from "types";
|
||||||
import { trackEvent } from "helpers/event-tracker.helper";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -30,7 +29,7 @@ export const DeleteWorkspaceModal: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { workspace: workspaceStore } = useMobxStore();
|
const { workspace: workspaceStore, trackEvent: { postHogEventTracker } } = useMobxStore();
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
@ -60,14 +59,16 @@ export const DeleteWorkspaceModal: React.FC<Props> = observer((props) => {
|
|||||||
.deleteWorkspace(data.slug)
|
.deleteWorkspace(data.slug)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
handleClose();
|
handleClose();
|
||||||
console.log('DELETE WORKPSACE', res);
|
|
||||||
router.push("/");
|
router.push("/");
|
||||||
const payload = {
|
const payload = {
|
||||||
slug: data.slug
|
slug: data.slug
|
||||||
};
|
};
|
||||||
trackEvent(
|
postHogEventTracker(
|
||||||
'DELETE_WORKSPACE',
|
'WORKSPACE_DELETE',
|
||||||
payload
|
{
|
||||||
|
res,
|
||||||
|
state: "SUCCESS"
|
||||||
|
}
|
||||||
);
|
);
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
@ -76,11 +77,19 @@ export const DeleteWorkspaceModal: React.FC<Props> = observer((props) => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() =>
|
.catch(() =>
|
||||||
|
{
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "error",
|
type: "error",
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Something went wrong. Please try again later.",
|
message: "Something went wrong. Please try again later.",
|
||||||
})
|
})
|
||||||
|
postHogEventTracker(
|
||||||
|
'WORKSPACE_DELETE',
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ export const WorkspaceDetails: FC = observer(() => {
|
|||||||
const {
|
const {
|
||||||
workspace: { currentWorkspace, updateWorkspace },
|
workspace: { currentWorkspace, updateWorkspace },
|
||||||
user: { currentWorkspaceRole },
|
user: { currentWorkspaceRole },
|
||||||
|
trackEvent: { postHogEventTracker }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
const isAdmin = currentWorkspaceRole === 20;
|
const isAdmin = currentWorkspaceRole === 20;
|
||||||
// hooks
|
// hooks
|
||||||
@ -66,14 +67,28 @@ export const WorkspaceDetails: FC = observer(() => {
|
|||||||
|
|
||||||
await updateWorkspace(currentWorkspace.slug, payload)
|
await updateWorkspace(currentWorkspace.slug, payload)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
trackEvent("UPDATE_WORKSPACE", res);
|
postHogEventTracker(
|
||||||
|
'WORKSPACE_UPDATE',
|
||||||
|
{
|
||||||
|
...res,
|
||||||
|
state: "SUCCESS"
|
||||||
|
}
|
||||||
|
)
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
title: "Success",
|
title: "Success",
|
||||||
type: "success",
|
type: "success",
|
||||||
message: "Workspace updated successfully",
|
message: "Workspace updated successfully",
|
||||||
});
|
});
|
||||||
})
|
}).catch((err) => {
|
||||||
.catch((err) => console.error(err));
|
postHogEventTracker(
|
||||||
|
'WORKSPACE_UPDATE',
|
||||||
|
{
|
||||||
|
state: "FAILED"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveLogo = () => {
|
const handleRemoveLogo = () => {
|
||||||
@ -262,10 +277,9 @@ export const WorkspaceDetails: FC = observer(() => {
|
|||||||
id="url"
|
id="url"
|
||||||
name="url"
|
name="url"
|
||||||
type="url"
|
type="url"
|
||||||
value={`${
|
value={`${typeof window !== "undefined" &&
|
||||||
typeof window !== "undefined" &&
|
|
||||||
window.location.origin.replace("http://", "").replace("https://", "")
|
window.location.origin.replace("http://", "").replace("https://", "")
|
||||||
}/${currentWorkspace.slug}`}
|
}/${currentWorkspace.slug}`}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
hasError={Boolean(errors.url)}
|
hasError={Boolean(errors.url)}
|
||||||
|
@ -56,6 +56,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
theme: { sidebarCollapsed },
|
theme: { sidebarCollapsed },
|
||||||
workspace: { workspaces, currentWorkspace: activeWorkspace },
|
workspace: { workspaces, currentWorkspace: activeWorkspace },
|
||||||
user: { currentUser, updateCurrentUser, isUserInstanceAdmin },
|
user: { currentUser, updateCurrentUser, isUserInstanceAdmin },
|
||||||
|
trackEvent: { setTrackElement }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
// hooks
|
// hooks
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
@ -203,6 +204,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
as="button"
|
as="button"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
setTrackElement("APP_SIEDEBAR_WORKSPACE_DROPDOWN");
|
||||||
router.push("/create-workspace");
|
router.push("/create-workspace");
|
||||||
}}
|
}}
|
||||||
className="flex w-full items-center gap-2 px-2 py-1 text-sm text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80"
|
className="flex w-full items-center gap-2 px-2 py-1 text-sm text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80"
|
||||||
|
@ -14,7 +14,7 @@ export const WorkspaceSidebarQuickAction = observer(() => {
|
|||||||
// states
|
// states
|
||||||
const [isDraftIssueModalOpen, setIsDraftIssueModalOpen] = useState(false);
|
const [isDraftIssueModalOpen, setIsDraftIssueModalOpen] = useState(false);
|
||||||
|
|
||||||
const { theme: themeStore, commandPalette: commandPaletteStore } = useMobxStore();
|
const { theme: themeStore, commandPalette: commandPaletteStore, trackEvent: { setTrackElement } } = useMobxStore();
|
||||||
|
|
||||||
const { storedValue, clearValue } = useLocalStorage<any>("draftedIssue", JSON.stringify({}));
|
const { storedValue, clearValue } = useLocalStorage<any>("draftedIssue", JSON.stringify({}));
|
||||||
|
|
||||||
@ -34,23 +34,24 @@ export const WorkspaceSidebarQuickAction = observer(() => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`flex items-center justify-between w-full cursor-pointer px-4 mt-4 ${
|
className={`flex items-center justify-between w-full cursor-pointer px-4 mt-4 ${isSidebarCollapsed ? "flex-col gap-1" : "gap-2"
|
||||||
isSidebarCollapsed ? "flex-col gap-1" : "gap-2"
|
}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`relative flex items-center justify-between w-full rounded cursor-pointer px-2 gap-1 group ${
|
className={`relative flex items-center justify-between w-full rounded cursor-pointer px-2 gap-1 group ${isSidebarCollapsed
|
||||||
isSidebarCollapsed
|
? "px-2 hover:bg-custom-sidebar-background-80"
|
||||||
? "px-2 hover:bg-custom-sidebar-background-80"
|
: "px-3 shadow-custom-sidebar-shadow-2xs border-[0.5px] border-custom-border-200"
|
||||||
: "px-3 shadow-custom-sidebar-shadow-2xs border-[0.5px] border-custom-border-200"
|
}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`relative flex items-center gap-2 flex-grow rounded flex-shrink-0 py-1.5 outline-none ${
|
className={`relative flex items-center gap-2 flex-grow rounded flex-shrink-0 py-1.5 outline-none ${isSidebarCollapsed ? "justify-center" : ""
|
||||||
isSidebarCollapsed ? "justify-center" : ""
|
}`}
|
||||||
}`}
|
onClick={() => {
|
||||||
onClick={() => commandPaletteStore.toggleCreateIssueModal(true)}
|
setTrackElement("APP_SIDEBAR_QUICK_ACTIONS");
|
||||||
|
commandPaletteStore.toggleCreateIssueModal(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<PenSquare className="h-4 w-4 text-custom-sidebar-text-300" />
|
<PenSquare className="h-4 w-4 text-custom-sidebar-text-300" />
|
||||||
{!isSidebarCollapsed && <span className="text-sm font-medium">New Issue</span>}
|
{!isSidebarCollapsed && <span className="text-sm font-medium">New Issue</span>}
|
||||||
@ -62,9 +63,8 @@ export const WorkspaceSidebarQuickAction = observer(() => {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`flex items-center justify-center rounded flex-shrink-0 py-1.5 ml-1.5 ${
|
className={`flex items-center justify-center rounded flex-shrink-0 py-1.5 ml-1.5 ${isSidebarCollapsed ? "hidden" : "block"
|
||||||
isSidebarCollapsed ? "hidden" : "block"
|
}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<ChevronDown
|
<ChevronDown
|
||||||
size={16}
|
size={16}
|
||||||
@ -73,9 +73,8 @@ export const WorkspaceSidebarQuickAction = observer(() => {
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`fixed h-10 pt-2 w-[203px] left-4 opacity-0 group-hover:opacity-100 mt-0 pointer-events-none group-hover:pointer-events-auto ${
|
className={`fixed h-10 pt-2 w-[203px] left-4 opacity-0 group-hover:opacity-100 mt-0 pointer-events-none group-hover:pointer-events-auto ${isSidebarCollapsed ? "top-[5.5rem]" : "top-24"
|
||||||
isSidebarCollapsed ? "top-[5.5rem]" : "top-24"
|
}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<div className="w-full h-full">
|
<div className="w-full h-full">
|
||||||
<button
|
<button
|
||||||
@ -92,11 +91,10 @@ export const WorkspaceSidebarQuickAction = observer(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
className={`flex items-center justify-center rounded flex-shrink-0 p-2 outline-none ${
|
className={`flex items-center justify-center rounded flex-shrink-0 p-2 outline-none ${isSidebarCollapsed
|
||||||
isSidebarCollapsed
|
? "hover:bg-custom-sidebar-background-80"
|
||||||
? "hover:bg-custom-sidebar-background-80"
|
: "shadow-custom-sidebar-shadow-2xs border-[0.5px] border-custom-border-200"
|
||||||
: "shadow-custom-sidebar-shadow-2xs border-[0.5px] border-custom-border-200"
|
}`}
|
||||||
}`}
|
|
||||||
onClick={() => commandPaletteStore.toggleCommandPaletteModal(true)}
|
onClick={() => commandPaletteStore.toggleCommandPaletteModal(true)}
|
||||||
>
|
>
|
||||||
<Search className="h-4 w-4 text-custom-sidebar-text-300" />
|
<Search className="h-4 w-4 text-custom-sidebar-text-300" />
|
||||||
|
@ -23,6 +23,7 @@ const AnalyticsPage: NextPageWithLayout = observer(() => {
|
|||||||
const {
|
const {
|
||||||
project: { workspaceProjects },
|
project: { workspaceProjects },
|
||||||
commandPalette: { toggleCreateProjectModal },
|
commandPalette: { toggleCreateProjectModal },
|
||||||
|
trackEvent: { setTrackElement }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -35,11 +36,10 @@ const AnalyticsPage: NextPageWithLayout = observer(() => {
|
|||||||
<Tab
|
<Tab
|
||||||
key={tab.key}
|
key={tab.key}
|
||||||
className={({ selected }) =>
|
className={({ selected }) =>
|
||||||
`rounded-3xl border border-custom-border-200 px-4 py-2 text-xs hover:bg-custom-background-80 ${
|
`rounded-3xl border border-custom-border-200 px-4 py-2 text-xs hover:bg-custom-background-80 ${selected ? "bg-custom-background-80" : ""
|
||||||
selected ? "bg-custom-background-80" : ""
|
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
onClick={() => {}}
|
onClick={() => { }}
|
||||||
>
|
>
|
||||||
{tab.title}
|
{tab.title}
|
||||||
</Tab>
|
</Tab>
|
||||||
@ -64,7 +64,10 @@ const AnalyticsPage: NextPageWithLayout = observer(() => {
|
|||||||
primaryButton={{
|
primaryButton={{
|
||||||
icon: <Plus className="h-4 w-4" />,
|
icon: <Plus className="h-4 w-4" />,
|
||||||
text: "New Project",
|
text: "New Project",
|
||||||
onClick: () => toggleCreateProjectModal(true),
|
onClick: () => {
|
||||||
|
setTrackElement("ANALYTICS_EMPTY_STATE");
|
||||||
|
toggleCreateProjectModal(true)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -26,6 +26,7 @@ const WorkspaceMembersSettingsPage: NextPageWithLayout = observer(() => {
|
|||||||
// store
|
// store
|
||||||
const {
|
const {
|
||||||
workspaceMember: { inviteMembersToWorkspace },
|
workspaceMember: { inviteMembersToWorkspace },
|
||||||
|
trackEvent: { postHogEventTracker, setTrackElement }
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
// states
|
// states
|
||||||
const [inviteModal, setInviteModal] = useState(false);
|
const [inviteModal, setInviteModal] = useState(false);
|
||||||
@ -37,9 +38,9 @@ const WorkspaceMembersSettingsPage: NextPageWithLayout = observer(() => {
|
|||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
|
|
||||||
return inviteMembersToWorkspace(workspaceSlug.toString(), data)
|
return inviteMembersToWorkspace(workspaceSlug.toString(), data)
|
||||||
.then(async () => {
|
.then(async (res) => {
|
||||||
setInviteModal(false);
|
setInviteModal(false);
|
||||||
trackEvent("WORKSPACE_USER_INVITE");
|
postHogEventTracker("WORKSPACE_USER_INVITE", { ...res, state: "SUCCESS" });
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
@ -47,7 +48,7 @@ const WorkspaceMembersSettingsPage: NextPageWithLayout = observer(() => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
trackEvent("WORKSPACE_USER_INVITE/FAIL");
|
postHogEventTracker("WORKSPACE_USER_INVITE", { state: "FAILED" });
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "error",
|
type: "error",
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
@ -78,7 +79,11 @@ const WorkspaceMembersSettingsPage: NextPageWithLayout = observer(() => {
|
|||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button variant="primary" size="sm" onClick={() => setInviteModal(true)}>
|
<Button variant="primary" size="sm" onClick={() => {
|
||||||
|
setTrackElement("WORKSPACE_SETTINGS_MEMBERS_PAGE_HEADER");
|
||||||
|
setInviteModal(true)
|
||||||
|
}
|
||||||
|
}>
|
||||||
Add Member
|
Add Member
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
80
web/store/event-tracker.store.ts
Normal file
80
web/store/event-tracker.store.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { action, makeObservable, observable } from "mobx";
|
||||||
|
import posthog from "posthog-js";
|
||||||
|
import { RootStore } from "./root";
|
||||||
|
|
||||||
|
export interface ITrackEventStore {
|
||||||
|
trackElement: string;
|
||||||
|
setTrackElement: (element: string) => void;
|
||||||
|
postHogEventTracker: (
|
||||||
|
eventName: string,
|
||||||
|
payload: object | [] | null
|
||||||
|
// group: { isGrouping: boolean; groupType: string; gorupId: string } | null
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TrackEventStore implements ITrackEventStore {
|
||||||
|
trackElement: string = "";
|
||||||
|
rootStore;
|
||||||
|
constructor(_rootStore: RootStore) {
|
||||||
|
makeObservable(this, {
|
||||||
|
trackElement: observable,
|
||||||
|
setTrackElement: action,
|
||||||
|
postHogEventTracker: action,
|
||||||
|
});
|
||||||
|
this.rootStore = _rootStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTrackElement = (element: string) => {
|
||||||
|
this.trackElement = element;
|
||||||
|
};
|
||||||
|
|
||||||
|
postHogEventTracker = (
|
||||||
|
eventName: string,
|
||||||
|
payload: object | [] | null
|
||||||
|
// group: { isGrouping: boolean; groupType: string; gorupId: string } | null
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
console.log("POSTHOG_EVENT: ", eventName);
|
||||||
|
let extras: any = {
|
||||||
|
workspace_name: this.rootStore.workspace.currentWorkspace?.name ?? "",
|
||||||
|
workspace_id: this.rootStore.workspace.currentWorkspace?.id ?? "",
|
||||||
|
workspace_slug: this.rootStore.workspace.currentWorkspace?.slug ?? "",
|
||||||
|
project_name: this.rootStore.project.currentProjectDetails?.name ?? "",
|
||||||
|
project_id: this.rootStore.project.currentProjectDetails?.id ?? "",
|
||||||
|
project_identifier: this.rootStore.project.currentProjectDetails?.identifier ?? "",
|
||||||
|
};
|
||||||
|
if (["PROJECT_CREATE", "PROJECT_UPDATE"].includes(eventName)) {
|
||||||
|
const project_details: any = payload as object;
|
||||||
|
extras = {
|
||||||
|
...extras,
|
||||||
|
project_name: project_details?.name ?? "",
|
||||||
|
project_id: project_details?.id ?? "",
|
||||||
|
project_identifier: project_details?.identifier ?? "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (group!.isGrouping === true) {
|
||||||
|
// posthog?.group(group!.groupType, group!.gorupId, {
|
||||||
|
// name: "PostHog",
|
||||||
|
// subscription: "subscription",
|
||||||
|
// date_joined: "2020-01-23T00:00:00.000Z",
|
||||||
|
// });
|
||||||
|
// console.log("END OF GROUPING");
|
||||||
|
// posthog?.capture(eventName, {
|
||||||
|
// ...payload,
|
||||||
|
// element: this.trackElement ?? "",
|
||||||
|
// });
|
||||||
|
// } else {
|
||||||
|
posthog?.capture(eventName, {
|
||||||
|
...payload,
|
||||||
|
extras: extras,
|
||||||
|
element: this.trackElement ?? "",
|
||||||
|
});
|
||||||
|
// }
|
||||||
|
console.log(payload);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
this.setTrackElement("");
|
||||||
|
};
|
||||||
|
}
|
@ -160,6 +160,8 @@ import { ModuleIssueFiltersStore, IModuleIssueFiltersStore } from "store/module-
|
|||||||
import { IMentionsStore, MentionsStore } from "store/editor";
|
import { IMentionsStore, MentionsStore } from "store/editor";
|
||||||
// pages
|
// pages
|
||||||
import { PageStore, IPageStore } from "store/page.store";
|
import { PageStore, IPageStore } from "store/page.store";
|
||||||
|
// event tracking
|
||||||
|
import { TrackEventStore, ITrackEventStore } from "./event-tracker.store";
|
||||||
|
|
||||||
enableStaticRendering(typeof window === "undefined");
|
enableStaticRendering(typeof window === "undefined");
|
||||||
|
|
||||||
@ -261,6 +263,8 @@ export class RootStore {
|
|||||||
|
|
||||||
page: IPageStore;
|
page: IPageStore;
|
||||||
|
|
||||||
|
trackEvent: ITrackEventStore;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.instance = new InstanceStore(this);
|
this.instance = new InstanceStore(this);
|
||||||
|
|
||||||
@ -357,5 +361,7 @@ export class RootStore {
|
|||||||
this.moduleIssueFilters = new ModuleIssueFiltersStore(this);
|
this.moduleIssueFilters = new ModuleIssueFiltersStore(this);
|
||||||
|
|
||||||
this.page = new PageStore(this);
|
this.page = new PageStore(this);
|
||||||
|
|
||||||
|
this.trackEvent = new TrackEventStore(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user