fix: merge conflicts from preview
This commit is contained in:
commit
3729011cb0
283 changed files with 4895 additions and 5157 deletions
|
|
@ -8,7 +8,7 @@ import { AlertModalCore, TOAST_TYPE, setToast } from "@plane/ui";
|
|||
// constants
|
||||
import { PROJECT_ERROR_MESSAGES } from "@/constants/project";
|
||||
// hooks
|
||||
import { useIssues, useProject } from "@/hooks/store";
|
||||
import { useIssues, useProject, useUser } from "@/hooks/store";
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean;
|
||||
|
|
@ -26,6 +26,7 @@ export const DeleteIssueModal: React.FC<Props> = (props) => {
|
|||
// store hooks
|
||||
const { issueMap } = useIssues();
|
||||
const { getProjectById } = useProject();
|
||||
const { data: currentUser, canPerformProjectAdminActions } = useUser();
|
||||
|
||||
useEffect(() => {
|
||||
setIsDeleting(false);
|
||||
|
|
@ -36,6 +37,8 @@ export const DeleteIssueModal: React.FC<Props> = (props) => {
|
|||
// derived values
|
||||
const issue = data ? data : issueMap[dataId!];
|
||||
const projectDetails = getProjectById(issue?.project_id);
|
||||
const isIssueCreator = issue?.created_by === currentUser?.id;
|
||||
const authorized = isIssueCreator || canPerformProjectAdminActions;
|
||||
|
||||
const onClose = () => {
|
||||
setIsDeleting(false);
|
||||
|
|
@ -44,6 +47,16 @@ export const DeleteIssueModal: React.FC<Props> = (props) => {
|
|||
|
||||
const handleIssueDelete = async () => {
|
||||
setIsDeleting(true);
|
||||
|
||||
if (!authorized) {
|
||||
setToast({
|
||||
title: PROJECT_ERROR_MESSAGES.permissionError.title,
|
||||
type: TOAST_TYPE.ERROR,
|
||||
message: PROJECT_ERROR_MESSAGES.permissionError.message,
|
||||
});
|
||||
onClose();
|
||||
return;
|
||||
}
|
||||
if (onSubmit)
|
||||
await onSubmit()
|
||||
.then(() => {
|
||||
|
|
|
|||
|
|
@ -70,11 +70,12 @@ export const useRelationOperations = (): TRelationIssueOperations => {
|
|||
},
|
||||
remove: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||
try {
|
||||
await removeIssue(workspaceSlug, projectId, issueId);
|
||||
captureIssueEvent({
|
||||
eventName: ISSUE_DELETED,
|
||||
payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" },
|
||||
path: pathname,
|
||||
return removeIssue(workspaceSlug, projectId, issueId).then(() => {
|
||||
captureIssueEvent({
|
||||
eventName: ISSUE_DELETED,
|
||||
payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" },
|
||||
path: pathname,
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
captureIssueEvent({
|
||||
|
|
|
|||
|
|
@ -150,13 +150,14 @@ export const useSubIssueOperations = (): TSubIssueOperations => {
|
|||
deleteSubIssue: async (workspaceSlug: string, projectId: string, parentIssueId: string, issueId: string) => {
|
||||
try {
|
||||
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
||||
await deleteSubIssue(workspaceSlug, projectId, parentIssueId, issueId);
|
||||
captureIssueEvent({
|
||||
eventName: "Sub-issue deleted",
|
||||
payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" },
|
||||
path: pathname,
|
||||
return deleteSubIssue(workspaceSlug, projectId, parentIssueId, issueId).then(() => {
|
||||
captureIssueEvent({
|
||||
eventName: "Sub-issue deleted",
|
||||
payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" },
|
||||
path: pathname,
|
||||
});
|
||||
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
||||
});
|
||||
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
||||
} catch (error) {
|
||||
captureIssueEvent({
|
||||
eventName: "Sub-issue removed",
|
||||
|
|
|
|||
|
|
@ -137,7 +137,11 @@ export const IssueCommentCard: FC<TIssueCommentCard> = observer((props) => {
|
|||
>
|
||||
<>
|
||||
<form className={`flex-col gap-2 ${isEditing ? "flex" : "hidden"}`}>
|
||||
<div>
|
||||
<div
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" && !e.shiftKey && !e.ctrlKey && !e.metaKey && !isEmpty) handleSubmit(onEnter)(e);
|
||||
}}
|
||||
>
|
||||
<LiteTextEditor
|
||||
workspaceId={workspaceId}
|
||||
projectId={projectId}
|
||||
|
|
@ -147,13 +151,9 @@ export const IssueCommentCard: FC<TIssueCommentCard> = observer((props) => {
|
|||
initialValue={watch("comment_html") ?? ""}
|
||||
value={null}
|
||||
onChange={(comment_json, comment_html) => setValue("comment_html", comment_html)}
|
||||
onEnterKeyPress={(commentHTML) => {
|
||||
const isCommentEmpty =
|
||||
commentHTML?.trim() === "" ||
|
||||
commentHTML === "<p></p>" ||
|
||||
(isEmptyHtmlString(commentHTML ?? "") && !commentHTML?.includes("mention-component"));
|
||||
if (!isCommentEmpty && !isSubmitting) {
|
||||
handleSubmit(onEnter)();
|
||||
onEnterKeyPress={(e) => {
|
||||
if (!isEmpty && !isSubmitting) {
|
||||
handleSubmit(onEnter)(e);
|
||||
}
|
||||
}}
|
||||
showSubmitButton={false}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ export const IssueCommentCreate: FC<TIssueCommentCreate> = (props) => {
|
|||
const {
|
||||
handleSubmit,
|
||||
control,
|
||||
watch,
|
||||
formState: { isSubmitting },
|
||||
reset,
|
||||
} = useForm<Partial<TIssueComment>>({
|
||||
|
|
@ -49,8 +50,19 @@ export const IssueCommentCreate: FC<TIssueCommentCreate> = (props) => {
|
|||
editorRef.current?.clearEditor();
|
||||
});
|
||||
|
||||
const commentHTML = watch("comment_html");
|
||||
const isEmpty =
|
||||
commentHTML?.trim() === "" ||
|
||||
commentHTML === "<p></p>" ||
|
||||
(isEmptyHtmlString(commentHTML ?? "") && !commentHTML?.includes("mention-component"));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" && !e.shiftKey && !e.ctrlKey && !e.metaKey && !isEmpty && !isSubmitting)
|
||||
handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
>
|
||||
<Controller
|
||||
name="access"
|
||||
control={control}
|
||||
|
|
@ -65,13 +77,9 @@ export const IssueCommentCreate: FC<TIssueCommentCreate> = (props) => {
|
|||
value={"<p></p>"}
|
||||
projectId={projectId}
|
||||
workspaceSlug={workspaceSlug}
|
||||
onEnterKeyPress={(commentHTML) => {
|
||||
const isEmpty =
|
||||
commentHTML?.trim() === "" ||
|
||||
commentHTML === "<p></p>" ||
|
||||
(isEmptyHtmlString(commentHTML ?? "") && !commentHTML?.includes("mention-component"));
|
||||
onEnterKeyPress={(e) => {
|
||||
if (!isEmpty && !isSubmitting) {
|
||||
handleSubmit(onSubmit)();
|
||||
handleSubmit(onSubmit)(e);
|
||||
}
|
||||
}}
|
||||
ref={editorRef}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ type TIssueActivity = {
|
|||
projectId: string;
|
||||
issueId: string;
|
||||
disabled?: boolean;
|
||||
isIntakeIssue?: boolean;
|
||||
};
|
||||
|
||||
export type TActivityOperations = {
|
||||
|
|
@ -30,7 +31,7 @@ export type TActivityOperations = {
|
|||
};
|
||||
|
||||
export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
||||
const { workspaceSlug, projectId, issueId, disabled = false } = props;
|
||||
const { workspaceSlug, projectId, issueId, disabled = false, isIntakeIssue = false } = props;
|
||||
// hooks
|
||||
const { createComment, updateComment, removeComment } = useIssueDetail();
|
||||
const { getProjectById } = useProject();
|
||||
|
|
@ -114,12 +115,14 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
|||
<div className="flex items-center justify-between">
|
||||
<div className="text-lg text-custom-text-100">Activity</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<IssueActivityWorklogCreateButton
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
issueId={issueId}
|
||||
disabled={disabled}
|
||||
/>
|
||||
{!isIntakeIssue && (
|
||||
<IssueActivityWorklogCreateButton
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
issueId={issueId}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
<ActivityFilterRoot selectedFilters={selectedFilters} toggleFilter={toggleFilter} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -78,14 +78,18 @@ export const IssueDetailQuickActions: FC<Props> = observer((props) => {
|
|||
|
||||
const handleDeleteIssue = async () => {
|
||||
try {
|
||||
if (issue?.archived_at) await removeArchivedIssue(workspaceSlug, projectId, issueId);
|
||||
else await removeIssue(workspaceSlug, projectId, issueId);
|
||||
router.push(`/${workspaceSlug}/projects/${projectId}/issues`);
|
||||
captureIssueEvent({
|
||||
eventName: ISSUE_DELETED,
|
||||
payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" },
|
||||
path: pathname,
|
||||
});
|
||||
if (issue?.archived_at) {
|
||||
return removeArchivedIssue(workspaceSlug, projectId, issueId).then(() => {
|
||||
router.push(`/${workspaceSlug}/projects/${projectId}/issues`);
|
||||
captureIssueEvent({
|
||||
eventName: ISSUE_DELETED,
|
||||
payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" },
|
||||
path: pathname,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return removeIssue(workspaceSlug, projectId, issueId);
|
||||
}
|
||||
} catch (error) {
|
||||
setToast({
|
||||
title: "Error!",
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||
<UserCircle2 className="h-4 w-4 flex-shrink-0" />
|
||||
<span>Created by</span>
|
||||
</div>
|
||||
<div className="h-full flex items-center gap-1.5 rounded px-2 py-0.5 text-sm justify-between cursor-default">
|
||||
<div className="w-full h-full flex items-center gap-1.5 rounded px-2 py-0.5 text-sm justify-between cursor-not-allowed">
|
||||
<ButtonAvatars showTooltip userIds={createdByDetails.id} />
|
||||
<span className="flex-grow truncate text-xs leading-5">{createdByDetails?.display_name}</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
|||
<UserCircle2 className="h-4 w-4 flex-shrink-0" />
|
||||
<span>Created by</span>
|
||||
</div>
|
||||
<div className="h-full flex items-center gap-1.5 rounded px-2 py-0.5 text-sm justify-between cursor-default">
|
||||
<div className="w-full h-full flex items-center gap-1.5 rounded px-2 py-0.5 text-sm justify-between cursor-not-allowed">
|
||||
<ButtonAvatars showTooltip userIds={createdByDetails?.id} />
|
||||
<span className="flex-grow truncate text-xs leading-5">{createdByDetails?.display_name}</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||
} = useIssues(EIssuesStoreType.ARCHIVED);
|
||||
const {
|
||||
peekIssue,
|
||||
setPeekIssue,
|
||||
issue: { fetchIssue },
|
||||
fetchActivities,
|
||||
} = useIssueDetail();
|
||||
|
|
@ -44,6 +45,11 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||
const [loader, setLoader] = useState(true);
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
const removeRoutePeekId = () => {
|
||||
setPeekIssue(undefined);
|
||||
if (embedIssue) embedRemoveCurrentNotification && embedRemoveCurrentNotification();
|
||||
};
|
||||
|
||||
const issueOperations: TIssueOperations = useMemo(
|
||||
() => ({
|
||||
fetch: async (workspaceSlug: string, projectId: string, issueId: string, loader = true) => {
|
||||
|
|
@ -95,16 +101,13 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||
},
|
||||
remove: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||
try {
|
||||
issues?.removeIssue(workspaceSlug, projectId, issueId);
|
||||
setToast({
|
||||
title: "Success!",
|
||||
type: TOAST_TYPE.SUCCESS,
|
||||
message: "Issue deleted successfully",
|
||||
});
|
||||
captureIssueEvent({
|
||||
eventName: ISSUE_DELETED,
|
||||
payload: { id: issueId, state: "SUCCESS", element: "Issue peek-overview" },
|
||||
path: pathname,
|
||||
return issues?.removeIssue(workspaceSlug, projectId, issueId).then(() => {
|
||||
captureIssueEvent({
|
||||
eventName: ISSUE_DELETED,
|
||||
payload: { id: issueId, state: "SUCCESS", element: "Issue peek-overview" },
|
||||
path: pathname,
|
||||
});
|
||||
removeRoutePeekId();
|
||||
});
|
||||
} catch (error) {
|
||||
setToast({
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ export const IssueView: FC<IIssueView> = observer((props) => {
|
|||
toggleDeleteIssueModal(null);
|
||||
}}
|
||||
data={issue}
|
||||
onSubmit={() => issueOperations.remove(workspaceSlug, projectId, issueId).then(() => removeRoutePeekId())}
|
||||
onSubmit={async () => issueOperations.remove(workspaceSlug, projectId, issueId)}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue