chore: Removing 'description_html' from Issue List (#3623)

* chore: removed issue description from issue list

* fix: issue description handling on peekoverview

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
This commit is contained in:
Bavisetti Narayan 2024-02-12 15:26:02 +05:30 committed by GitHub
parent 963d26ccda
commit 0fb43c6fc5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 77 additions and 50 deletions

View File

@ -68,6 +68,7 @@ from .issue import (
IssueRelationSerializer, IssueRelationSerializer,
RelatedIssueSerializer, RelatedIssueSerializer,
IssuePublicSerializer, IssuePublicSerializer,
IssueDetailSerializer,
) )
from .module import ( from .module import (

View File

@ -586,7 +586,6 @@ class IssueSerializer(DynamicBaseSerializer):
"id", "id",
"name", "name",
"state_id", "state_id",
"description_html",
"sort_order", "sort_order",
"completed_at", "completed_at",
"estimate_point", "estimate_point",
@ -618,6 +617,13 @@ class IssueSerializer(DynamicBaseSerializer):
return [module for module in obj.issue_module.values_list("module_id", flat=True)] return [module for module in obj.issue_module.values_list("module_id", flat=True)]
class IssueDetailSerializer(IssueSerializer):
description_html = serializers.CharField()
class Meta(IssueSerializer.Meta):
fields = IssueSerializer.Meta.fields + ['description_html']
class IssueLiteSerializer(DynamicBaseSerializer): class IssueLiteSerializer(DynamicBaseSerializer):
workspace_detail = WorkspaceLiteSerializer( workspace_detail = WorkspaceLiteSerializer(
read_only=True, source="workspace" read_only=True, source="workspace"

View File

@ -50,6 +50,7 @@ from plane.app.serializers import (
CommentReactionSerializer, CommentReactionSerializer,
IssueRelationSerializer, IssueRelationSerializer,
RelatedIssueSerializer, RelatedIssueSerializer,
IssueDetailSerializer,
) )
from plane.app.permissions import ( from plane.app.permissions import (
ProjectEntityPermission, ProjectEntityPermission,
@ -267,7 +268,7 @@ class IssueViewSet(WebhookMixin, BaseViewSet):
def retrieve(self, request, slug, project_id, pk=None): def retrieve(self, request, slug, project_id, pk=None):
issue = self.get_queryset().filter(pk=pk).first() issue = self.get_queryset().filter(pk=pk).first()
return Response( return Response(
IssueSerializer( IssueDetailSerializer(
issue, fields=self.fields, expand=self.expand issue, fields=self.fields, expand=self.expand
).data, ).data,
status=status.HTTP_200_OK, status=status.HTTP_200_OK,

View File

@ -4,7 +4,7 @@ import { Controller, useForm } from "react-hook-form";
import useReloadConfirmations from "hooks/use-reload-confirmation"; import useReloadConfirmations from "hooks/use-reload-confirmation";
import debounce from "lodash/debounce"; import debounce from "lodash/debounce";
// components // components
import { TextArea } from "@plane/ui"; import { Loader, TextArea } from "@plane/ui";
import { RichReadOnlyEditor, RichTextEditor } from "@plane/rich-text-editor"; import { RichReadOnlyEditor, RichTextEditor } from "@plane/rich-text-editor";
// types // types
import { TIssue } from "@plane/types"; import { TIssue } from "@plane/types";
@ -12,6 +12,8 @@ import { TIssueOperations } from "./issue-detail";
// services // services
import { FileService } from "services/file.service"; import { FileService } from "services/file.service";
import { useMention, useWorkspace } from "hooks/store"; import { useMention, useWorkspace } from "hooks/store";
import { observer } from "mobx-react";
import { isNil } from "lodash";
export interface IssueDescriptionFormValues { export interface IssueDescriptionFormValues {
name: string; name: string;
@ -36,7 +38,7 @@ export interface IssueDetailsProps {
const fileService = new FileService(); const fileService = new FileService();
export const IssueDescriptionForm: FC<IssueDetailsProps> = (props) => { export const IssueDescriptionForm: FC<IssueDetailsProps> = observer((props) => {
const { workspaceSlug, projectId, issueId, issue, issueOperations, disabled, isSubmitting, setIsSubmitting } = props; const { workspaceSlug, projectId, issueId, issue, issueOperations, disabled, isSubmitting, setIsSubmitting } = props;
const workspaceStore = useWorkspace(); const workspaceStore = useWorkspace();
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug)?.id as string; const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug)?.id as string;
@ -71,12 +73,20 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = (props) => {
// editor rerendering on every save // editor rerendering on every save
useEffect(() => { useEffect(() => {
if (issue.id) { if (issue.id) {
setLocalIssueDescription({ id: issue.id, description_html: issue.description_html });
setLocalTitleValue(issue.name); setLocalTitleValue(issue.name);
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [issue.id]); // TODO: verify the exhaustive-deps warning }, [issue.id]); // TODO: verify the exhaustive-deps warning
useEffect(() => {
if (issue.description_html) {
setLocalIssueDescription((state) => {
if (!isNil(state.description_html)) return state;
return { id: issue.id, description_html: issue.description_html };
});
}
}, [issue.description_html]);
const handleDescriptionFormSubmit = useCallback( const handleDescriptionFormSubmit = useCallback(
async (formData: Partial<TIssue>) => { async (formData: Partial<TIssue>) => {
if (!formData?.name || formData?.name.length === 0 || formData?.name.length > 255) return; if (!formData?.name || formData?.name.length === 0 || formData?.name.length > 255) return;
@ -167,6 +177,7 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = (props) => {
</div> </div>
<span>{errors.name ? errors.name.message : null}</span> <span>{errors.name ? errors.name.message : null}</span>
<div className="relative"> <div className="relative">
{issue.description_html ? (
<Controller <Controller
name="description_html" name="description_html"
control={control} control={control}
@ -202,7 +213,12 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = (props) => {
) )
} }
/> />
) : (
<Loader>
<Loader.Item height="150px" />
</Loader>
)}
</div> </div>
</div> </div>
); );
}; });

View File

@ -4,6 +4,7 @@ import { useIssueDetail, useProject, useUser } from "hooks/store";
// components // components
import { IssueDescriptionForm, TIssueOperations } from "components/issues"; import { IssueDescriptionForm, TIssueOperations } from "components/issues";
import { IssueReaction } from "../issue-detail/reactions"; import { IssueReaction } from "../issue-detail/reactions";
import { observer } from "mobx-react";
interface IPeekOverviewIssueDetails { interface IPeekOverviewIssueDetails {
workspaceSlug: string; workspaceSlug: string;
@ -15,7 +16,7 @@ interface IPeekOverviewIssueDetails {
setIsSubmitting: (value: "submitting" | "submitted" | "saved") => void; setIsSubmitting: (value: "submitting" | "submitted" | "saved") => void;
} }
export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = (props) => { export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = observer((props) => {
const { workspaceSlug, projectId, issueId, issueOperations, disabled, isSubmitting, setIsSubmitting } = props; const { workspaceSlug, projectId, issueId, issueOperations, disabled, isSubmitting, setIsSubmitting } = props;
// store hooks // store hooks
const { getProjectById } = useProject(); const { getProjectById } = useProject();
@ -23,6 +24,7 @@ export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = (props) =
const { const {
issue: { getIssueById }, issue: { getIssueById },
} = useIssueDetail(); } = useIssueDetail();
// derived values // derived values
const issue = getIssueById(issueId); const issue = getIssueById(issueId);
if (!issue) return <></>; if (!issue) return <></>;
@ -53,4 +55,4 @@ export const PeekOverviewIssueDetails: FC<IPeekOverviewIssueDetails> = (props) =
)} )}
</> </>
); );
}; });

View File

@ -4,6 +4,7 @@ import { IssueArchiveService, IssueService } from "services/issue";
// types // types
import { IIssueDetail } from "./root.store"; import { IIssueDetail } from "./root.store";
import { TIssue } from "@plane/types"; import { TIssue } from "@plane/types";
import { computedFn } from "mobx-utils";
export interface IIssueStoreActions { export interface IIssueStoreActions {
// actions // actions
@ -44,10 +45,10 @@ export class IssueStore implements IIssueStore {
} }
// helper methods // helper methods
getIssueById = (issueId: string) => { getIssueById = computedFn((issueId: string) => {
if (!issueId) return undefined; if (!issueId) return undefined;
return this.rootIssueDetailStore.rootIssueStore.issues.getIssueById(issueId) ?? undefined; return this.rootIssueDetailStore.rootIssueStore.issues.getIssueById(issueId) ?? undefined;
}; });
// actions // actions
fetchIssue = async (workspaceSlug: string, projectId: string, issueId: string, isArchived = false) => { fetchIssue = async (workspaceSlug: string, projectId: string, issueId: string, isArchived = false) => {
@ -63,12 +64,12 @@ export class IssueStore implements IIssueStore {
if (!issue) throw new Error("Issue not found"); if (!issue) throw new Error("Issue not found");
this.rootIssueDetailStore.rootIssueStore.issues.addIssue([issue]); this.rootIssueDetailStore.rootIssueStore.issues.addIssue([issue], true);
// 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]); this.rootIssueDetailStore.rootIssueStore.issues.addIssue([issue.parent]);
// assignees // assignees
// labels // labels
// state // state

View File

@ -10,7 +10,7 @@ export type IIssueStore = {
// observables // observables
issuesMap: Record<string, TIssue>; // Record defines issue_id as key and TIssue as value issuesMap: Record<string, TIssue>; // Record defines issue_id as key and TIssue as value
// actions // actions
addIssue(issues: TIssue[]): void; addIssue(issues: TIssue[], shouldReplace?: boolean): void;
updateIssue(issueId: string, issue: Partial<TIssue>): void; updateIssue(issueId: string, issue: Partial<TIssue>): void;
removeIssue(issueId: string): void; removeIssue(issueId: string): void;
// helper methods // helper methods
@ -39,11 +39,11 @@ export class IssueStore implements IIssueStore {
* @param {TIssue[]} issues * @param {TIssue[]} issues
* @returns {void} * @returns {void}
*/ */
addIssue = (issues: TIssue[]) => { addIssue = (issues: TIssue[], shouldReplace = false) => {
if (issues && issues.length <= 0) return; if (issues && issues.length <= 0) return;
runInAction(() => { runInAction(() => {
issues.forEach((issue) => { issues.forEach((issue) => {
if (!this.issuesMap[issue.id]) set(this.issuesMap, issue.id, issue); if (!this.issuesMap[issue.id] || shouldReplace) set(this.issuesMap, issue.id, issue);
}); });
}); });
}; };