mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: updated project-pages related events
This commit is contained in:
parent
dd54f6bd77
commit
fc5901d2d6
@ -11,7 +11,7 @@ import { Button, Input } from "@plane/ui";
|
||||
import { checkEmailValidity } from "helpers/string.helper";
|
||||
// constants
|
||||
import { ESignUpSteps } from "components/account";
|
||||
import { PASSWORD_CREATE_SELECTED, PASSWORD_CREATE_SKIPPED, SETUP_PASSWORD } from "constants/event-tracker";
|
||||
import { PASSWORD_CREATE_SKIPPED, SETUP_PASSWORD } from "constants/event-tracker";
|
||||
// icons
|
||||
import { Eye, EyeOff } from "lucide-react";
|
||||
|
||||
|
@ -17,7 +17,9 @@ type Props = {
|
||||
isOpen: boolean;
|
||||
projectId: string;
|
||||
handleClose: () => void;
|
||||
onResponse: (response: any) => void;
|
||||
onResponse: (question: string, response: any) => void;
|
||||
onGenerateResponse?: (question: string, response: any) => void;
|
||||
onReGenerateResponse?: (question: string, response: any) => void;
|
||||
onError?: (error: any) => void;
|
||||
placement?: Placement;
|
||||
prompt?: string;
|
||||
@ -33,7 +35,19 @@ type FormData = {
|
||||
const aiService = new AIService();
|
||||
|
||||
export const GptAssistantPopover: React.FC<Props> = (props) => {
|
||||
const { isOpen, projectId, handleClose, onResponse, onError, placement, prompt, button, className = "" } = props;
|
||||
const {
|
||||
isOpen,
|
||||
projectId,
|
||||
handleClose,
|
||||
onResponse,
|
||||
onGenerateResponse,
|
||||
onReGenerateResponse,
|
||||
onError,
|
||||
placement,
|
||||
prompt,
|
||||
button,
|
||||
className = "",
|
||||
} = props;
|
||||
// states
|
||||
const [response, setResponse] = useState("");
|
||||
const [invalidResponse, setInvalidResponse] = useState(false);
|
||||
@ -55,6 +69,7 @@ export const GptAssistantPopover: React.FC<Props> = (props) => {
|
||||
handleSubmit,
|
||||
control,
|
||||
reset,
|
||||
getValues,
|
||||
setFocus,
|
||||
formState: { isSubmitting },
|
||||
} = useForm<FormData>({
|
||||
@ -120,6 +135,8 @@ export const GptAssistantPopover: React.FC<Props> = (props) => {
|
||||
}
|
||||
|
||||
await callAIService(formData);
|
||||
if (response !== "" && onReGenerateResponse) onReGenerateResponse(formData.task, response);
|
||||
else if (response === "" && onGenerateResponse) onGenerateResponse(formData.task, response);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -164,7 +181,7 @@ export const GptAssistantPopover: React.FC<Props> = (props) => {
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
onResponse(response);
|
||||
onResponse(getValues("task"), response);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FC, useEffect, useState, useRef, use } from "react";
|
||||
import { FC, useEffect, useState, useRef } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { Avatar, PriorityIcon, StateGroupIcon } from "@plane/ui";
|
||||
import { EIssueListRow, ISSUE_PRIORITIES } from "constants/issue";
|
||||
import { ISSUE_PRIORITIES } from "constants/issue";
|
||||
import { renderEmoji } from "helpers/emoji.helper";
|
||||
import { IMemberRootStore } from "store/member";
|
||||
import { IProjectStore } from "store/project/project.store";
|
||||
import { IStateStore } from "store/state.store";
|
||||
import { GroupByColumnTypes, IGroupByColumn, IIssueListRow, TGroupedIssues, TUnGroupedIssues } from "@plane/types";
|
||||
import { GroupByColumnTypes, IGroupByColumn } from "@plane/types";
|
||||
import { STATE_GROUPS } from "constants/state";
|
||||
import { ILabelStore } from "store/label.store";
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { FC, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import {
|
||||
AlertCircle,
|
||||
@ -13,18 +14,21 @@ import {
|
||||
Star,
|
||||
Trash2,
|
||||
} from "lucide-react";
|
||||
// hooks
|
||||
import { useProjectPages } from "hooks/store/use-project-specific-pages";
|
||||
import { useEventTracker, useMember, usePage, useUser } from "hooks/store";
|
||||
// helpers
|
||||
import { copyUrlToClipboard } from "helpers/string.helper";
|
||||
import { renderFormattedTime, renderFormattedDate } from "helpers/date-time.helper";
|
||||
// ui
|
||||
import { CustomMenu, Tooltip } from "@plane/ui";
|
||||
// components
|
||||
import { CreateUpdatePageModal, DeletePageModal } from "components/pages";
|
||||
// types
|
||||
import { IIssueLabel } from "@plane/types";
|
||||
// constants
|
||||
import { EUserProjectRoles } from "constants/project";
|
||||
import { useRouter } from "next/router";
|
||||
import { useProjectPages } from "hooks/store/use-project-specific-pages";
|
||||
import { useMember, usePage, useUser } from "hooks/store";
|
||||
import { IIssueLabel } from "@plane/types";
|
||||
import { PAGE_ARCHIVED, PAGE_FAVORITED, PAGE_RESTORED, PAGE_UNFAVORITED, PAGE_UPDATED } from "constants/event-tracker";
|
||||
|
||||
export interface IPagesListItem {
|
||||
pageId: string;
|
||||
@ -38,21 +42,21 @@ export const PagesListItem: FC<IPagesListItem> = observer(({ pageId, projectId }
|
||||
|
||||
const pageStore = usePage(pageId);
|
||||
|
||||
// states
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
// states
|
||||
const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false);
|
||||
|
||||
const [deletePageModal, setDeletePageModal] = useState(false);
|
||||
|
||||
// store hooks
|
||||
const {
|
||||
currentUser,
|
||||
membership: { currentProjectRole },
|
||||
} = useUser();
|
||||
|
||||
const {
|
||||
project: { getProjectMemberDetails },
|
||||
} = useMember();
|
||||
const { captureEvent } = useEventTracker();
|
||||
|
||||
if (!pageStore) return null;
|
||||
|
||||
@ -81,42 +85,81 @@ export const PagesListItem: FC<IPagesListItem> = observer(({ pageId, projectId }
|
||||
const handleAddToFavorites = (e: React.MouseEvent<HTMLElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
addToFavorites();
|
||||
addToFavorites().then(() => {
|
||||
captureEvent(PAGE_FAVORITED, {
|
||||
page_id: pageId,
|
||||
element: "Project pages page",
|
||||
state: "SUCCESS",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleRemoveFromFavorites = (e: React.MouseEvent<HTMLElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
removeFromFavorites();
|
||||
removeFromFavorites().then(() => {
|
||||
captureEvent(PAGE_UNFAVORITED, {
|
||||
page_id: pageId,
|
||||
state: "SUCCESS",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleMakePublic = (e: React.MouseEvent<HTMLElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
makePublic();
|
||||
makePublic().then(() => {
|
||||
captureEvent(PAGE_UPDATED, {
|
||||
page_id: pageId,
|
||||
access: "public",
|
||||
element: "Project pages page",
|
||||
state: "SUCCESS",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleMakePrivate = (e: React.MouseEvent<HTMLElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
makePrivate();
|
||||
makePrivate().then(() => {
|
||||
captureEvent(PAGE_UPDATED, {
|
||||
page_id: pageId,
|
||||
access: "private",
|
||||
element: "Project pages page",
|
||||
state: "SUCCESS",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleArchivePage = async (e: React.MouseEvent<HTMLElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
await archivePage(workspaceSlug as string, projectId as string, pageId as string);
|
||||
await archivePage(workspaceSlug as string, projectId as string, pageId as string).then(() => {
|
||||
captureEvent(PAGE_ARCHIVED, {
|
||||
page_id: pageId,
|
||||
access: access == 1 ? "private" : "public",
|
||||
element: "Project pages page",
|
||||
state: "SUCCESS",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleRestorePage = async (e: React.MouseEvent<HTMLElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
await restorePage(workspaceSlug as string, projectId as string, pageId as string);
|
||||
await restorePage(workspaceSlug as string, projectId as string, pageId as string).then(() => {
|
||||
captureEvent(PAGE_RESTORED, {
|
||||
page_id: pageId,
|
||||
access: access == 1 ? "private" : "public",
|
||||
element: "Project pages page",
|
||||
state: "SUCCESS",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleDeletePage = (e: React.MouseEvent<HTMLElement>) => {
|
||||
|
@ -58,7 +58,7 @@ export const DeleteWorkspaceModal: React.FC<Props> = observer((props) => {
|
||||
if (!data || !canDelete) return;
|
||||
|
||||
await deleteWorkspace(data.slug)
|
||||
.then((res) => {
|
||||
.then(() => {
|
||||
handleClose();
|
||||
router.push("/");
|
||||
captureWorkspaceEvent({
|
||||
|
@ -56,7 +56,6 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
||||
const {
|
||||
theme: { sidebarCollapsed, toggleMobileSidebar },
|
||||
} = useApplication();
|
||||
const { setTrackElement } = useEventTracker();
|
||||
const { currentUser, updateCurrentUser, isUserInstanceAdmin, signOut } = useUser();
|
||||
const { currentWorkspace: activeWorkspace, workspaces } = useWorkspace();
|
||||
// hooks
|
||||
|
@ -66,7 +66,7 @@ export const GlobalViewsHeader: React.FC = observer(() => {
|
||||
const activeTabElement = document.querySelector(`#global-view-${globalViewId.toString()}`);
|
||||
|
||||
if (activeTabElement) activeTabElement.scrollIntoView({ behavior: "smooth", inline: "center" });
|
||||
}, [globalViewId]);
|
||||
}, [globalViewId, captureEvent]);
|
||||
|
||||
const isAuthorizedUser = !!currentWorkspaceRole && currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER;
|
||||
|
||||
|
@ -184,6 +184,17 @@ export const STATE_DELETED = "State deleted";
|
||||
export const PAGE_CREATED = "Page created";
|
||||
export const PAGE_UPDATED = "Page updated";
|
||||
export const PAGE_DELETED = "Page deleted";
|
||||
export const PAGE_FAVORITED = "Page favorited";
|
||||
export const PAGE_UNFAVORITED = "Page unfavorited";
|
||||
export const PAGE_ARCHIVED = "Page archived";
|
||||
export const PAGE_LOCKED = "Page locked";
|
||||
export const PAGE_UNLOCKED = "Page unlocked";
|
||||
export const PAGE_DUPLICATED = "Page duplicated";
|
||||
export const PAGE_RESTORED = "Page restored";
|
||||
// AI Assistant Events
|
||||
export const AI_TRIGGERED = "AI triggered";
|
||||
export const AI_RES_USED = "AI response used";
|
||||
export const AI_RES_REGENERATED = "AI response regenerated";
|
||||
// Member Events
|
||||
export const MEMBER_INVITED = "Member invited";
|
||||
export const MEMBER_ACCEPTED = "Member accepted";
|
||||
|
@ -6,7 +6,7 @@ import { ReactElement, useEffect, useRef, useState } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// hooks
|
||||
|
||||
import { useApplication, usePage, useUser, useWorkspace } from "hooks/store";
|
||||
import { useApplication, useEventTracker, usePage, useUser, useWorkspace } from "hooks/store";
|
||||
import useReloadConfirmations from "hooks/use-reload-confirmation";
|
||||
import useToast from "hooks/use-toast";
|
||||
// services
|
||||
@ -29,6 +29,16 @@ import { NextPageWithLayout } from "lib/types";
|
||||
import { EUserProjectRoles } from "constants/project";
|
||||
import { useProjectPages } from "hooks/store/use-project-specific-pages";
|
||||
import { IssuePeekOverview } from "components/issues";
|
||||
import {
|
||||
AI_RES_REGENERATED,
|
||||
AI_RES_USED,
|
||||
AI_TRIGGERED,
|
||||
PAGE_ARCHIVED,
|
||||
PAGE_DUPLICATED,
|
||||
PAGE_LOCKED,
|
||||
PAGE_RESTORED,
|
||||
PAGE_UNLOCKED,
|
||||
} from "constants/event-tracker";
|
||||
|
||||
// services
|
||||
const fileService = new FileService();
|
||||
@ -53,6 +63,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
||||
currentUser,
|
||||
membership: { currentProjectRole },
|
||||
} = useUser();
|
||||
const { captureEvent } = useEventTracker();
|
||||
// toast alert
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
@ -115,6 +126,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
||||
updateDescription: updateDescriptionAction,
|
||||
id: pageIdMobx,
|
||||
isSubmitting,
|
||||
access,
|
||||
setIsSubmitting,
|
||||
owned_by,
|
||||
is_locked,
|
||||
@ -130,13 +142,19 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
||||
await updateDescriptionAction(formData.description_html);
|
||||
};
|
||||
|
||||
const handleAiAssistance = async (response: string) => {
|
||||
const handleAiAssistance = async (question: string, response: string) => {
|
||||
if (!workspaceSlug || !projectId || !pageId) return;
|
||||
|
||||
const newDescription = `${watch("description_html")}<p>${response}</p>`;
|
||||
setValue("description_html", newDescription);
|
||||
editorRef.current?.setEditorValue(newDescription);
|
||||
updateDescriptionAction(newDescription);
|
||||
captureEvent(AI_RES_USED, {
|
||||
page_id: pageId,
|
||||
element: "Pages detail page",
|
||||
question: question,
|
||||
answer: response,
|
||||
});
|
||||
};
|
||||
|
||||
const actionCompleteAlert = ({
|
||||
@ -180,7 +198,14 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
||||
};
|
||||
|
||||
try {
|
||||
await createPage(formData);
|
||||
await createPage(formData).then(() => {
|
||||
captureEvent(PAGE_DUPLICATED, {
|
||||
page_id: pageId,
|
||||
access: access == 1 ? "private" : "public",
|
||||
element: "Pages detail page",
|
||||
state: "SUCCESS",
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
actionCompleteAlert({
|
||||
title: `Page could not be duplicated`,
|
||||
@ -193,7 +218,14 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
||||
const archivePage = async () => {
|
||||
if (!workspaceSlug || !projectId || !pageId) return;
|
||||
try {
|
||||
await archivePageAction(workspaceSlug as string, projectId as string, pageId as string);
|
||||
await archivePageAction(workspaceSlug as string, projectId as string, pageId as string).then(() => {
|
||||
captureEvent(PAGE_ARCHIVED, {
|
||||
page_id: pageId,
|
||||
access: access == 1 ? "private" : "public",
|
||||
element: "Pages detail page",
|
||||
state: "SUCCESS",
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
actionCompleteAlert({
|
||||
title: `Page could not be archived`,
|
||||
@ -206,7 +238,14 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
||||
const unArchivePage = async () => {
|
||||
if (!workspaceSlug || !projectId || !pageId) return;
|
||||
try {
|
||||
await restorePageAction(workspaceSlug as string, projectId as string, pageId as string);
|
||||
await restorePageAction(workspaceSlug as string, projectId as string, pageId as string).then(() => {
|
||||
captureEvent(PAGE_RESTORED, {
|
||||
page_id: pageId,
|
||||
access: access == 1 ? "private" : "public",
|
||||
element: "Pages detail page",
|
||||
state: "SUCCESS",
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
actionCompleteAlert({
|
||||
title: `Page could not be restored`,
|
||||
@ -219,7 +258,14 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
||||
const lockPage = async () => {
|
||||
if (!workspaceSlug || !projectId || !pageId) return;
|
||||
try {
|
||||
await lockPageAction();
|
||||
await lockPageAction().then(() => {
|
||||
captureEvent(PAGE_LOCKED, {
|
||||
page_id: pageId,
|
||||
access: access == 1 ? "private" : "public",
|
||||
element: "Pages detail page",
|
||||
state: "SUCCESS",
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
actionCompleteAlert({
|
||||
title: `Page could not be locked`,
|
||||
@ -232,7 +278,14 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
||||
const unlockPage = async () => {
|
||||
if (!workspaceSlug || !projectId || !pageId) return;
|
||||
try {
|
||||
await unlockPageAction();
|
||||
await unlockPageAction().then(() => {
|
||||
captureEvent(PAGE_UNLOCKED, {
|
||||
page_id: pageId,
|
||||
access: access == 1 ? "private" : "public",
|
||||
element: "Pages detail page",
|
||||
state: "SUCCESS",
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
actionCompleteAlert({
|
||||
title: `Page could not be unlocked`,
|
||||
@ -342,8 +395,21 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
||||
// this is done so that the title do not reset after gpt popover closed
|
||||
reset(getValues());
|
||||
}}
|
||||
onResponse={(response) => {
|
||||
handleAiAssistance(response);
|
||||
onResponse={handleAiAssistance}
|
||||
onGenerateResponse={(question) => {
|
||||
captureEvent(AI_TRIGGERED, {
|
||||
page_id: pageId,
|
||||
element: "Pages detail page",
|
||||
question: question,
|
||||
});
|
||||
}}
|
||||
onReGenerateResponse={(question, response) => {
|
||||
captureEvent(AI_RES_REGENERATED, {
|
||||
page_id: pageId,
|
||||
element: "Pages detail page",
|
||||
question: question,
|
||||
prev_answer: response,
|
||||
});
|
||||
}}
|
||||
placement="top-end"
|
||||
button={
|
||||
|
@ -31,7 +31,7 @@ const WorkspaceMembersSettingsPage: NextPageWithLayout = observer(() => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
// store hooks
|
||||
const { captureEvent, setTrackElement } = useEventTracker();
|
||||
const { captureEvent } = useEventTracker();
|
||||
const {
|
||||
membership: { currentWorkspaceRole },
|
||||
} = useUser();
|
||||
|
@ -80,7 +80,7 @@ const UserInvitationsPage: NextPageWithLayout = observer(() => {
|
||||
|
||||
workspaceService
|
||||
.joinWorkspaces({ invitations: invitationsRespond })
|
||||
.then((res) => {
|
||||
.then(() => {
|
||||
mutate("USER_WORKSPACES");
|
||||
const firstInviteId = invitationsRespond[0];
|
||||
const invitation = invitations?.find((i) => i.id === firstInviteId);
|
||||
|
Loading…
Reference in New Issue
Block a user