mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: issue activity/ comments disable
and showAccessSpecifier
logic.
This commit is contained in:
parent
1873b445ed
commit
81b46e72c2
@ -9,15 +9,13 @@ import { IssueCommentCard } from "./comments/comment-card";
|
||||
import { TActivityOperations } from "./root";
|
||||
|
||||
type TIssueActivityCommentRoot = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
issueId: string;
|
||||
activityOperations: TActivityOperations;
|
||||
disabled: boolean;
|
||||
showAccessSpecifier?: boolean;
|
||||
};
|
||||
|
||||
export const IssueActivityCommentRoot: FC<TIssueActivityCommentRoot> = observer((props) => {
|
||||
const { workspaceSlug, projectId, issueId, activityOperations, disabled } = props;
|
||||
const { issueId, activityOperations, showAccessSpecifier } = props;
|
||||
// hooks
|
||||
const {
|
||||
activity: { getActivityCommentByIssueId },
|
||||
@ -32,21 +30,14 @@ export const IssueActivityCommentRoot: FC<TIssueActivityCommentRoot> = observer(
|
||||
{activityComments.map((activityComment, index) =>
|
||||
activityComment.activity_type === "COMMENT" ? (
|
||||
<IssueCommentCard
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
issueId={issueId}
|
||||
commentId={activityComment.id}
|
||||
activityOperations={activityOperations}
|
||||
disabled={disabled}
|
||||
ends={index === 0 ? "top" : index === activityComments.length - 1 ? "bottom" : undefined}
|
||||
showAccessSpecifier={showAccessSpecifier}
|
||||
/>
|
||||
) : activityComment.activity_type === "ACTIVITY" ? (
|
||||
<IssueActivityList
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
issueId={issueId}
|
||||
activityId={activityComment.id}
|
||||
disabled={disabled}
|
||||
ends={index === 0 ? "top" : index === activityComments.length - 1 ? "bottom" : undefined}
|
||||
/>
|
||||
) : (
|
||||
|
@ -24,11 +24,7 @@ import {
|
||||
} from "./actions";
|
||||
|
||||
type TIssueActivityList = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
issueId: string;
|
||||
activityId: string;
|
||||
disabled: boolean;
|
||||
ends: "top" | "bottom" | undefined;
|
||||
};
|
||||
|
||||
|
@ -6,14 +6,11 @@ import { useIssueDetail } from "hooks/store";
|
||||
import { IssueActivityList } from "./activity-list";
|
||||
|
||||
type TIssueActivityRoot = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
issueId: string;
|
||||
disabled: boolean;
|
||||
};
|
||||
|
||||
export const IssueActivityRoot: FC<TIssueActivityRoot> = observer((props) => {
|
||||
const { workspaceSlug, projectId, issueId, disabled } = props;
|
||||
const { issueId } = props;
|
||||
// hooks
|
||||
const {
|
||||
activity: { getActivitiesByIssueId },
|
||||
@ -26,11 +23,7 @@ export const IssueActivityRoot: FC<TIssueActivityRoot> = observer((props) => {
|
||||
<div>
|
||||
{activityIds.map((activityId, index) => (
|
||||
<IssueActivityList
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
issueId={issueId}
|
||||
activityId={activityId}
|
||||
disabled={disabled}
|
||||
ends={index === 0 ? "top" : index === activityIds.length - 1 ? "bottom" : undefined}
|
||||
/>
|
||||
))}
|
||||
|
@ -44,7 +44,7 @@ export const IssueCommentBlock: FC<TIssueCommentBlock> = (props) => {
|
||||
</>
|
||||
)}
|
||||
<div className="absolute top-2 left-4 w-5 h-5 rounded-full overflow-hidden flex justify-center items-center bg-custom-background-80">
|
||||
<MessageSquare className="w-3 h-3" />
|
||||
<MessageSquare className="w-3 h-3" color="#6b7280" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full relative flex ">
|
||||
|
@ -17,18 +17,14 @@ import { TActivityOperations } from "../root";
|
||||
const fileService = new FileService();
|
||||
|
||||
type TIssueCommentCard = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
issueId: string;
|
||||
commentId: string;
|
||||
activityOperations: TActivityOperations;
|
||||
disabled: boolean;
|
||||
ends: "top" | "bottom" | undefined;
|
||||
showAccessSpecifier?: boolean;
|
||||
};
|
||||
|
||||
export const IssueCommentCard: FC<TIssueCommentCard> = (props) => {
|
||||
const { commentId, activityOperations, ends, showAccessSpecifier = true } = props;
|
||||
const { commentId, activityOperations, ends, showAccessSpecifier = false } = props;
|
||||
// hooks
|
||||
const {
|
||||
comment: { getCommentById },
|
||||
|
@ -1,79 +0,0 @@
|
||||
import { FC, useRef } from "react";
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
// components
|
||||
import { LiteTextEditorWithRef } from "@plane/lite-text-editor";
|
||||
import { Button } from "@plane/ui";
|
||||
// services
|
||||
import { FileService } from "services/file.service";
|
||||
// types
|
||||
import { TActivityOperations } from "../root";
|
||||
import { TIssueComment } from "@plane/types";
|
||||
|
||||
const fileService = new FileService();
|
||||
|
||||
type TIssueCommentCreateUpdate = {
|
||||
workspaceSlug: string;
|
||||
activityOperations: TActivityOperations;
|
||||
disabled: boolean;
|
||||
};
|
||||
|
||||
export const IssueCommentCreateUpdate: FC<TIssueCommentCreateUpdate> = (props) => {
|
||||
const { workspaceSlug, activityOperations, disabled } = props;
|
||||
// refs
|
||||
const editorRef = useRef<any>(null);
|
||||
// react hook form
|
||||
const {
|
||||
handleSubmit,
|
||||
control,
|
||||
formState: { isSubmitting },
|
||||
reset,
|
||||
} = useForm<Partial<TIssueComment>>({ defaultValues: { comment_html: "<p></p>" } });
|
||||
|
||||
const onSubmit = async (formData: Partial<TIssueComment>) => {
|
||||
await activityOperations.createComment(formData).finally(() => {
|
||||
reset({ comment_html: "" });
|
||||
editorRef.current?.clearEditor();
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Controller
|
||||
name="comment_html"
|
||||
control={control}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<LiteTextEditorWithRef
|
||||
onEnterKeyPress={(e) => {
|
||||
handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
ref={editorRef}
|
||||
value={!value ? "<p></p>" : value}
|
||||
customClassName="p-2"
|
||||
editorContentCustomClassNames="min-h-[35px]"
|
||||
debouncedUpdatesEnabled={false}
|
||||
onChange={(comment_json: Object, comment_html: string) => {
|
||||
onChange(comment_html);
|
||||
}}
|
||||
submitButton={
|
||||
<Button
|
||||
disabled={isSubmitting || disabled}
|
||||
variant="primary"
|
||||
type="submit"
|
||||
className="!px-2.5 !py-1.5 !text-xs"
|
||||
onClick={(e) => {
|
||||
handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
>
|
||||
{isSubmitting ? "Adding..." : "Comment"}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -0,0 +1,111 @@
|
||||
import { FC, useRef } from "react";
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
// components
|
||||
import { LiteTextEditorWithRef } from "@plane/lite-text-editor";
|
||||
import { Button } from "@plane/ui";
|
||||
// services
|
||||
import { FileService } from "services/file.service";
|
||||
// types
|
||||
import { TActivityOperations } from "../root";
|
||||
import { TIssueComment } from "@plane/types";
|
||||
// icons
|
||||
import { Globe2, Lock } from "lucide-react";
|
||||
|
||||
const fileService = new FileService();
|
||||
|
||||
type TIssueCommentCreate = {
|
||||
workspaceSlug: string;
|
||||
activityOperations: TActivityOperations;
|
||||
disabled: boolean;
|
||||
showAccessSpecifier?: boolean;
|
||||
};
|
||||
|
||||
type commentAccessType = {
|
||||
icon: any;
|
||||
key: string;
|
||||
label: "Private" | "Public";
|
||||
};
|
||||
const commentAccess: commentAccessType[] = [
|
||||
{
|
||||
icon: Lock,
|
||||
key: "INTERNAL",
|
||||
label: "Private",
|
||||
},
|
||||
{
|
||||
icon: Globe2,
|
||||
key: "EXTERNAL",
|
||||
label: "Public",
|
||||
},
|
||||
];
|
||||
|
||||
export const IssueCommentCreate: FC<TIssueCommentCreate> = (props) => {
|
||||
const { workspaceSlug, activityOperations, disabled, showAccessSpecifier = false } = props;
|
||||
// refs
|
||||
const editorRef = useRef<any>(null);
|
||||
// react hook form
|
||||
const {
|
||||
handleSubmit,
|
||||
control,
|
||||
formState: { isSubmitting },
|
||||
reset,
|
||||
} = useForm<Partial<TIssueComment>>({ defaultValues: { comment_html: "<p></p>" } });
|
||||
|
||||
const onSubmit = async (formData: Partial<TIssueComment>) => {
|
||||
await activityOperations.createComment(formData).finally(() => {
|
||||
reset({ comment_html: "" });
|
||||
editorRef.current?.clearEditor();
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Controller
|
||||
name="access"
|
||||
control={control}
|
||||
render={({ field: { onChange: onAccessChange, value: accessValue } }) => (
|
||||
<Controller
|
||||
name="comment_html"
|
||||
control={control}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<LiteTextEditorWithRef
|
||||
onEnterKeyPress={(e) => {
|
||||
handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
cancelUploadImage={fileService.cancelUpload}
|
||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||
deleteFile={fileService.deleteImage}
|
||||
restoreFile={fileService.restoreImage}
|
||||
ref={editorRef}
|
||||
value={!value ? "<p></p>" : value}
|
||||
customClassName="p-2"
|
||||
editorContentCustomClassNames="min-h-[35px]"
|
||||
debouncedUpdatesEnabled={false}
|
||||
onChange={(comment_json: Object, comment_html: string) => {
|
||||
onChange(comment_html);
|
||||
}}
|
||||
commentAccessSpecifier={
|
||||
showAccessSpecifier
|
||||
? { accessValue: accessValue ?? "INTERNAL", onAccessChange, showAccessSpecifier, commentAccess }
|
||||
: undefined
|
||||
}
|
||||
submitButton={
|
||||
<Button
|
||||
disabled={isSubmitting || disabled}
|
||||
variant="primary"
|
||||
type="submit"
|
||||
className="!px-2.5 !py-1.5 !text-xs"
|
||||
onClick={(e) => {
|
||||
handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
>
|
||||
{isSubmitting ? "Adding..." : "Comment"}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -8,34 +8,29 @@ import { IssueCommentCard } from "./comment-card";
|
||||
import { TActivityOperations } from "../root";
|
||||
|
||||
type TIssueCommentRoot = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
issueId: string;
|
||||
activityOperations: TActivityOperations;
|
||||
disabled: boolean;
|
||||
showAccessSpecifier?: boolean;
|
||||
};
|
||||
|
||||
export const IssueCommentRoot: FC<TIssueCommentRoot> = observer((props) => {
|
||||
const { workspaceSlug, projectId, issueId, disabled, activityOperations } = props;
|
||||
const { issueId, activityOperations, showAccessSpecifier } = props;
|
||||
// hooks
|
||||
const {
|
||||
comment: { getCommentsByIssueId },
|
||||
} = useIssueDetail();
|
||||
|
||||
const commentIds = getCommentsByIssueId(issueId);
|
||||
|
||||
if (!commentIds) return <></>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{commentIds.map((commentId, index) => (
|
||||
<IssueCommentCard
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
issueId={issueId}
|
||||
commentId={commentId}
|
||||
disabled={disabled}
|
||||
ends={index === 0 ? "top" : index === commentIds.length - 1 ? "bottom" : undefined}
|
||||
activityOperations={activityOperations}
|
||||
showAccessSpecifier={showAccessSpecifier}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
@ -9,4 +9,4 @@ export * from "./activity/activity-list";
|
||||
// issue comment
|
||||
export * from "./comments/root";
|
||||
export * from "./comments/comment-card";
|
||||
export * from "./comments/comment-create-update";
|
||||
export * from "./comments/comment-create";
|
||||
|
@ -5,7 +5,7 @@ import { History, LucideIcon, MessageSquare, Network } from "lucide-react";
|
||||
import { useIssueDetail } from "hooks/store";
|
||||
import useToast from "hooks/use-toast";
|
||||
// components
|
||||
import { IssueActivityCommentRoot, IssueActivityRoot, IssueCommentRoot, IssueCommentCreateUpdate } from "./";
|
||||
import { IssueActivityCommentRoot, IssueActivityRoot, IssueCommentRoot, IssueCommentCreate } from "./";
|
||||
// types
|
||||
import { TIssueComment } from "@plane/types";
|
||||
|
||||
@ -14,6 +14,7 @@ type TIssueActivity = {
|
||||
projectId: string;
|
||||
issueId: string;
|
||||
disabled: boolean;
|
||||
showAccessSpecifier?: boolean;
|
||||
};
|
||||
|
||||
type TActivityTabs = "all" | "activity" | "comments";
|
||||
@ -45,7 +46,7 @@ export type TActivityOperations = {
|
||||
};
|
||||
|
||||
export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
||||
const { workspaceSlug, projectId, issueId, disabled } = props;
|
||||
const { workspaceSlug, projectId, issueId, disabled, showAccessSpecifier } = props;
|
||||
// hooks
|
||||
const { createComment, updateComment, removeComment, createCommentReaction, removeCommentReaction } =
|
||||
useIssueDetail();
|
||||
@ -154,13 +155,6 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
||||
]
|
||||
);
|
||||
|
||||
const componentCommonProps = {
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
issueId,
|
||||
disabled,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-3 pt-3">
|
||||
{/* header */}
|
||||
@ -191,22 +185,32 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
||||
<div className="min-h-[200px]">
|
||||
{activityTab === "all" ? (
|
||||
<>
|
||||
<IssueActivityCommentRoot {...componentCommonProps} activityOperations={activityOperations} />
|
||||
<IssueCommentCreateUpdate
|
||||
<IssueActivityCommentRoot
|
||||
issueId={issueId}
|
||||
activityOperations={activityOperations}
|
||||
showAccessSpecifier={showAccessSpecifier}
|
||||
/>
|
||||
<IssueCommentCreate
|
||||
workspaceSlug={workspaceSlug}
|
||||
activityOperations={activityOperations}
|
||||
disabled={disabled}
|
||||
showAccessSpecifier={showAccessSpecifier}
|
||||
/>
|
||||
</>
|
||||
) : activityTab === "activity" ? (
|
||||
<IssueActivityRoot {...componentCommonProps} />
|
||||
<IssueActivityRoot issueId={issueId} />
|
||||
) : (
|
||||
<>
|
||||
<IssueCommentRoot {...componentCommonProps} activityOperations={activityOperations} />
|
||||
<IssueCommentCreateUpdate
|
||||
<IssueCommentRoot
|
||||
issueId={issueId}
|
||||
activityOperations={activityOperations}
|
||||
showAccessSpecifier={showAccessSpecifier}
|
||||
/>
|
||||
<IssueCommentCreate
|
||||
workspaceSlug={workspaceSlug}
|
||||
activityOperations={activityOperations}
|
||||
disabled={disabled}
|
||||
showAccessSpecifier={showAccessSpecifier}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
// hooks
|
||||
import { useIssueDetail, useProjectState, useUser } from "hooks/store";
|
||||
import { useIssueDetail, useProject, useProjectState, useUser } from "hooks/store";
|
||||
// components
|
||||
import { IssueDescriptionForm, IssueAttachmentRoot, IssueUpdateStatus } from "components/issues";
|
||||
import { IssueParentDetail } from "./parent";
|
||||
@ -32,10 +32,14 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
||||
const {
|
||||
issue: { getIssueById },
|
||||
} = useIssueDetail();
|
||||
const { getProjectById } = useProject();
|
||||
|
||||
const issue = getIssueById(issueId);
|
||||
if (!issue) return <></>;
|
||||
|
||||
const project = getProjectById(projectId);
|
||||
if (!project) return <></>;
|
||||
|
||||
const currentIssueState = projectStates?.find((s) => s.id === issue.state_id);
|
||||
|
||||
return (
|
||||
@ -100,7 +104,13 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
||||
disabled={!is_editable}
|
||||
/>
|
||||
|
||||
<IssueActivity workspaceSlug={workspaceSlug} projectId={projectId} issueId={issueId} disabled={false} />
|
||||
<IssueActivity
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
issueId={issueId}
|
||||
disabled={!is_editable}
|
||||
showAccessSpecifier={project.is_deployed}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user