mirror of
https://github.com/makeplane/plane
synced 2025-08-07 19:59:33 +00:00
[WEB-3146] | [WEB-3147] chore: project overview permission (#2207)
* chore: project overview description edit permission updated * chore: project overview update validation updated
This commit is contained in:
committed by
GitHub
parent
b5fa81465d
commit
f3325a99eb
@@ -2,9 +2,11 @@
|
||||
|
||||
import React, { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { EUserPermissionsLevel } from "@plane/constants";
|
||||
// hooks
|
||||
import { useProject } from "@/hooks/store";
|
||||
import { useProject, useUserPermissions } from "@/hooks/store";
|
||||
// types
|
||||
import { EUserPermissions } from "@/plane-web/constants";
|
||||
import { TProject } from "@/plane-web/types";
|
||||
// local components
|
||||
import { useLinks } from "./collaspible-section/links/use-links";
|
||||
@@ -20,6 +22,7 @@ export const ProjectOverviewInfoSectionRoot: FC<Props> = observer((props) => {
|
||||
const { workspaceSlug, projectId } = props;
|
||||
// store hooks
|
||||
const { getProjectById, updateProject } = useProject();
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
// helper hooks
|
||||
const { toggleLinkModal } = useLinks(workspaceSlug.toString(), projectId.toString());
|
||||
|
||||
@@ -31,6 +34,13 @@ export const ProjectOverviewInfoSectionRoot: FC<Props> = observer((props) => {
|
||||
const handleUpdateProject = async (data: Partial<TProject>) => {
|
||||
await updateProject(workspaceSlug.toString(), projectId.toString(), data);
|
||||
};
|
||||
|
||||
const isProjectAdmin = allowPermissions(
|
||||
[EUserPermissions.ADMIN],
|
||||
EUserPermissionsLevel.PROJECT,
|
||||
workspaceSlug.toString(),
|
||||
project.id.toString()
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<HeroSection project={project} workspaceSlug={workspaceSlug.toString()} />
|
||||
@@ -39,6 +49,7 @@ export const ProjectOverviewInfoSectionRoot: FC<Props> = observer((props) => {
|
||||
project={project}
|
||||
handleProjectUpdate={handleUpdateProject}
|
||||
toggleLinkModalOpen={toggleLinkModal}
|
||||
disabled={!isProjectAdmin}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -10,9 +10,10 @@ type TProps = {
|
||||
project: TProject;
|
||||
handleProjectUpdate: (data: Partial<TProject>) => Promise<void>;
|
||||
toggleLinkModalOpen: (value: boolean) => void;
|
||||
disabled?: boolean;
|
||||
};
|
||||
export const DescriptionBox = (props: TProps) => {
|
||||
const { workspaceSlug, project, handleProjectUpdate, toggleLinkModalOpen } = props;
|
||||
const { workspaceSlug, project, handleProjectUpdate, toggleLinkModalOpen, disabled = false } = props;
|
||||
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
|
||||
|
||||
// hooks
|
||||
@@ -27,6 +28,7 @@ export const DescriptionBox = (props: TProps) => {
|
||||
handleUpdate={handleProjectUpdate}
|
||||
setIsSubmitting={setIsSubmitting}
|
||||
containerClassName="px-0 text-base min-h-[200px] w-full"
|
||||
disabled={disabled}
|
||||
/>
|
||||
<div className="flex items-center justify-between w-full gap-2 pb-6 border-b border-custom-border-200">
|
||||
<ProjectReaction workspaceSlug={workspaceSlug} projectId={project.id} currentUser={currentUser} />
|
||||
|
||||
@@ -136,7 +136,7 @@ export const ProjectDescriptionInput: FC<ProjectDescriptionInputProps> = observe
|
||||
) : (
|
||||
<RichTextReadOnlyEditor
|
||||
id={project.id}
|
||||
initialValue={""}
|
||||
initialValue={initialValue ?? ""}
|
||||
containerClassName={containerClassName}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={project.id}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import React, { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { MessageCircle, Rocket } from "lucide-react";
|
||||
import { EUserPermissionsLevel } from "@plane/constants";
|
||||
import { AtRiskIcon, OffTrackIcon, OnTrackIcon } from "@plane/ui";
|
||||
import { cn } from "@plane/utils";
|
||||
import { renderFormattedDate } from "@/helpers/date-time.helper";
|
||||
import { useMember, useUser } from "@/hooks/store";
|
||||
import { useMember, useUser, useUserPermissions } from "@/hooks/store";
|
||||
import { EUserPermissions } from "@/plane-web/constants";
|
||||
import { useProjectUpdates } from "@/plane-web/hooks/store/projects/use-project-updates";
|
||||
import { EProjectUpdateStatus, TProjectUpdate } from "@/plane-web/types";
|
||||
import { CommentList } from "./comments/comment-list";
|
||||
@@ -49,6 +51,7 @@ export const UpdateBlock = observer((props: TProps) => {
|
||||
const { getUserDetails } = useMember();
|
||||
const { data: currentUser } = useUser();
|
||||
const { getUpdateById } = useProjectUpdates();
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
|
||||
const updateData = getUpdateById(updateId);
|
||||
|
||||
@@ -56,6 +59,13 @@ export const UpdateBlock = observer((props: TProps) => {
|
||||
|
||||
const icon = conf[updateData?.status].icon;
|
||||
|
||||
const isProjectAdmin = allowPermissions(
|
||||
[EUserPermissions.ADMIN],
|
||||
EUserPermissionsLevel.PROJECT,
|
||||
workspaceSlug.toString(),
|
||||
projectId.toString()
|
||||
);
|
||||
|
||||
return isEditing ? (
|
||||
<NewUpdate
|
||||
initialValues={updateData}
|
||||
@@ -87,16 +97,17 @@ export const UpdateBlock = observer((props: TProps) => {
|
||||
</div>
|
||||
</div>
|
||||
{/* quick actions */}
|
||||
<UpdateQuickActions
|
||||
isCreator={updateData.created_by === currentUser?.id}
|
||||
updateId={updateData.id}
|
||||
operations={{
|
||||
remove: handleUpdateOperations.remove,
|
||||
update: () => {
|
||||
setIsEditing(true);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
{isProjectAdmin && (
|
||||
<UpdateQuickActions
|
||||
updateId={updateData.id}
|
||||
operations={{
|
||||
remove: handleUpdateOperations.remove,
|
||||
update: () => {
|
||||
setIsEditing(true);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Update */}
|
||||
|
||||
@@ -5,7 +5,6 @@ import { cn } from "@plane/utils";
|
||||
import { ProjectUpdateDeleteModal } from "./delete-update-modal";
|
||||
|
||||
type TProps = {
|
||||
isCreator: boolean;
|
||||
updateId: string;
|
||||
operations: {
|
||||
update: () => void;
|
||||
@@ -13,7 +12,7 @@ type TProps = {
|
||||
};
|
||||
};
|
||||
export const UpdateQuickActions = (props: TProps) => {
|
||||
const { isCreator, operations, updateId } = props;
|
||||
const { operations, updateId } = props;
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
const [isMenuActive, setIsMenuActive] = useState(false);
|
||||
const actionSectionRef = useRef(null);
|
||||
@@ -41,23 +40,19 @@ export const UpdateQuickActions = (props: TProps) => {
|
||||
customButtonClassName="grid place-items-center"
|
||||
placement="bottom-start"
|
||||
>
|
||||
{isCreator && (
|
||||
<CustomMenu.MenuItem onClick={() => operations.update()}>
|
||||
<button className="flex items-center justify-start gap-2">
|
||||
<Pencil className="h-3.5 w-3.5 stroke-[1.5]" />
|
||||
<span>Edit</span>
|
||||
</button>
|
||||
</CustomMenu.MenuItem>
|
||||
)}
|
||||
<CustomMenu.MenuItem onClick={() => operations.update()}>
|
||||
<button className="flex items-center justify-start gap-2">
|
||||
<Pencil className="h-3.5 w-3.5 stroke-[1.5]" />
|
||||
<span>Edit</span>
|
||||
</button>
|
||||
</CustomMenu.MenuItem>
|
||||
|
||||
{isCreator && (
|
||||
<CustomMenu.MenuItem onClick={() => setIsDeleteModalOpen(true)}>
|
||||
<button className="flex items-center justify-start gap-2">
|
||||
<Trash2 className="h-3.5 w-3.5 stroke-[1.5]" />
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
</CustomMenu.MenuItem>
|
||||
)}
|
||||
<CustomMenu.MenuItem onClick={() => setIsDeleteModalOpen(true)}>
|
||||
<button className="flex items-center justify-start gap-2">
|
||||
<Trash2 className="h-3.5 w-3.5 stroke-[1.5]" />
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
</CustomMenu.MenuItem>
|
||||
</CustomMenu>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user