forked from github/plane
fix: sub-issue properties not rendering and other sub-issue bugs (#3020)
* fix: sub-issue properties not rendering * fix: delete sub-issue * fix: delete issue modal on command k and the issue details page
This commit is contained in:
parent
c6e2effa65
commit
5fdd2ac366
@ -34,6 +34,7 @@ export const CommandPalette: FC = observer(() => {
|
||||
theme: { toggleSidebar },
|
||||
user: { currentUser },
|
||||
trackEvent: { setTrackElement },
|
||||
projectIssues: { removeIssue },
|
||||
} = useMobxStore();
|
||||
const {
|
||||
toggleCommandPaletteModal,
|
||||
@ -218,11 +219,15 @@ export const CommandPalette: FC = observer(() => {
|
||||
currentStore={createIssueStoreType}
|
||||
/>
|
||||
|
||||
{issueId && issueDetails && (
|
||||
{workspaceSlug && projectId && issueId && issueDetails && (
|
||||
<DeleteIssueModal
|
||||
handleClose={() => toggleDeleteIssueModal(false)}
|
||||
isOpen={isDeleteIssueModalOpen}
|
||||
data={issueDetails}
|
||||
onSubmit={async () => {
|
||||
await removeIssue(workspaceSlug.toString(), projectId.toString(), issueId.toString());
|
||||
router.push(`/${workspaceSlug}/projects/${projectId}/issues`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
@ -57,12 +57,8 @@ export const UserImageUploadModal: React.FC<Props> = observer((props) => {
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
console.log("Submit triggered");
|
||||
|
||||
if (!image) return;
|
||||
|
||||
console.log("Inside submit");
|
||||
|
||||
setIsImageUploading(true);
|
||||
|
||||
const formData = new FormData();
|
||||
|
@ -29,7 +29,10 @@ export const DeleteIssueModal: React.FC<Props> = (props) => {
|
||||
|
||||
const handleIssueDelete = async () => {
|
||||
setIsDeleteLoading(true);
|
||||
if (onSubmit) await onSubmit().finally(() => setIsDeleteLoading(false));
|
||||
if (onSubmit)
|
||||
await onSubmit()
|
||||
.then(() => onClose())
|
||||
.finally(() => setIsDeleteLoading(false));
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -61,8 +61,6 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = (props) => {
|
||||
description_html: issue.description_html,
|
||||
});
|
||||
|
||||
console.log("in form", localIssueDescription);
|
||||
|
||||
useEffect(() => {
|
||||
if (issue.id) {
|
||||
setLocalIssueDescription({ id: issue.id, description_html: issue.description_html });
|
||||
|
@ -81,11 +81,10 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<ILinkDetails | null>(null);
|
||||
|
||||
const {
|
||||
user: userStore,
|
||||
user: { currentUser, currentProjectRole },
|
||||
projectState: { states },
|
||||
projectIssues: { removeIssue },
|
||||
} = useMobxStore();
|
||||
const user = userStore.currentUser;
|
||||
const userRole = userStore.currentProjectRole;
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, issueId, inboxIssueId } = router.query;
|
||||
@ -102,7 +101,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
|
||||
const handleCycleChange = useCallback(
|
||||
(cycleId: string) => {
|
||||
if (!workspaceSlug || !projectId || !issueDetail || !user) return;
|
||||
if (!workspaceSlug || !projectId || !issueDetail || !currentUser) return;
|
||||
|
||||
issueService
|
||||
.addIssueToCycle(workspaceSlug as string, projectId as string, cycleId, {
|
||||
@ -112,12 +111,12 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
mutate(ISSUE_DETAILS(issueId as string));
|
||||
});
|
||||
},
|
||||
[workspaceSlug, projectId, issueId, issueDetail, user]
|
||||
[workspaceSlug, projectId, issueId, issueDetail, currentUser]
|
||||
);
|
||||
|
||||
const handleModuleChange = useCallback(
|
||||
(moduleId: string) => {
|
||||
if (!workspaceSlug || !projectId || !issueDetail || !user) return;
|
||||
if (!workspaceSlug || !projectId || !issueDetail || !currentUser) return;
|
||||
|
||||
moduleService
|
||||
.addIssuesToModule(workspaceSlug as string, projectId as string, moduleId, {
|
||||
@ -127,7 +126,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
mutate(ISSUE_DETAILS(issueId as string));
|
||||
});
|
||||
},
|
||||
[workspaceSlug, projectId, issueId, issueDetail, user]
|
||||
[workspaceSlug, projectId, issueId, issueDetail, currentUser]
|
||||
);
|
||||
|
||||
const handleCreateLink = async (formData: IIssueLink) => {
|
||||
@ -249,7 +248,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
setLinkModal(true);
|
||||
};
|
||||
|
||||
const isAllowed = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||
|
||||
const currentIssueState = projectId
|
||||
? states[projectId.toString()]?.find((s) => s.id === issueDetail?.state)
|
||||
@ -268,8 +267,16 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
createIssueLink={handleCreateLink}
|
||||
updateIssueLink={handleUpdateLink}
|
||||
/>
|
||||
{issueDetail && (
|
||||
<DeleteIssueModal handleClose={() => setDeleteIssueModal(false)} isOpen={deleteIssueModal} data={issueDetail} />
|
||||
{workspaceSlug && projectId && issueDetail && (
|
||||
<DeleteIssueModal
|
||||
handleClose={() => setDeleteIssueModal(false)}
|
||||
isOpen={deleteIssueModal}
|
||||
data={issueDetail}
|
||||
onSubmit={async () => {
|
||||
await removeIssue(workspaceSlug.toString(), projectId.toString(), issueDetail.id);
|
||||
router.push(`/${workspaceSlug}/projects/${projectId}/issues`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className="h-full w-full flex flex-col divide-y-2 divide-custom-border-200 overflow-hidden">
|
||||
<div className="flex items-center justify-between px-5 pb-3">
|
||||
@ -288,8 +295,8 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
</h4>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{issueDetail?.created_by !== user?.id &&
|
||||
!issueDetail?.assignees.includes(user?.id ?? "") &&
|
||||
{issueDetail?.created_by !== currentUser?.id &&
|
||||
!issueDetail?.assignees.includes(currentUser?.id ?? "") &&
|
||||
!router.pathname.includes("[archivedIssueId]") &&
|
||||
(fieldsToShow.includes("all") || fieldsToShow.includes("subscribe")) && (
|
||||
<Button
|
||||
@ -654,10 +661,10 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||
handleDeleteLink={handleDeleteLink}
|
||||
handleEditLink={handleEditLink}
|
||||
userAuth={{
|
||||
isGuest: userRole === 5,
|
||||
isViewer: userRole === 10,
|
||||
isMember: userRole === 15,
|
||||
isOwner: userRole === 20,
|
||||
isGuest: currentProjectRole === 5,
|
||||
isViewer: currentProjectRole === 10,
|
||||
isMember: currentProjectRole === 15,
|
||||
isOwner: currentProjectRole === 20,
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
|
@ -117,17 +117,16 @@ export const SubIssues: React.FC<ISubIssues> = ({
|
||||
workspaceSlug={workspaceSlug}
|
||||
parentIssue={parentIssue}
|
||||
issue={issue}
|
||||
user={user}
|
||||
editable={editable}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-shrink-0 text-sm">
|
||||
<CustomMenu width="auto" ellipsis>
|
||||
<CustomMenu width="auto" placement="bottom-end" ellipsis>
|
||||
{editable && (
|
||||
<CustomMenu.MenuItem onClick={() => handleIssueCrudOperation("edit", parentIssue?.id, issue)}>
|
||||
<div className="flex items-center justify-start gap-2">
|
||||
<Pencil width={14} strokeWidth={2} />
|
||||
<div className="flex items-center gap-2">
|
||||
<Pencil className="h-3.5 w-3.5" strokeWidth={2} />
|
||||
<span>Edit issue</span>
|
||||
</div>
|
||||
</CustomMenu.MenuItem>
|
||||
@ -135,8 +134,8 @@ export const SubIssues: React.FC<ISubIssues> = ({
|
||||
|
||||
{editable && (
|
||||
<CustomMenu.MenuItem onClick={() => handleIssueCrudOperation("delete", parentIssue?.id, issue)}>
|
||||
<div className="flex items-center justify-start gap-2">
|
||||
<Trash width={14} strokeWidth={2} />
|
||||
<div className="flex items-center gap-2">
|
||||
<Trash className="h-3.5 w-3.5" strokeWidth={2} />
|
||||
<span>Delete issue</span>
|
||||
</div>
|
||||
</CustomMenu.MenuItem>
|
||||
@ -145,8 +144,8 @@ export const SubIssues: React.FC<ISubIssues> = ({
|
||||
<CustomMenu.MenuItem
|
||||
onClick={() => copyText(`${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`)}
|
||||
>
|
||||
<div className="flex items-center justify-start gap-2">
|
||||
<LinkIcon width={14} strokeWidth={2} />
|
||||
<div className="flex items-center gap-2">
|
||||
<LinkIcon className="h-3.5 w-3.5" strokeWidth={2} />
|
||||
<span>Copy issue link</span>
|
||||
</div>
|
||||
</CustomMenu.MenuItem>
|
||||
|
@ -1,15 +1,11 @@
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { mutate } from "swr";
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
// services
|
||||
import { IssueService } from "services/issue";
|
||||
// components
|
||||
import { ViewDueDateSelect, ViewStartDateSelect } from "components/issues";
|
||||
import { PrioritySelect } from "components/project";
|
||||
// types
|
||||
import { IUser, IIssue, IState } from "types";
|
||||
import { IIssue, IState } from "types";
|
||||
// fetch-keys
|
||||
import { SUB_ISSUES } from "constants/fetch-keys";
|
||||
import { IssuePropertyAssignee, IssuePropertyState } from "../issue-layouts/properties";
|
||||
@ -18,19 +14,14 @@ export interface IIssueProperty {
|
||||
workspaceSlug: string;
|
||||
parentIssue: IIssue;
|
||||
issue: IIssue;
|
||||
user: IUser | undefined;
|
||||
editable: boolean;
|
||||
}
|
||||
|
||||
// services
|
||||
const issueService = new IssueService();
|
||||
|
||||
export const IssueProperty: React.FC<IIssueProperty> = observer((props) => {
|
||||
const { workspaceSlug, parentIssue, issue, user, editable } = props;
|
||||
|
||||
const { issueFilter: issueFilterStore } = useMobxStore();
|
||||
|
||||
const displayProperties = issueFilterStore.userDisplayProperties ?? {};
|
||||
export const IssueProperty: React.FC<IIssueProperty> = (props) => {
|
||||
const { workspaceSlug, parentIssue, issue, editable } = props;
|
||||
|
||||
const handlePriorityChange = (data: any) => {
|
||||
partialUpdateIssue({ priority: data });
|
||||
@ -77,63 +68,30 @@ export const IssueProperty: React.FC<IIssueProperty> = observer((props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative flex items-center gap-1">
|
||||
{displayProperties.priority && (
|
||||
<div className="flex-shrink-0">
|
||||
<PrioritySelect
|
||||
value={issue.priority}
|
||||
onChange={handlePriorityChange}
|
||||
hideDropdownArrow
|
||||
disabled={!editable}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="relative flex items-center gap-2">
|
||||
<div className="flex-shrink-0">
|
||||
<PrioritySelect value={issue.priority} onChange={handlePriorityChange} hideDropdownArrow disabled={!editable} />
|
||||
</div>
|
||||
|
||||
{displayProperties.state && (
|
||||
<div className="flex-shrink-0">
|
||||
<IssuePropertyState
|
||||
projectId={issue?.project_detail?.id || null}
|
||||
value={issue?.state_detail || null}
|
||||
onChange={(data) => handleStateChange(data)}
|
||||
disabled={false}
|
||||
hideDropdownArrow
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex-shrink-0">
|
||||
<IssuePropertyState
|
||||
projectId={issue?.project_detail?.id || null}
|
||||
value={issue?.state || null}
|
||||
onChange={(data) => handleStateChange(data)}
|
||||
disabled={false}
|
||||
hideDropdownArrow
|
||||
/>
|
||||
</div>
|
||||
|
||||
{displayProperties.start_date && issue.start_date && (
|
||||
<div className="flex-shrink-0 w-[104px]">
|
||||
<ViewStartDateSelect
|
||||
issue={issue}
|
||||
onChange={(val) => partialUpdateIssue({ start_date: val })}
|
||||
disabled={!editable}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{displayProperties.due_date && issue.target_date && (
|
||||
<div className="flex-shrink-0 w-[104px]">
|
||||
{user && (
|
||||
<ViewDueDateSelect
|
||||
issue={issue}
|
||||
onChange={(val) => partialUpdateIssue({ target_date: val })}
|
||||
disabled={!editable}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{displayProperties.assignee && (
|
||||
<div className="flex-shrink-0">
|
||||
<IssuePropertyAssignee
|
||||
projectId={issue?.project_detail?.id || null}
|
||||
value={issue?.assignees || null}
|
||||
hideDropdownArrow
|
||||
onChange={(val) => handleAssigneeChange(val)}
|
||||
disabled={false}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex-shrink-0">
|
||||
<IssuePropertyAssignee
|
||||
projectId={issue?.project_detail?.id || null}
|
||||
value={issue?.assignees || null}
|
||||
hideDropdownArrow
|
||||
onChange={(val) => handleAssigneeChange(val)}
|
||||
disabled={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
@ -45,11 +45,10 @@ export const SubIssuesRoot: React.FC<ISubIssuesRoot> = observer((props) => {
|
||||
const { parentIssue, user } = props;
|
||||
|
||||
const {
|
||||
user: userStore,
|
||||
user: { currentProjectRole },
|
||||
issue: { updateIssueStructure },
|
||||
projectIssues: { updateIssue },
|
||||
projectIssues: { updateIssue, removeIssue },
|
||||
} = useMobxStore();
|
||||
const userRole = userStore.currentProjectRole;
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
@ -177,7 +176,7 @@ export const SubIssuesRoot: React.FC<ISubIssuesRoot> = observer((props) => {
|
||||
[updateIssueStructure, projectId, updateIssue, user, workspaceSlug]
|
||||
);
|
||||
|
||||
const isEditable = !!userRole && userRole >= EUserWorkspaceRoles.MEMBER;
|
||||
const isEditable = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||
|
||||
const mutateSubIssues = (parentIssueId: string | null) => {
|
||||
if (parentIssueId) mutate(SUB_ISSUES(parentIssueId));
|
||||
@ -261,7 +260,7 @@ export const SubIssuesRoot: React.FC<ISubIssuesRoot> = observer((props) => {
|
||||
</>
|
||||
}
|
||||
buttonClassName="whitespace-nowrap"
|
||||
// position="left"
|
||||
placement="bottom-end"
|
||||
noBorder
|
||||
noChevron
|
||||
>
|
||||
@ -297,7 +296,7 @@ export const SubIssuesRoot: React.FC<ISubIssuesRoot> = observer((props) => {
|
||||
</>
|
||||
}
|
||||
buttonClassName="whitespace-nowrap"
|
||||
// position="left"
|
||||
placement="bottom-end"
|
||||
noBorder
|
||||
noChevron
|
||||
>
|
||||
@ -356,7 +355,8 @@ export const SubIssuesRoot: React.FC<ISubIssuesRoot> = observer((props) => {
|
||||
</>
|
||||
)}
|
||||
{isEditable &&
|
||||
issueCrudOperation?.delete?.toggle &&
|
||||
workspaceSlug &&
|
||||
projectId &&
|
||||
issueCrudOperation?.delete?.issueId &&
|
||||
issueCrudOperation?.delete?.issue && (
|
||||
<DeleteIssueModal
|
||||
@ -366,6 +366,13 @@ export const SubIssuesRoot: React.FC<ISubIssuesRoot> = observer((props) => {
|
||||
handleIssueCrudOperation("delete", null, null);
|
||||
}}
|
||||
data={issueCrudOperation?.delete?.issue}
|
||||
onSubmit={async () => {
|
||||
await removeIssue(
|
||||
workspaceSlug.toString(),
|
||||
projectId.toString(),
|
||||
issueCrudOperation?.delete?.issue?.id ?? ""
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
Loading…
Reference in New Issue
Block a user