[WEB-3712] improvement: create draft work item logic (#6847)

This commit is contained in:
Prateek Shourya
2025-04-01 20:47:44 +05:30
committed by GitHub
parent 4be94adaca
commit 7bb291408d
5 changed files with 66 additions and 34 deletions

View File

@@ -1,18 +1,15 @@
import React, { useRef, useState } from "react";
import { usePopper } from "react-popper";
import { Combobox } from "@headlessui/react";
import { Check, ChevronDown, Info, Search } from "lucide-react";
import React, { useRef, useState } from "react";
import { createPortal } from "react-dom";
// plane helpers
import { usePopper } from "react-popper";
// plane imports
import { useOutsideClickDetector } from "@plane/hooks";
// hooks
import { useDropdownKeyDown } from "../hooks/use-dropdown-key-down";
// helpers
// local imports
import { cn } from "../../helpers";
// types
import { ICustomSearchSelectProps } from "./helper";
// local components
import { useDropdownKeyDown } from "../hooks/use-dropdown-key-down";
import { Tooltip } from "../tooltip";
import { ICustomSearchSelectProps } from "./helper";
export const CustomSearchSelect = (props: ICustomSearchSelectProps) => {
const {
@@ -36,6 +33,7 @@ export const CustomSearchSelect = (props: ICustomSearchSelectProps) => {
optionsClassName = "",
value,
tabIndex,
noResultsMessage = "No matches found",
} = props;
const [query, setQuery] = useState("");
@@ -201,7 +199,7 @@ export const CustomSearchSelect = (props: ICustomSearchSelectProps) => {
</Combobox.Option>
))
) : (
<p className="text-custom-text-400 italic py-1 px-1.5">No matches found</p>
<p className="text-custom-text-400 italic py-1 px-1.5">{noResultsMessage}</p>
)
) : (
<p className="text-custom-text-400 italic py-1 px-1.5">Loading...</p>

View File

@@ -43,6 +43,7 @@ interface CustomSearchSelectProps {
footerOption?: JSX.Element;
onChange: any;
onClose?: () => void;
noResultsMessage?: string;
options:
| {
value: any;

View File

@@ -8,6 +8,7 @@ export type TWorkItemTemplateSelect = {
placeholder?: string;
renderChevron?: boolean;
dropDownContainerClassName?: string;
handleModalClose: () => void;
handleFormChange?: () => void;
};

View File

@@ -38,27 +38,34 @@ export const DraftIssueLayout: React.FC<DraftIssueProps> = observer((props) => {
const { createIssue } = useWorkspaceDraftIssues();
const { t } = useTranslation();
const sanitizeChanges = (): Partial<TIssue> => {
const sanitizedChanges = { ...changesMade };
Object.entries(sanitizedChanges).forEach(([key, value]) => {
const issueKey = key as keyof TIssue;
if (value === null || value === undefined || value === "") delete sanitizedChanges[issueKey];
if (typeof value === "object" && isEmpty(value)) delete sanitizedChanges[issueKey];
if (Array.isArray(value) && value.length === 0) delete sanitizedChanges[issueKey];
if (issueKey === "project_id") delete sanitizedChanges.project_id;
if (issueKey === "priority" && value && value === "none") delete sanitizedChanges.priority;
if (
issueKey === "description_html" &&
changesMade?.description_html &&
isEmptyHtmlString(changesMade.description_html, ["img"])
)
delete sanitizedChanges.description_html;
});
return sanitizedChanges;
};
const handleClose = () => {
// If the user is updating an existing work item, we don't need to show the discard modal
if (data?.id) {
onClose();
setIssueDiscardModal(false);
} else {
if (changesMade) {
Object.entries(changesMade).forEach(([key, value]) => {
const issueKey = key as keyof TIssue;
if (value === null || value === undefined || value === "") delete changesMade[issueKey];
if (typeof value === "object" && isEmpty(value)) delete changesMade[issueKey];
if (Array.isArray(value) && value.length === 0) delete changesMade[issueKey];
if (issueKey === "project_id") delete changesMade.project_id;
if (issueKey === "priority" && value && value === "none") delete changesMade.priority;
if (
issueKey === "description_html" &&
changesMade.description_html &&
isEmptyHtmlString(changesMade.description_html, ["img"])
)
delete changesMade.description_html;
});
if (isEmpty(changesMade)) {
const sanitizedChanges = sanitizeChanges();
if (isEmpty(sanitizedChanges)) {
onClose();
setIssueDiscardModal(false);
} else setIssueDiscardModal(true);
@@ -119,6 +126,14 @@ export const DraftIssueLayout: React.FC<DraftIssueProps> = observer((props) => {
}
};
const handleDraftAndClose = () => {
const sanitizedChanges = sanitizeChanges();
if (!data?.id && !isEmpty(sanitizedChanges)) {
handleCreateDraftIssue();
}
onClose();
};
return (
<>
<ConfirmIssueDiscard
@@ -131,7 +146,7 @@ export const DraftIssueLayout: React.FC<DraftIssueProps> = observer((props) => {
onClose();
}}
/>
<IssueFormRoot {...props} onClose={handleClose} />
<IssueFormRoot {...props} onClose={handleClose} handleDraftAndClose={handleDraftAndClose} />
</>
);
});

View File

@@ -61,6 +61,7 @@ export interface IssueFormProps {
};
isDuplicateModalOpen: boolean;
handleDuplicateIssueModal: (isOpen: boolean) => void;
handleDraftAndClose?: () => void;
isProjectSelectionDisabled?: boolean;
storeType: EIssuesStoreType;
}
@@ -86,6 +87,7 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
},
isDuplicateModalOpen,
handleDuplicateIssueModal,
handleDraftAndClose,
isProjectSelectionDisabled = false,
storeType,
} = props;
@@ -235,14 +237,22 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
await onSubmit(submitData, is_draft_issue)
.then(() => {
setGptAssistantModal(false);
reset({
...DEFAULT_WORK_ITEM_FORM_VALUES,
...(isCreateMoreToggleEnabled ? { ...data } : {}),
project_id: getValues<"project_id">("project_id"),
type_id: getValues<"type_id">("type_id"),
description_html: data?.description_html ?? "<p></p>",
});
editorRef?.current?.clearEditor();
if (isCreateMoreToggleEnabled && workItemTemplateId) {
handleTemplateChange({
workspaceSlug: workspaceSlug?.toString(),
reset,
editorRef,
});
} else {
reset({
...DEFAULT_WORK_ITEM_FORM_VALUES,
...(isCreateMoreToggleEnabled ? { ...data } : {}),
project_id: getValues<"project_id">("project_id"),
type_id: getValues<"type_id">("type_id"),
description_html: data?.description_html ?? "<p></p>",
});
editorRef?.current?.clearEditor();
}
})
.catch((error) => {
console.error(error);
@@ -389,6 +399,13 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
<WorkItemTemplateSelect
projectId={projectId}
typeId={watch("type_id")}
handleModalClose={() => {
if (handleDraftAndClose) {
handleDraftAndClose();
} else {
onClose();
}
}}
handleFormChange={handleFormChange}
renderChevron
/>