diff --git a/web/components/headers/project-view-issues.tsx b/web/components/headers/project-view-issues.tsx index aeb91538c..827997f7b 100644 --- a/web/components/headers/project-view-issues.tsx +++ b/web/components/headers/project-view-issues.tsx @@ -173,7 +173,7 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => { handleDisplayPropertiesUpdate={handleDisplayProperties} /> - { + {canUserCreateIssue && ( - } + )} ); diff --git a/web/components/headers/project-views.tsx b/web/components/headers/project-views.tsx index 964110967..36c278e82 100644 --- a/web/components/headers/project-views.tsx +++ b/web/components/headers/project-views.tsx @@ -7,15 +7,24 @@ import { useMobxStore } from "lib/mobx/store-provider"; import { Breadcrumbs, PhotoFilterIcon, Button } from "@plane/ui"; // helpers import { renderEmoji } from "helpers/emoji.helper"; +// constants +import { EUserWorkspaceRoles } from "constants/workspace"; export const ProjectViewsHeader: React.FC = observer(() => { // router const router = useRouter(); const { workspaceSlug } = router.query; - const { project: projectStore, commandPalette } = useMobxStore(); + const { + project: projectStore, + commandPalette, + user: { currentProjectRole }, + } = useMobxStore(); const { currentProjectDetails } = projectStore; + const canUserCreateIssue = + currentProjectRole && [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER].includes(currentProjectRole); + return ( <>
@@ -50,18 +59,20 @@ export const ProjectViewsHeader: React.FC = observer(() => {
-
-
- + {canUserCreateIssue && ( +
+
+ +
-
+ )}
); diff --git a/web/components/issues/sidebar-select/assignee.tsx b/web/components/issues/sidebar-select/assignee.tsx index 497ab6589..34e3bc06a 100644 --- a/web/components/issues/sidebar-select/assignee.tsx +++ b/web/components/issues/sidebar-select/assignee.tsx @@ -60,7 +60,9 @@ export const SidebarAssigneeSelect: React.FC = ({ value, onChange, disabl ) : ( diff --git a/web/components/issues/sidebar.tsx b/web/components/issues/sidebar.tsx index f002b6dda..4cb4d74a1 100644 --- a/web/components/issues/sidebar.tsx +++ b/web/components/issues/sidebar.tsx @@ -572,7 +572,7 @@ export const IssueDetailsSidebar: React.FC = observer((props) => { labelList={issueDetail?.labels ?? []} submitChanges={submitChanges} isNotAllowed={!isAllowed} - uneditable={uneditable ?? false} + uneditable={uneditable || !isAllowed} /> diff --git a/web/components/views/view-list-item.tsx b/web/components/views/view-list-item.tsx index 95ca50562..6299c4cdb 100644 --- a/web/components/views/view-list-item.tsx +++ b/web/components/views/view-list-item.tsx @@ -2,17 +2,22 @@ import React, { useState } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; -import { PencilIcon, StarIcon, TrashIcon } from "lucide-react"; +import { LinkIcon, PencilIcon, StarIcon, TrashIcon } from "lucide-react"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; +// hooks +import useToast from "hooks/use-toast"; // components import { CreateUpdateProjectViewModal, DeleteProjectViewModal } from "components/views"; // ui import { CustomMenu, PhotoFilterIcon } from "@plane/ui"; // helpers import { calculateTotalFilters } from "helpers/filter.helper"; +import { copyUrlToClipboard } from "helpers/string.helper"; // types import { IProjectView } from "types"; +// constants +import { EUserWorkspaceRoles } from "constants/workspace"; type Props = { view: IProjectView; @@ -27,7 +32,12 @@ export const ProjectViewListItem: React.FC = observer((props) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; - const { projectViews: projectViewsStore } = useMobxStore(); + const { setToastAlert } = useToast(); + + const { + projectViews: projectViewsStore, + user: { currentProjectRole }, + } = useMobxStore(); const handleAddToFavorites = () => { if (!workspaceSlug || !projectId) return; @@ -41,8 +51,22 @@ export const ProjectViewListItem: React.FC = observer((props) => { projectViewsStore.removeViewFromFavorites(workspaceSlug.toString(), projectId.toString(), view.id); }; + const handleCopyText = (e: React.MouseEvent) => { + e.stopPropagation(); + e.preventDefault(); + copyUrlToClipboard(`${workspaceSlug}/projects/${projectId}/views/${view.id}`).then(() => { + setToastAlert({ + type: "success", + title: "Link Copied!", + message: "View link copied to clipboard.", + }); + }); + }; + const totalFilters = calculateTotalFilters(view.query_data ?? {}); + const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER; + return ( <> {workspaceSlug && projectId && view && ( @@ -73,55 +97,66 @@ export const ProjectViewListItem: React.FC = observer((props) => {

{totalFilters} {totalFilters === 1 ? "filter" : "filters"}

+ {isEditingAllowed && + (view.is_favorite ? ( + + ) : ( + + ))} - {view.is_favorite ? ( - - ) : ( - - )} - { - e.preventDefault(); - e.stopPropagation(); - setCreateUpdateViewModal(true); - }} - > + {isEditingAllowed && ( + <> + { + e.preventDefault(); + e.stopPropagation(); + setCreateUpdateViewModal(true); + }} + > + + + Edit View + + + { + e.preventDefault(); + e.stopPropagation(); + setDeleteViewModal(true); + }} + > + + + Delete View + + + + )} + - - Edit View - - - { - e.preventDefault(); - e.stopPropagation(); - setDeleteViewModal(true); - }} - > - - - Delete View + + Copy view link