[WEB-2189] fix: issue peek overview and issue detail unauthorised delete action (#5341)
* fix: issue peek overview and issue detail delete action * chore: code refactor * chore: code refactor
This commit is contained in:
parent
421bf2abc7
commit
679b0b6465
6 changed files with 53 additions and 31 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",
|
||||
|
|
|
|||
|
|
@ -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!",
|
||||
|
|
|
|||
|
|
@ -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