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";