Compare commits

..
Author SHA1 Message Date
Bavisetti NarayanandGitHub b8d3b3c5eb fix: module percentage calculation (#8595) 2026-01-29 14:48:43 +05:30
2 changed files with 28 additions and 57 deletions
+5 -5
View File
@@ -46,7 +46,7 @@ class WorkspaceModulesEndpoint(BaseAPIView):
)
.annotate(
completed_issues=Count(
"issue_module__issue__state__group",
"issue_module",
filter=Q(
issue_module__issue__state__group="completed",
issue_module__issue__archived_at__isnull=True,
@@ -58,7 +58,7 @@ class WorkspaceModulesEndpoint(BaseAPIView):
)
.annotate(
cancelled_issues=Count(
"issue_module__issue__state__group",
"issue_module",
filter=Q(
issue_module__issue__state__group="cancelled",
issue_module__issue__archived_at__isnull=True,
@@ -70,7 +70,7 @@ class WorkspaceModulesEndpoint(BaseAPIView):
)
.annotate(
started_issues=Count(
"issue_module__issue__state__group",
"issue_module",
filter=Q(
issue_module__issue__state__group="started",
issue_module__issue__archived_at__isnull=True,
@@ -82,7 +82,7 @@ class WorkspaceModulesEndpoint(BaseAPIView):
)
.annotate(
unstarted_issues=Count(
"issue_module__issue__state__group",
"issue_module",
filter=Q(
issue_module__issue__state__group="unstarted",
issue_module__issue__archived_at__isnull=True,
@@ -94,7 +94,7 @@ class WorkspaceModulesEndpoint(BaseAPIView):
)
.annotate(
backlog_issues=Count(
"issue_module__issue__state__group",
"issue_module",
filter=Q(
issue_module__issue__state__group="backlog",
issue_module__issue__archived_at__isnull=True,
@@ -1,25 +1,18 @@
/**
* SPDX-FileCopyrightText: 2023-present Plane Software, Inc.
* SPDX-License-Identifier: LicenseRef-Plane-Commercial
*
* Licensed under the Plane Commercial License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://plane.so/legals/eula
*
* DO NOT remove or modify this notice.
* NOTICE: Proprietary and confidential. Unauthorized use or distribution is prohibited.
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { useEffect, useRef, useState } from "react";
import type { FC } from "react";
import { useRef, useState } from "react";
import { observer } from "mobx-react";
import { useForm, Controller } from "react-hook-form";
// plane imports
import { EIssueCommentAccessSpecifier } from "@plane/constants";
import type { EditorRefApi } from "@plane/editor";
import { useLocalStorage } from "@plane/hooks";
import type { TIssueComment, TCommentsOperations } from "@plane/types";
import { isCommentEmpty } from "@plane/utils";
import { cn, isCommentEmpty } from "@plane/utils";
// components
import { LiteTextEditor } from "@/components/editor/lite-text";
// hooks
@@ -58,21 +51,16 @@ export const CommentCreate = observer(function CommentCreate(props: TCommentCrea
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug)?.id as string;
// form info
const {
getValues,
handleSubmit,
control,
watch,
formState: { isSubmitting },
reset,
watch,
} = useForm<Partial<TIssueComment>>();
// local storage
const commentId = "add_comment_" + entityId;
const { storedValue: storedCommentDescription, setValue: setStoredCommentDescription } = useLocalStorage<
string | undefined
>(commentId, undefined);
// derived form values
const commentHTML = watch("comment_html");
const isEmpty = isCommentEmpty(commentHTML);
} = useForm<Partial<TIssueComment>>({
defaultValues: {
comment_html: "<p></p>",
},
});
const onSubmit = async (formData: Partial<TIssueComment>) => {
try {
@@ -90,40 +78,22 @@ export const CommentCreate = observer(function CommentCreate(props: TCommentCrea
}
setUploadedAssetIds([]);
}
setStoredCommentDescription(undefined);
} catch (error) {
console.error(error);
} finally {
reset({
comment_html: "",
comment_html: "<p></p>",
});
editorRef.current?.clearEditor();
}
};
// auto save comment description to local storage on unmount and page reload/close
useEffect(() => {
const saveCommentToLocalStorage = () => {
const latestDescription = getValues("comment_html");
const isLatestDescriptionEmpty = isCommentEmpty(latestDescription);
if (latestDescription && !isLatestDescriptionEmpty) {
setStoredCommentDescription(latestDescription);
}
};
window.addEventListener("beforeunload", saveCommentToLocalStorage);
return () => {
saveCommentToLocalStorage();
window.removeEventListener("beforeunload", saveCommentToLocalStorage);
};
// react-hook-form methods should not be included in the dependency array
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [setStoredCommentDescription]);
const commentHTML = watch("comment_html");
const isEmpty = isCommentEmpty(commentHTML ?? undefined);
return (
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<div
className="sticky sm:static bottom-0 z-4 bg-surface-1"
className={cn("sticky bottom-0 z-[4] bg-surface-1 sm:static")}
onKeyDown={(e) => {
if (
e.key === "Enter" &&
@@ -134,7 +104,7 @@ export const CommentCreate = observer(function CommentCreate(props: TCommentCrea
!isSubmitting &&
editorRef.current?.isEditorReadyToDiscard()
)
void handleSubmit(onSubmit)(e);
handleSubmit(onSubmit)(e);
}}
>
<Controller
@@ -144,22 +114,23 @@ export const CommentCreate = observer(function CommentCreate(props: TCommentCrea
<Controller
name="comment_html"
control={control}
render={({ field: { onChange } }) => (
render={({ field: { value, onChange } }) => (
<LiteTextEditor
editable
workspaceId={workspaceId}
id={commentId}
id={"add_comment_" + entityId}
value={"<p></p>"}
workspaceSlug={workspaceSlug}
projectId={projectId}
onEnterKeyPress={(e) => {
if (!isEmpty && !isSubmitting) {
void handleSubmit(onSubmit)(e);
handleSubmit(onSubmit)(e);
}
}}
ref={editorRef}
initialValue={storedCommentDescription || "<p></p>"}
initialValue={value ?? "<p></p>"}
containerClassName="min-h-min"
onChange={(_comment_json, comment_html) => onChange(comment_html)}
onChange={(comment_json, comment_html) => onChange(comment_html)}
accessSpecifier={accessValue ?? EIssueCommentAccessSpecifier.INTERNAL}
handleAccessChange={onAccessChange}
isSubmitting={isSubmitting}