From 2756c383baae5f7c68dd9fee5087cd80cc2248df Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Thu, 14 Nov 2024 20:42:42 +0530 Subject: [PATCH] feat: version history for issues --- .../editors/issue-version-editor.tsx | 3 +- .../components/issues/description-input.tsx | 16 +++++-- .../issue-detail-quick-actions.tsx | 44 ++++++++++++++----- .../components/issues/issue-detail/root.tsx | 5 +-- .../issues/issue-detail/version-history.tsx | 4 +- web/core/components/pages/index.ts | 1 - 6 files changed, 49 insertions(+), 24 deletions(-) diff --git a/web/core/components/editor/version-history/editors/issue-version-editor.tsx b/web/core/components/editor/version-history/editors/issue-version-editor.tsx index dc02f7c6af..7e379ae8e1 100644 --- a/web/core/components/editor/version-history/editors/issue-version-editor.tsx +++ b/web/core/components/editor/version-history/editors/issue-version-editor.tsx @@ -61,8 +61,7 @@ export const IssueVersionEditor: React.FC = observer((props

"} - containerClassName="p-0 pb-64 border-none" - editorClassName="pl-10" + containerClassName="!px-5 pb-64 border-none" workspaceSlug={workspaceSlug?.toString() ?? ""} projectId={projectId?.toString() ?? ""} /> diff --git a/web/core/components/issues/description-input.tsx b/web/core/components/issues/description-input.tsx index 7e6229d9e4..6c64ee3ba6 100644 --- a/web/core/components/issues/description-input.tsx +++ b/web/core/components/issues/description-input.tsx @@ -4,13 +4,14 @@ import { FC, useCallback, useRef } from "react"; import debounce from "lodash/debounce"; import { observer } from "mobx-react"; // plane editor -import { convertBinaryDataToBase64String, EditorRefApi } from "@plane/editor"; +import { convertBinaryDataToBase64String, EditorReadOnlyRefApi, EditorRefApi } from "@plane/editor"; // types import { EFileAssetType } from "@plane/types/src/enums"; // plane ui import { Loader } from "@plane/ui"; // components import { CollaborativeRichTextEditor, CollaborativeRichTextReadOnlyEditor } from "@/components/editor"; +import { IssueVersionHistory } from "@/components/issues"; // helpers import { getDescriptionPlaceholder } from "@/helpers/issue.helper"; // hooks @@ -49,6 +50,7 @@ export const IssueDescriptionInput: FC = observer((p } = props; // refs const editorRef = useRef(null); + const readOnlyEditorRef = useRef(null); // store hooks const { getWorkspaceBySlug } = useWorkspace(); // derived values @@ -95,7 +97,7 @@ export const IssueDescriptionInput: FC = observer((p ); return ( - <> +
{!disabled ? ( = observer((p /> ) : ( = observer((p workspaceSlug={workspaceSlug} /> )} - + {/* version history overlay */} + +
); }); diff --git a/web/core/components/issues/issue-detail/issue-detail-quick-actions.tsx b/web/core/components/issues/issue-detail/issue-detail-quick-actions.tsx index e0dedfaa5c..0b12268eca 100644 --- a/web/core/components/issues/issue-detail/issue-detail-quick-actions.tsx +++ b/web/core/components/issues/issue-detail/issue-detail-quick-actions.tsx @@ -3,8 +3,9 @@ import React, { FC, useState } from "react"; import { observer } from "mobx-react"; import { usePathname } from "next/navigation"; -import { ArchiveIcon, ArchiveRestoreIcon, LinkIcon, Trash2 } from "lucide-react"; -import { TOAST_TYPE, Tooltip, setToast } from "@plane/ui"; +import { ArchiveIcon, ArchiveRestoreIcon, History, LinkIcon, Trash2 } from "lucide-react"; +// plane ui +import { CustomMenu, TOAST_TYPE, Tooltip, setToast } from "@plane/ui"; // components import { ArchiveIssueModal, DeleteIssueModal, IssueSubscription } from "@/components/issues"; // constants @@ -25,6 +26,8 @@ import { } from "@/hooks/store"; import { useAppRouter } from "@/hooks/use-app-router"; import { usePlatformOS } from "@/hooks/use-platform-os"; +import { useQueryParams } from "@/hooks/use-query-params"; +// plane web constants import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions"; type Props = { @@ -35,15 +38,12 @@ type Props = { export const IssueDetailQuickActions: FC = observer((props) => { const { workspaceSlug, projectId, issueId } = props; - // states const [deleteIssueModal, setDeleteIssueModal] = useState(false); const [archiveIssueModal, setArchiveIssueModal] = useState(false); const [isRestoring, setIsRestoring] = useState(false); - // router const router = useAppRouter(); - // hooks const { data: currentUser } = useUser(); const { allowPermissions } = useUserPermissions(); @@ -62,13 +62,11 @@ export const IssueDetailQuickActions: FC = observer((props) => { } = useIssues(EIssuesStoreType.ARCHIVED); const { captureIssueEvent } = useEventTracker(); const pathname = usePathname(); - + const { updateQueryParams } = useQueryParams(); // derived values const issue = getIssueById(issueId); if (!issue) return <>; - const stateDetails = getStateById(issue.state_id); - // handlers const handleCopyText = () => { const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; @@ -80,7 +78,6 @@ export const IssueDetailQuickActions: FC = observer((props) => { }); }); }; - const handleDeleteIssue = async () => { try { const deleteIssue = issue?.archived_at ? removeArchivedIssue : removeIssue; @@ -109,7 +106,6 @@ export const IssueDetailQuickActions: FC = observer((props) => { }); } }; - const handleArchiveIssue = async () => { try { await archiveIssue(workspaceSlug, projectId, issueId).then(() => { @@ -128,7 +124,6 @@ export const IssueDetailQuickActions: FC = observer((props) => { }); } }; - const handleRestore = async () => { if (!workspaceSlug || !projectId || !issueId) return; @@ -153,6 +148,21 @@ export const IssueDetailQuickActions: FC = observer((props) => { .finally(() => setIsRestoring(false)); }; + const MENU_ITEMS = [ + { + key: "version-history", + action: () => { + // add query param, version=current to the route + const updatedRoute = updateQueryParams({ + paramsToAdd: { version: "current" }, + }); + router.push(updatedRoute); + }, + label: "Version history", + icon: History, + shouldRender: true, + }, + ]; // auth const isEditable = allowPermissions([EUserPermissions.ADMIN, EUserPermissions.MEMBER], EUserPermissionsLevel.PROJECT); const canRestoreIssue = allowPermissions( @@ -239,7 +249,6 @@ export const IssueDetailQuickActions: FC = observer((props) => { )} )} - {isEditable && ( )} + + {MENU_ITEMS.map((item) => { + if (!item.shouldRender) return null; + return ( + + + {item.label} + + ); + })} + diff --git a/web/core/components/issues/issue-detail/root.tsx b/web/core/components/issues/issue-detail/root.tsx index 02d756e474..74eb1483f4 100644 --- a/web/core/components/issues/issue-detail/root.tsx +++ b/web/core/components/issues/issue-detail/root.tsx @@ -9,7 +9,7 @@ import { TIssue } from "@plane/types"; import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/ui"; // components import { EmptyState } from "@/components/common"; -import { IssuePeekOverview, IssueVersionHistory } from "@/components/issues"; +import { IssuePeekOverview } from "@/components/issues"; // constants import { ISSUE_UPDATED, ISSUE_DELETED, ISSUE_ARCHIVED } from "@/constants/event-tracker"; import { EIssuesStoreType } from "@/constants/issue"; @@ -344,7 +344,6 @@ export const IssueDetailRoot: FC = observer((props) => { pathname, ] ); - // issue details const issue = getIssueById(issueId); // checking if issue is editable, based on user role @@ -390,8 +389,6 @@ export const IssueDetailRoot: FC = observer((props) => { )} {/* peek overview */} - {/* version history overlay */} - ); }); diff --git a/web/core/components/issues/issue-detail/version-history.tsx b/web/core/components/issues/issue-detail/version-history.tsx index 4da63db8f5..527802d585 100644 --- a/web/core/components/issues/issue-detail/version-history.tsx +++ b/web/core/components/issues/issue-detail/version-history.tsx @@ -14,9 +14,9 @@ const issueVersionService = new IssueVersionService(); type Props = { disabled: boolean; - editorRef: EditorRefApi; + editorRef: EditorRefApi | null; issueId: string; - readOnlyEditorRef: EditorReadOnlyRefApi; + readOnlyEditorRef: EditorReadOnlyRefApi | null; }; export const IssueVersionHistory: React.FC = (props) => { diff --git a/web/core/components/pages/index.ts b/web/core/components/pages/index.ts index d372f2b89c..13f5cec802 100644 --- a/web/core/components/pages/index.ts +++ b/web/core/components/pages/index.ts @@ -4,6 +4,5 @@ export * from "./header"; export * from "./list"; export * from "./loaders"; export * from "./modals"; -export * from "./version"; export * from "./pages-list-main-content"; export * from "./pages-list-view";