forked from github/plane
[WEB-926] fix: issue description component update handled in peek overview, issue detail, and inbox issues (#4159)
* fix: issue description mutation * fix: implemented same issue description logic for issue detail and inbox issue description * fix: fixed parent issue title dissapearing while loading the issue detail page * chore: code cleanup * chore: handled exception when issue in not available in issue detail in issue store --------- Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
This commit is contained in:
parent
c80638090f
commit
d0cb00f28a
@ -2,7 +2,7 @@ import { Dispatch, SetStateAction, useEffect, useMemo } from "react";
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
import { Loader, TOAST_TYPE, setToast } from "@plane/ui";
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { InboxIssueProperties } from "@/components/inbox/content";
|
import { InboxIssueProperties } from "@/components/inbox/content";
|
||||||
import {
|
import {
|
||||||
@ -13,7 +13,7 @@ import {
|
|||||||
TIssueOperations,
|
TIssueOperations,
|
||||||
} from "@/components/issues";
|
} from "@/components/issues";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useProjectInbox, useUser } from "@/hooks/store";
|
import { useEventTracker, useUser } from "@/hooks/store";
|
||||||
import useReloadConfirmations from "@/hooks/use-reload-confirmation";
|
import useReloadConfirmations from "@/hooks/use-reload-confirmation";
|
||||||
// store types
|
// store types
|
||||||
import { IInboxIssueStore } from "@/store/inbox/inbox-issue.store";
|
import { IInboxIssueStore } from "@/store/inbox/inbox-issue.store";
|
||||||
@ -32,7 +32,6 @@ export const InboxIssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
const { workspaceSlug, projectId, inboxIssue, is_editable, isSubmitting, setIsSubmitting } = props;
|
const { workspaceSlug, projectId, inboxIssue, is_editable, isSubmitting, setIsSubmitting } = props;
|
||||||
// hooks
|
// hooks
|
||||||
const { currentUser } = useUser();
|
const { currentUser } = useUser();
|
||||||
const { isLoading } = useProjectInbox();
|
|
||||||
const { setShowAlert } = useReloadConfirmations(isSubmitting === "submitting");
|
const { setShowAlert } = useReloadConfirmations(isSubmitting === "submitting");
|
||||||
const { captureIssueEvent } = useEventTracker();
|
const { captureIssueEvent } = useEventTracker();
|
||||||
|
|
||||||
@ -131,22 +130,16 @@ export const InboxIssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
value={issue.name}
|
value={issue.name}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{isLoading ? (
|
<IssueDescriptionInput
|
||||||
<Loader className="h-[150px] space-y-2 overflow-hidden rounded-md border border-custom-border-200 p-2 py-2">
|
workspaceSlug={workspaceSlug}
|
||||||
<Loader.Item width="100%" height="132px" />
|
projectId={issue.project_id}
|
||||||
</Loader>
|
issueId={issue.id}
|
||||||
) : (
|
value={issueDescription}
|
||||||
<IssueDescriptionInput
|
initialValue={issueDescription}
|
||||||
workspaceSlug={workspaceSlug}
|
disabled={!is_editable}
|
||||||
projectId={issue.project_id}
|
issueOperations={issueOperations}
|
||||||
issueId={issue.id}
|
setIsSubmitting={(value) => setIsSubmitting(value)}
|
||||||
value={issueDescription}
|
/>
|
||||||
initialValue={issueDescription}
|
|
||||||
disabled={!is_editable}
|
|
||||||
issueOperations={issueOperations}
|
|
||||||
setIsSubmitting={(value) => setIsSubmitting(value)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{currentUser && (
|
{currentUser && (
|
||||||
<IssueReaction
|
<IssueReaction
|
||||||
|
@ -25,6 +25,7 @@ export type IssueDescriptionInputProps = {
|
|||||||
export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = (props) => {
|
export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = (props) => {
|
||||||
const { workspaceSlug, projectId, issueId, value, initialValue, disabled, issueOperations, setIsSubmitting } = props;
|
const { workspaceSlug, projectId, issueId, value, initialValue, disabled, issueOperations, setIsSubmitting } = props;
|
||||||
// states
|
// states
|
||||||
|
const [localIssueId, setLocalIssueId] = useState(issueId);
|
||||||
const [descriptionHTML, setDescriptionHTML] = useState(value);
|
const [descriptionHTML, setDescriptionHTML] = useState(value);
|
||||||
// store hooks
|
// store hooks
|
||||||
const { mentionHighlights, mentionSuggestions } = useMention();
|
const { mentionHighlights, mentionSuggestions } = useMention();
|
||||||
@ -35,8 +36,14 @@ export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = (props) =>
|
|||||||
const workspaceId = getWorkspaceBySlug(workspaceSlug)?.id as string;
|
const workspaceId = getWorkspaceBySlug(workspaceSlug)?.id as string;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDescriptionHTML(value);
|
if (issueId !== localIssueId) {
|
||||||
}, [value]);
|
setDescriptionHTML(undefined);
|
||||||
|
setLocalIssueId(issueId);
|
||||||
|
} else {
|
||||||
|
setDescriptionHTML(value);
|
||||||
|
}
|
||||||
|
return () => setDescriptionHTML(undefined);
|
||||||
|
}, [issueId, localIssueId, value]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (debouncedValue && debouncedValue !== value) {
|
if (debouncedValue && debouncedValue !== value) {
|
||||||
|
@ -28,7 +28,6 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
const { workspaceSlug, projectId, issueId, issueOperations, is_editable } = props;
|
const { workspaceSlug, projectId, issueId, issueOperations, is_editable } = props;
|
||||||
// states
|
// states
|
||||||
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
|
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
|
||||||
const [issueDescription, setIssueDescription] = useState<string | undefined>(undefined);
|
|
||||||
// hooks
|
// hooks
|
||||||
const { currentUser } = useUser();
|
const { currentUser } = useUser();
|
||||||
const { projectStates } = useProjectState();
|
const { projectStates } = useProjectState();
|
||||||
@ -53,16 +52,12 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
const currentIssueState = projectStates?.find((s) => s.id === issue.state_id);
|
const currentIssueState = projectStates?.find((s) => s.id === issue.state_id);
|
||||||
|
|
||||||
useEffect(() => {
|
const issueDescription =
|
||||||
setIssueDescription(
|
issue.description_html !== undefined || issue.description_html !== null
|
||||||
issue.description_html !== undefined || issue.description_html !== null
|
? issue.description_html != ""
|
||||||
? issue.description_html != ""
|
? issue.description_html
|
||||||
? issue.description_html
|
: "<p></p>"
|
||||||
: "<p></p>"
|
: undefined;
|
||||||
: undefined
|
|
||||||
);
|
|
||||||
return () => setIssueDescription(undefined);
|
|
||||||
}, [issue.description_html]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -99,18 +94,16 @@ export const IssueMainContent: React.FC<Props> = observer((props) => {
|
|||||||
value={issue.name}
|
value={issue.name}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{issue?.description_html === issueDescription && (
|
<IssueDescriptionInput
|
||||||
<IssueDescriptionInput
|
workspaceSlug={workspaceSlug}
|
||||||
workspaceSlug={workspaceSlug}
|
projectId={issue.project_id}
|
||||||
projectId={issue.project_id}
|
issueId={issue.id}
|
||||||
issueId={issue.id}
|
value={issueDescription}
|
||||||
value={issueDescription}
|
initialValue={issueDescription}
|
||||||
initialValue={issueDescription}
|
disabled={!is_editable}
|
||||||
disabled={!is_editable}
|
issueOperations={issueOperations}
|
||||||
issueOperations={issueOperations}
|
setIsSubmitting={(value) => setIsSubmitting(value)}
|
||||||
setIsSubmitting={(value) => setIsSubmitting(value)}
|
/>
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{currentUser && (
|
{currentUser && (
|
||||||
<IssueReaction
|
<IssueReaction
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { MinusCircle } from "lucide-react";
|
import { MinusCircle } from "lucide-react";
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
@ -19,7 +20,7 @@ export type TIssueParentDetail = {
|
|||||||
issueOperations: TIssueOperations;
|
issueOperations: TIssueOperations;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IssueParentDetail: FC<TIssueParentDetail> = (props) => {
|
export const IssueParentDetail: FC<TIssueParentDetail> = observer((props) => {
|
||||||
const { workspaceSlug, projectId, issueId, issue, issueOperations } = props;
|
const { workspaceSlug, projectId, issueId, issue, issueOperations } = props;
|
||||||
// hooks
|
// hooks
|
||||||
const { issueMap } = useIssues();
|
const { issueMap } = useIssues();
|
||||||
@ -68,4 +69,4 @@ export const IssueParentDetail: FC<TIssueParentDetail> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -66,7 +66,6 @@ export class IssueStore implements IIssueStore {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let issue: TIssue;
|
let issue: TIssue;
|
||||||
let issuePayload: TIssue;
|
|
||||||
|
|
||||||
if (issueType === "ARCHIVED")
|
if (issueType === "ARCHIVED")
|
||||||
issue = await this.issueArchiveService.retrieveArchivedIssue(workspaceSlug, projectId, issueId, query);
|
issue = await this.issueArchiveService.retrieveArchivedIssue(workspaceSlug, projectId, issueId, query);
|
||||||
@ -76,7 +75,7 @@ export class IssueStore implements IIssueStore {
|
|||||||
|
|
||||||
if (!issue) throw new Error("Issue not found");
|
if (!issue) throw new Error("Issue not found");
|
||||||
|
|
||||||
issuePayload = {
|
const issuePayload: TIssue = {
|
||||||
id: issue?.id,
|
id: issue?.id,
|
||||||
sequence_id: issue?.sequence_id,
|
sequence_id: issue?.sequence_id,
|
||||||
name: issue?.name,
|
name: issue?.name,
|
||||||
@ -110,8 +109,10 @@ export class IssueStore implements IIssueStore {
|
|||||||
|
|
||||||
// store handlers from issue detail
|
// store handlers from issue detail
|
||||||
// parent
|
// parent
|
||||||
if (issue && issue?.parent && issue?.parent?.id)
|
if (issue && issue?.parent && issue?.parent?.id) {
|
||||||
this.rootIssueDetailStore.rootIssueStore.issues.addIssue([issue.parent]);
|
const parentIssue = await this.issueService.retrieve(workspaceSlug, projectId, issue?.parent?.id);
|
||||||
|
this.rootIssueDetailStore.rootIssueStore.issues.addIssue([parentIssue]);
|
||||||
|
}
|
||||||
// assignees
|
// assignees
|
||||||
// labels
|
// labels
|
||||||
// state
|
// state
|
||||||
@ -184,7 +185,7 @@ export class IssueStore implements IIssueStore {
|
|||||||
};
|
};
|
||||||
|
|
||||||
addModulesToIssue = async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => {
|
addModulesToIssue = async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => {
|
||||||
const _module = await this.rootIssueDetailStore.rootIssueStore.moduleIssues.addModulesToIssue(
|
const currentModule = await this.rootIssueDetailStore.rootIssueStore.moduleIssues.addModulesToIssue(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
issueId,
|
issueId,
|
||||||
@ -192,28 +193,28 @@ export class IssueStore implements IIssueStore {
|
|||||||
);
|
);
|
||||||
if (moduleIds && moduleIds.length > 0)
|
if (moduleIds && moduleIds.length > 0)
|
||||||
await this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
|
await this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
|
||||||
return _module;
|
return currentModule;
|
||||||
};
|
};
|
||||||
|
|
||||||
removeModulesFromIssue = async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => {
|
removeModulesFromIssue = async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => {
|
||||||
const _module = await this.rootIssueDetailStore.rootIssueStore.moduleIssues.removeModulesFromIssue(
|
const currentModule = await this.rootIssueDetailStore.rootIssueStore.moduleIssues.removeModulesFromIssue(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
issueId,
|
issueId,
|
||||||
moduleIds
|
moduleIds
|
||||||
);
|
);
|
||||||
await this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
|
await this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
|
||||||
return _module;
|
return currentModule;
|
||||||
};
|
};
|
||||||
|
|
||||||
removeIssueFromModule = async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
|
removeIssueFromModule = async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
|
||||||
const _module = await this.rootIssueDetailStore.rootIssueStore.moduleIssues.removeIssueFromModule(
|
const currentModule = await this.rootIssueDetailStore.rootIssueStore.moduleIssues.removeIssueFromModule(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
moduleId,
|
moduleId,
|
||||||
issueId
|
issueId
|
||||||
);
|
);
|
||||||
await this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
|
await this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
|
||||||
return _module;
|
return currentModule;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user