forked from github/plane
fix: issue relation mutation and draft issue (#2340)
* fix: issue relation mutation and draft issue * fix: 'New Issue' in gantt view fix: emoji select going under * fix: profile page typo
This commit is contained in:
parent
d9bd07886f
commit
cecdf890de
@ -6,6 +6,7 @@ import { useRouter } from "next/router";
|
|||||||
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
||||||
import { Draggable } from "react-beautiful-dnd";
|
import { Draggable } from "react-beautiful-dnd";
|
||||||
// components
|
// components
|
||||||
|
import { CreateUpdateDraftIssueModal } from "components/issues";
|
||||||
import { BoardHeader, SingleBoardIssue, BoardInlineCreateIssueForm } from "components/core";
|
import { BoardHeader, SingleBoardIssue, BoardInlineCreateIssueForm } from "components/core";
|
||||||
// ui
|
// ui
|
||||||
import { CustomMenu } from "components/ui";
|
import { CustomMenu } from "components/ui";
|
||||||
@ -57,6 +58,7 @@ export const SingleBoard: React.FC<Props> = (props) => {
|
|||||||
const [isCollapsed, setIsCollapsed] = useState(true);
|
const [isCollapsed, setIsCollapsed] = useState(true);
|
||||||
|
|
||||||
const [isInlineCreateIssueFormOpen, setIsInlineCreateIssueFormOpen] = useState(false);
|
const [isInlineCreateIssueFormOpen, setIsInlineCreateIssueFormOpen] = useState(false);
|
||||||
|
const [isCreateDraftIssueModalOpen, setIsCreateDraftIssueModalOpen] = useState(false);
|
||||||
|
|
||||||
const { displayFilters, groupedIssues } = viewProps;
|
const { displayFilters, groupedIssues } = viewProps;
|
||||||
|
|
||||||
@ -96,10 +98,27 @@ export const SingleBoard: React.FC<Props> = (props) => {
|
|||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAddIssueToGroup = () => {
|
||||||
|
if (isDraftIssuesPage) setIsCreateDraftIssueModalOpen(true);
|
||||||
|
else if (isMyIssuesPage || isProfileIssuesPage) addIssueToGroup();
|
||||||
|
else onCreateClick();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`flex-shrink-0 ${!isCollapsed ? "" : "flex h-full flex-col w-96"}`}>
|
<div className={`flex-shrink-0 ${!isCollapsed ? "" : "flex h-full flex-col w-96"}`}>
|
||||||
|
<CreateUpdateDraftIssueModal
|
||||||
|
isOpen={isCreateDraftIssueModalOpen}
|
||||||
|
handleClose={() => setIsCreateDraftIssueModalOpen(false)}
|
||||||
|
prePopulateData={{
|
||||||
|
...(cycleId && { cycle: cycleId.toString() }),
|
||||||
|
...(moduleId && { module: moduleId.toString() }),
|
||||||
|
[displayFilters?.group_by! === "labels" ? "labels_list" : displayFilters?.group_by!]:
|
||||||
|
displayFilters?.group_by === "labels" ? [groupTitle] : groupTitle,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
<BoardHeader
|
<BoardHeader
|
||||||
addIssueToGroup={addIssueToGroup}
|
addIssueToGroup={handleAddIssueToGroup}
|
||||||
currentState={currentState}
|
currentState={currentState}
|
||||||
groupTitle={groupTitle}
|
groupTitle={groupTitle}
|
||||||
isCollapsed={isCollapsed}
|
isCollapsed={isCollapsed}
|
||||||
@ -218,21 +237,22 @@ export const SingleBoard: React.FC<Props> = (props) => {
|
|||||||
{displayFilters?.group_by !== "created_by" && (
|
{displayFilters?.group_by !== "created_by" && (
|
||||||
<div>
|
<div>
|
||||||
{type === "issue"
|
{type === "issue"
|
||||||
? !disableAddIssueOption && (
|
? !disableAddIssueOption &&
|
||||||
|
!isDraftIssuesPage && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex items-center gap-2 font-medium text-custom-primary outline-none p-1"
|
className="flex items-center gap-2 font-medium text-custom-primary outline-none p-1"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isDraftIssuesPage || isMyIssuesPage || isProfileIssuesPage) {
|
if (isMyIssuesPage || isProfileIssuesPage) addIssueToGroup();
|
||||||
addIssueToGroup();
|
else onCreateClick();
|
||||||
} else onCreateClick();
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PlusIcon className="h-4 w-4" />
|
<PlusIcon className="h-4 w-4" />
|
||||||
Add Issue
|
Add Issue
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
: !disableUserActions && (
|
: !disableUserActions &&
|
||||||
|
!isDraftIssuesPage && (
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
customButton={
|
customButton={
|
||||||
<button
|
<button
|
||||||
@ -246,7 +266,13 @@ export const SingleBoard: React.FC<Props> = (props) => {
|
|||||||
position="left"
|
position="left"
|
||||||
noBorder
|
noBorder
|
||||||
>
|
>
|
||||||
<CustomMenu.MenuItem onClick={() => onCreateClick()}>
|
<CustomMenu.MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
if (isDraftIssuesPage) setIsCreateDraftIssueModalOpen(true);
|
||||||
|
else if (isMyIssuesPage || isProfileIssuesPage) addIssueToGroup();
|
||||||
|
else onCreateClick();
|
||||||
|
}}
|
||||||
|
>
|
||||||
Create new
|
Create new
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
{openIssuesListModal && (
|
{openIssuesListModal && (
|
||||||
|
@ -13,6 +13,7 @@ import projectService from "services/project.service";
|
|||||||
// hooks
|
// hooks
|
||||||
import useProjects from "hooks/use-projects";
|
import useProjects from "hooks/use-projects";
|
||||||
// components
|
// components
|
||||||
|
import { CreateUpdateDraftIssueModal } from "components/issues";
|
||||||
import { SingleListIssue, ListInlineCreateIssueForm } from "components/core";
|
import { SingleListIssue, ListInlineCreateIssueForm } from "components/core";
|
||||||
// ui
|
// ui
|
||||||
import { Avatar, CustomMenu } from "components/ui";
|
import { Avatar, CustomMenu } from "components/ui";
|
||||||
@ -75,6 +76,7 @@ export const SingleList: React.FC<Props> = (props) => {
|
|||||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||||
|
|
||||||
const [isCreateIssueFormOpen, setIsCreateIssueFormOpen] = useState(false);
|
const [isCreateIssueFormOpen, setIsCreateIssueFormOpen] = useState(false);
|
||||||
|
const [isDraftIssuesModalOpen, setIsDraftIssuesModalOpen] = useState(false);
|
||||||
|
|
||||||
const isMyIssuesPage = router.pathname.split("/")[3] === "my-issues";
|
const isMyIssuesPage = router.pathname.split("/")[3] === "my-issues";
|
||||||
const isProfileIssuesPage = router.pathname.split("/")[2] === "profile";
|
const isProfileIssuesPage = router.pathname.split("/")[2] === "profile";
|
||||||
@ -208,6 +210,18 @@ export const SingleList: React.FC<Props> = (props) => {
|
|||||||
if (!groupedIssues) return null;
|
if (!groupedIssues) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<CreateUpdateDraftIssueModal
|
||||||
|
isOpen={isDraftIssuesModalOpen}
|
||||||
|
handleClose={() => setIsDraftIssuesModalOpen(false)}
|
||||||
|
prePopulateData={{
|
||||||
|
...(cycleId && { cycle: cycleId.toString() }),
|
||||||
|
...(moduleId && { module: moduleId.toString() }),
|
||||||
|
[displayFilters?.group_by! === "labels" ? "labels_list" : displayFilters?.group_by!]:
|
||||||
|
displayFilters?.group_by === "labels" ? [groupTitle] : groupTitle,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
<Disclosure as="div" defaultOpen>
|
<Disclosure as="div" defaultOpen>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<div>
|
<div>
|
||||||
@ -241,9 +255,9 @@ export const SingleList: React.FC<Props> = (props) => {
|
|||||||
type="button"
|
type="button"
|
||||||
className="p-1 text-custom-text-200 hover:bg-custom-background-80"
|
className="p-1 text-custom-text-200 hover:bg-custom-background-80"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isDraftIssuesPage || isMyIssuesPage || isProfileIssuesPage) {
|
if (isDraftIssuesPage) setIsDraftIssuesModalOpen(true);
|
||||||
addIssueToGroup();
|
else if (isMyIssuesPage || isProfileIssuesPage) addIssueToGroup();
|
||||||
} else setIsCreateIssueFormOpen(true);
|
else setIsCreateIssueFormOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PlusIcon className="h-4 w-4" />
|
<PlusIcon className="h-4 w-4" />
|
||||||
@ -331,19 +345,21 @@ export const SingleList: React.FC<Props> = (props) => {
|
|||||||
prePopulatedData={{
|
prePopulatedData={{
|
||||||
...(cycleId && { cycle: cycleId.toString() }),
|
...(cycleId && { cycle: cycleId.toString() }),
|
||||||
...(moduleId && { module: moduleId.toString() }),
|
...(moduleId && { module: moduleId.toString() }),
|
||||||
[displayFilters?.group_by!]: groupTitle,
|
[displayFilters?.group_by! === "labels"
|
||||||
|
? "labels_list"
|
||||||
|
: displayFilters?.group_by!]:
|
||||||
|
displayFilters?.group_by === "labels" ? [groupTitle] : groupTitle,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!disableAddIssueOption && !isCreateIssueFormOpen && (
|
{!disableAddIssueOption && !isCreateIssueFormOpen && !isDraftIssuesPage && (
|
||||||
// TODO: add border here
|
|
||||||
<div className="w-full bg-custom-background-100 px-6 py-3 border-b border-custom-border-100">
|
<div className="w-full bg-custom-background-100 px-6 py-3 border-b border-custom-border-100">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isDraftIssuesPage || isMyIssuesPage || isProfileIssuesPage) {
|
if (isDraftIssuesPage) setIsDraftIssuesModalOpen(true);
|
||||||
addIssueToGroup();
|
else if (isMyIssuesPage || isProfileIssuesPage) addIssueToGroup();
|
||||||
} else setIsCreateIssueFormOpen(true);
|
else setIsCreateIssueFormOpen(true);
|
||||||
}}
|
}}
|
||||||
className="flex items-center gap-x-[6px] text-custom-primary-100 px-2 py-1 rounded-md"
|
className="flex items-center gap-x-[6px] text-custom-primary-100 px-2 py-1 rounded-md"
|
||||||
>
|
>
|
||||||
@ -357,5 +373,6 @@ export const SingleList: React.FC<Props> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Disclosure>
|
</Disclosure>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@ import { Tab, Transition, Popover } from "@headlessui/react";
|
|||||||
// react colors
|
// react colors
|
||||||
import { TwitterPicker } from "react-color";
|
import { TwitterPicker } from "react-color";
|
||||||
// hooks
|
// hooks
|
||||||
|
import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown";
|
||||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||||
// types
|
// types
|
||||||
import { Props } from "./types";
|
import { Props } from "./types";
|
||||||
@ -38,6 +39,7 @@ const EmojiIconPicker: React.FC<Props> = ({
|
|||||||
|
|
||||||
const [recentEmojis, setRecentEmojis] = useState<string[]>([]);
|
const [recentEmojis, setRecentEmojis] = useState<string[]>([]);
|
||||||
|
|
||||||
|
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||||
const emojiPickerRef = useRef<HTMLDivElement>(null);
|
const emojiPickerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -49,10 +51,12 @@ const EmojiIconPicker: React.FC<Props> = ({
|
|||||||
}, [value, onChange]);
|
}, [value, onChange]);
|
||||||
|
|
||||||
useOutsideClickDetector(emojiPickerRef, () => setIsOpen(false));
|
useOutsideClickDetector(emojiPickerRef, () => setIsOpen(false));
|
||||||
|
useDynamicDropdownPosition(isOpen, () => setIsOpen(false), buttonRef, emojiPickerRef);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover className="relative z-[1]">
|
<Popover className="relative z-[1]">
|
||||||
<Popover.Button
|
<Popover.Button
|
||||||
|
ref={buttonRef}
|
||||||
onClick={() => setIsOpen((prev) => !prev)}
|
onClick={() => setIsOpen((prev) => !prev)}
|
||||||
className="outline-none"
|
className="outline-none"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
@ -61,6 +65,8 @@ const EmojiIconPicker: React.FC<Props> = ({
|
|||||||
</Popover.Button>
|
</Popover.Button>
|
||||||
<Transition
|
<Transition
|
||||||
show={isOpen}
|
show={isOpen}
|
||||||
|
static
|
||||||
|
as={React.Fragment}
|
||||||
enter="transition ease-out duration-100"
|
enter="transition ease-out duration-100"
|
||||||
enterFrom="transform opacity-0 scale-95"
|
enterFrom="transform opacity-0 scale-95"
|
||||||
enterTo="transform opacity-100 scale-100"
|
enterTo="transform opacity-100 scale-100"
|
||||||
@ -68,11 +74,11 @@ const EmojiIconPicker: React.FC<Props> = ({
|
|||||||
leaveFrom="transform opacity-100 scale-100"
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
leaveTo="transform opacity-0 scale-95"
|
leaveTo="transform opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<Popover.Panel className="absolute z-10 mt-2 w-[250px] rounded-[4px] border border-custom-border-200 bg-custom-background-80 shadow-lg">
|
<Popover.Panel
|
||||||
<div
|
|
||||||
ref={emojiPickerRef}
|
ref={emojiPickerRef}
|
||||||
className="h-[230px] w-[250px] overflow-auto rounded-[4px] border border-custom-border-200 bg-custom-background-80 p-2 shadow-xl"
|
className="fixed z-10 mt-2 w-[250px] rounded-[4px] border border-custom-border-200 bg-custom-background-80 shadow-lg"
|
||||||
>
|
>
|
||||||
|
<div className="h-[230px] w-[250px] overflow-auto rounded-[4px] border border-custom-border-200 bg-custom-background-80 p-2 shadow-xl">
|
||||||
<Tab.Group as="div" className="flex h-full w-full flex-col">
|
<Tab.Group as="div" className="flex h-full w-full flex-col">
|
||||||
<Tab.List className="flex-0 -mx-2 flex justify-around gap-1 p-1">
|
<Tab.List className="flex-0 -mx-2 flex justify-around gap-1 p-1">
|
||||||
{tabOptions.map((tab) => (
|
{tabOptions.map((tab) => (
|
||||||
|
@ -80,6 +80,9 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { cycleId, moduleId } = router.query;
|
const { cycleId, moduleId } = router.query;
|
||||||
|
|
||||||
|
const isCyclePage = router.pathname.split("/")[4] === "cycles" && !cycleId;
|
||||||
|
const isModulePage = router.pathname.split("/")[4] === "modules" && !moduleId;
|
||||||
|
|
||||||
const renderBlockStructure = (view: any, blocks: IGanttBlock[] | null) =>
|
const renderBlockStructure = (view: any, blocks: IGanttBlock[] | null) =>
|
||||||
blocks && blocks.length > 0
|
blocks && blocks.length > 0
|
||||||
? blocks.map((block: any) => ({
|
? blocks.map((block: any) => ({
|
||||||
@ -317,7 +320,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = ({
|
|||||||
SidebarBlockRender={SidebarBlockRender}
|
SidebarBlockRender={SidebarBlockRender}
|
||||||
enableReorder={enableReorder}
|
enableReorder={enableReorder}
|
||||||
/>
|
/>
|
||||||
{chartBlocks && (
|
{chartBlocks && !(isCyclePage || isModulePage) && (
|
||||||
<div className="pl-2.5 py-3">
|
<div className="pl-2.5 py-3">
|
||||||
<GanttInlineCreateIssueForm
|
<GanttInlineCreateIssueForm
|
||||||
isOpen={isCreateIssueFormOpen}
|
isOpen={isCreateIssueFormOpen}
|
||||||
|
@ -8,6 +8,7 @@ import { Controller, useForm } from "react-hook-form";
|
|||||||
import aiService from "services/ai.service";
|
import aiService from "services/ai.service";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
|
import useLocalStorage from "hooks/use-local-storage";
|
||||||
// components
|
// components
|
||||||
import { GptAssistantModal } from "components/core";
|
import { GptAssistantModal } from "components/core";
|
||||||
import { ParentIssuesListModal } from "components/issues";
|
import { ParentIssuesListModal } from "components/issues";
|
||||||
@ -60,6 +61,7 @@ interface IssueFormProps {
|
|||||||
action?: "createDraft" | "createNewIssue" | "updateDraft" | "convertToNewIssue"
|
action?: "createDraft" | "createNewIssue" | "updateDraft" | "convertToNewIssue"
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
data?: Partial<IIssue> | null;
|
data?: Partial<IIssue> | null;
|
||||||
|
isOpen: boolean;
|
||||||
prePopulatedData?: Partial<IIssue> | null;
|
prePopulatedData?: Partial<IIssue> | null;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
setActiveProject: React.Dispatch<React.SetStateAction<string | null>>;
|
setActiveProject: React.Dispatch<React.SetStateAction<string | null>>;
|
||||||
@ -89,6 +91,7 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
const {
|
const {
|
||||||
handleFormSubmit,
|
handleFormSubmit,
|
||||||
data,
|
data,
|
||||||
|
isOpen,
|
||||||
prePopulatedData,
|
prePopulatedData,
|
||||||
projectId,
|
projectId,
|
||||||
setActiveProject,
|
setActiveProject,
|
||||||
@ -109,6 +112,8 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
const [gptAssistantModal, setGptAssistantModal] = useState(false);
|
const [gptAssistantModal, setGptAssistantModal] = useState(false);
|
||||||
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
||||||
|
|
||||||
|
const { setValue: setLocalStorageValue } = useLocalStorage("draftedIssue", {});
|
||||||
|
|
||||||
const editorRef = useRef<any>(null);
|
const editorRef = useRef<any>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -133,6 +138,33 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
|
|
||||||
const issueName = watch("name");
|
const issueName = watch("name");
|
||||||
|
|
||||||
|
const payload: Partial<IIssue> = {
|
||||||
|
name: watch("name"),
|
||||||
|
description: watch("description"),
|
||||||
|
description_html: watch("description_html"),
|
||||||
|
state: watch("state"),
|
||||||
|
priority: watch("priority"),
|
||||||
|
assignees: watch("assignees"),
|
||||||
|
labels: watch("labels"),
|
||||||
|
start_date: watch("start_date"),
|
||||||
|
target_date: watch("target_date"),
|
||||||
|
project: watch("project"),
|
||||||
|
parent: watch("parent"),
|
||||||
|
cycle: watch("cycle"),
|
||||||
|
module: watch("module"),
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isOpen || data) return;
|
||||||
|
|
||||||
|
setLocalStorageValue(
|
||||||
|
JSON.stringify({
|
||||||
|
...payload,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [JSON.stringify(payload), isOpen, data]);
|
||||||
|
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
handleClose();
|
handleClose();
|
||||||
};
|
};
|
||||||
@ -273,7 +305,7 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
)}
|
)}
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit((formData) =>
|
onSubmit={handleSubmit((formData) =>
|
||||||
handleCreateUpdateIssue(formData, "convertToNewIssue")
|
handleCreateUpdateIssue(formData, data ? "convertToNewIssue" : "createDraft")
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
|
@ -385,6 +385,7 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = (props) =
|
|||||||
>
|
>
|
||||||
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-200 bg-custom-background-100 p-5 text-left shadow-xl transition-all sm:w-full sm:max-w-2xl">
|
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-200 bg-custom-background-100 p-5 text-left shadow-xl transition-all sm:w-full sm:max-w-2xl">
|
||||||
<DraftIssueForm
|
<DraftIssueForm
|
||||||
|
isOpen={isOpen}
|
||||||
handleFormSubmit={handleFormSubmit}
|
handleFormSubmit={handleFormSubmit}
|
||||||
prePopulatedData={prePopulateData}
|
prePopulatedData={prePopulateData}
|
||||||
data={data}
|
data={data}
|
||||||
|
@ -129,18 +129,19 @@ export const IssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
const issueName = watch("name");
|
const issueName = watch("name");
|
||||||
|
|
||||||
const payload: Partial<IIssue> = {
|
const payload: Partial<IIssue> = {
|
||||||
name: getValues("name"),
|
name: watch("name"),
|
||||||
description: getValues("description"),
|
description: watch("description"),
|
||||||
state: getValues("state"),
|
description_html: watch("description_html"),
|
||||||
priority: getValues("priority"),
|
state: watch("state"),
|
||||||
assignees: getValues("assignees"),
|
priority: watch("priority"),
|
||||||
labels: getValues("labels"),
|
assignees: watch("assignees"),
|
||||||
start_date: getValues("start_date"),
|
labels: watch("labels"),
|
||||||
target_date: getValues("target_date"),
|
start_date: watch("start_date"),
|
||||||
project: getValues("project"),
|
target_date: watch("target_date"),
|
||||||
parent: getValues("parent"),
|
project: watch("project"),
|
||||||
cycle: getValues("cycle"),
|
parent: watch("parent"),
|
||||||
module: getValues("module"),
|
cycle: watch("cycle"),
|
||||||
|
module: watch("module"),
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -14,7 +14,7 @@ import { ExistingIssuesListModal } from "components/core";
|
|||||||
import { XMarkIcon } from "@heroicons/react/24/outline";
|
import { XMarkIcon } from "@heroicons/react/24/outline";
|
||||||
import { BlockedIcon } from "components/icons";
|
import { BlockedIcon } from "components/icons";
|
||||||
// types
|
// types
|
||||||
import { BlockeIssueDetail, IIssue, ISearchIssueResponse, UserAuth } from "types";
|
import { BlockeIssueDetail, IIssue, ISearchIssueResponse } from "types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issueId?: string;
|
issueId?: string;
|
||||||
@ -41,6 +41,9 @@ export const SidebarBlockedSelect: React.FC<Props> = ({
|
|||||||
setIsBlockedModalOpen(false);
|
setIsBlockedModalOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const blockedByIssue =
|
||||||
|
watch("related_issues")?.filter((i) => i.relation_type === "blocked_by") || [];
|
||||||
|
|
||||||
const onSubmit = async (data: ISearchIssueResponse[]) => {
|
const onSubmit = async (data: ISearchIssueResponse[]) => {
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -80,18 +83,13 @@ export const SidebarBlockedSelect: React.FC<Props> = ({
|
|||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
submitChanges({
|
submitChanges({
|
||||||
related_issues: [
|
related_issues: [...watch("related_issues"), ...response],
|
||||||
...watch("related_issues")?.filter((i) => i.relation_type !== "blocked_by"),
|
|
||||||
...response,
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
const blockedByIssue = watch("related_issues")?.filter((i) => i.relation_type === "blocked_by");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ExistingIssuesListModal
|
<ExistingIssuesListModal
|
||||||
|
@ -15,7 +15,7 @@ import issuesService from "services/issues.service";
|
|||||||
import { XMarkIcon } from "@heroicons/react/24/outline";
|
import { XMarkIcon } from "@heroicons/react/24/outline";
|
||||||
import { BlockerIcon } from "components/icons";
|
import { BlockerIcon } from "components/icons";
|
||||||
// types
|
// types
|
||||||
import { BlockeIssueDetail, IIssue, ISearchIssueResponse, UserAuth } from "types";
|
import { BlockeIssueDetail, IIssue, ISearchIssueResponse } from "types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issueId?: string;
|
issueId?: string;
|
||||||
|
@ -75,10 +75,8 @@ export const SidebarDuplicateSelect: React.FC<Props> = (props) => {
|
|||||||
})),
|
})),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then(() => {
|
||||||
submitChanges({
|
submitChanges();
|
||||||
related_issues: [...watch("related_issues"), ...(response ?? [])],
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
|
@ -75,10 +75,8 @@ export const SidebarRelatesSelect: React.FC<Props> = (props) => {
|
|||||||
})),
|
})),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then(() => {
|
||||||
submitChanges({
|
submitChanges();
|
||||||
related_issues: [...watch("related_issues"), ...(response ?? [])],
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
|
@ -53,7 +53,7 @@ import { copyTextToClipboard } from "helpers/string.helper";
|
|||||||
// types
|
// types
|
||||||
import type { ICycle, IIssue, IIssueLink, linkDetails, IModule } from "types";
|
import type { ICycle, IIssue, IIssueLink, linkDetails, IModule } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { ISSUE_DETAILS } from "constants/fetch-keys";
|
import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
|
||||||
import { ContrastIcon } from "components/icons";
|
import { ContrastIcon } from "components/icons";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -480,6 +480,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
||||||
}}
|
}}
|
||||||
watch={watchIssue}
|
watch={watchIssue}
|
||||||
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
|
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
|
||||||
@ -500,6 +501,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
||||||
}}
|
}}
|
||||||
watch={watchIssue}
|
watch={watchIssue}
|
||||||
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
|
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
|
||||||
@ -517,6 +519,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
...data,
|
...data,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
||||||
}}
|
}}
|
||||||
watch={watchIssue}
|
watch={watchIssue}
|
||||||
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
|
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
|
||||||
@ -534,6 +537,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
...data,
|
...data,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
mutate(PROJECT_ISSUES_ACTIVITY(issueId as string));
|
||||||
}}
|
}}
|
||||||
watch={watchIssue}
|
watch={watchIssue}
|
||||||
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
|
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
|
||||||
|
@ -375,7 +375,7 @@ const Profile: NextPage = () => {
|
|||||||
|
|
||||||
<div className="flex items-center justify-between py-2">
|
<div className="flex items-center justify-between py-2">
|
||||||
<PrimaryButton type="submit" loading={isSubmitting}>
|
<PrimaryButton type="submit" loading={isSubmitting}>
|
||||||
{isSubmitting ? "Updating Project..." : "Update Project"}
|
{isSubmitting ? "Updating Profile..." : "Update Profile"}
|
||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user