forked from github/plane
chore: add auto generate description option to create issue modals (#672)
This commit is contained in:
parent
93ba04aebc
commit
61875722e4
@ -6,6 +6,10 @@ import { useRouter } from "next/router";
|
|||||||
|
|
||||||
// react-hook-form
|
// react-hook-form
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
// services
|
||||||
|
import aiService from "services/ai.service";
|
||||||
|
// hooks
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
// components
|
// components
|
||||||
import { GptAssistantModal } from "components/core";
|
import { GptAssistantModal } from "components/core";
|
||||||
import {
|
import {
|
||||||
@ -83,10 +87,13 @@ export const IssueForm: FC<IssueFormProps> = ({
|
|||||||
const [parentIssueListModalOpen, setParentIssueListModalOpen] = useState(false);
|
const [parentIssueListModalOpen, setParentIssueListModalOpen] = useState(false);
|
||||||
|
|
||||||
const [gptAssistantModal, setGptAssistantModal] = useState(false);
|
const [gptAssistantModal, setGptAssistantModal] = useState(false);
|
||||||
|
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
formState: { errors, isSubmitting },
|
formState: { errors, isSubmitting },
|
||||||
@ -102,6 +109,8 @@ export const IssueForm: FC<IssueFormProps> = ({
|
|||||||
reValidateMode: "onChange",
|
reValidateMode: "onChange",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const issueName = watch("name");
|
||||||
|
|
||||||
const handleTitleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
const handleTitleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
const value = e.target.value;
|
const value = e.target.value;
|
||||||
const similarIssue = issues?.find((i: IIssue) => cosineSimilarity(i.name, value) > 0.7);
|
const similarIssue = issues?.find((i: IIssue) => cosineSimilarity(i.name, value) > 0.7);
|
||||||
@ -126,6 +135,44 @@ export const IssueForm: FC<IssueFormProps> = ({
|
|||||||
setValue("description_html", `${watch("description_html")}<p>${response}</p>`);
|
setValue("description_html", `${watch("description_html")}<p>${response}</p>`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handelAutoGenerateDescription = async () => {
|
||||||
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
|
setIAmFeelingLucky(true);
|
||||||
|
|
||||||
|
aiService
|
||||||
|
.createGptTask(workspaceSlug as string, projectId as string, {
|
||||||
|
prompt: issueName,
|
||||||
|
task: "Generate a proper description for this issue in context of a project management software.",
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.response === "")
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message:
|
||||||
|
"Issue title isn't informative enough to generate the description. Please try with a different title.",
|
||||||
|
});
|
||||||
|
else handleAiAssistance(res.response_html);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (err.status === 429)
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message:
|
||||||
|
"You have reached the maximum number of requests of 50 requests per month per user.",
|
||||||
|
});
|
||||||
|
else
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Some error occurred. Please try again.",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.finally(() => setIAmFeelingLucky(false));
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFocus("name");
|
setFocus("name");
|
||||||
|
|
||||||
@ -245,10 +292,28 @@ export const IssueForm: FC<IssueFormProps> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="flex justify-end -mb-2 mr-2">
|
<div className="flex justify-end -mb-2">
|
||||||
|
{issueName && issueName !== "" && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="-mr-2 flex items-center gap-1 rounded px-1.5 py-1 text-xs hover:bg-gray-100"
|
className={`flex items-center gap-1 rounded px-1.5 py-1 text-xs hover:bg-gray-100 ${
|
||||||
|
iAmFeelingLucky ? "cursor-wait" : ""
|
||||||
|
}`}
|
||||||
|
onClick={handelAutoGenerateDescription}
|
||||||
|
disabled={iAmFeelingLucky}
|
||||||
|
>
|
||||||
|
{iAmFeelingLucky ? (
|
||||||
|
"Generating response..."
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<SparklesIcon className="h-4 w-4" />I{"'"}m feeling lucky
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="flex items-center gap-1 rounded px-1.5 py-1 text-xs hover:bg-gray-100"
|
||||||
onClick={() => setGptAssistantModal((prevData) => !prevData)}
|
onClick={() => setGptAssistantModal((prevData) => !prevData)}
|
||||||
>
|
>
|
||||||
<SparklesIcon className="h-4 w-4" />
|
<SparklesIcon className="h-4 w-4" />
|
||||||
|
Loading…
Reference in New Issue
Block a user