mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
[WEB-1177] fix: sub-issues count mutation. (#4516)
* [WEB-1177] fix: sub-issues count mutation. * chore: refactor sub_issues_count mutation logic. * fix: build errors.
This commit is contained in:
parent
8a960e269f
commit
709cd9dd6c
@ -67,8 +67,9 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||||||
!getIsIssuePeeked(issue.id) &&
|
!getIsIssuePeeked(issue.id) &&
|
||||||
setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id, nestingLevel: nestingLevel });
|
setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id, nestingLevel: nestingLevel });
|
||||||
|
|
||||||
const issue = issuesMap[issueId];
|
const issue = issuesMap[issueId];
|
||||||
const subIssues = subIssuesStore.subIssuesByIssueId(issueId);
|
const subIssuesCount = issue.sub_issues_count;
|
||||||
|
|
||||||
const { isMobile } = usePlatformOS();
|
const { isMobile } = usePlatformOS();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -97,8 +98,6 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||||||
|
|
||||||
const canEditIssueProperties = canEditProperties(issue.project_id);
|
const canEditIssueProperties = canEditProperties(issue.project_id);
|
||||||
const projectIdentifier = getProjectIdentifierById(issue.project_id);
|
const projectIdentifier = getProjectIdentifierById(issue.project_id);
|
||||||
// if sub issues have been fetched for the issue, use that for count or use issue's sub_issues_count
|
|
||||||
const subIssuesCount = subIssues ? subIssues.length : issue.sub_issues_count;
|
|
||||||
|
|
||||||
const paddingLeft = `${spacingLeft}px`;
|
const paddingLeft = `${spacingLeft}px`;
|
||||||
|
|
||||||
|
@ -2,10 +2,13 @@ import { useCallback, useMemo } from "react";
|
|||||||
import xor from "lodash/xor";
|
import xor from "lodash/xor";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
// icons
|
||||||
import { CalendarCheck2, CalendarClock, Layers, Link, Paperclip } from "lucide-react";
|
import { CalendarCheck2, CalendarClock, Layers, Link, Paperclip } from "lucide-react";
|
||||||
|
// types
|
||||||
import { TIssue, IIssueDisplayProperties, TIssuePriorities } from "@plane/types";
|
import { TIssue, IIssueDisplayProperties, TIssuePriorities } from "@plane/types";
|
||||||
// hooks
|
// ui
|
||||||
import { Tooltip } from "@plane/ui";
|
import { Tooltip } from "@plane/ui";
|
||||||
|
// components
|
||||||
import {
|
import {
|
||||||
DateDropdown,
|
DateDropdown,
|
||||||
EstimateDropdown,
|
EstimateDropdown,
|
||||||
@ -15,23 +18,19 @@ import {
|
|||||||
CycleDropdown,
|
CycleDropdown,
|
||||||
StateDropdown,
|
StateDropdown,
|
||||||
} from "@/components/dropdowns";
|
} from "@/components/dropdowns";
|
||||||
// helpers
|
|
||||||
|
|
||||||
// types
|
|
||||||
// constants
|
// constants
|
||||||
import { ISSUE_UPDATED } from "@/constants/event-tracker";
|
import { ISSUE_UPDATED } from "@/constants/event-tracker";
|
||||||
import { EIssuesStoreType } from "@/constants/issue";
|
import { EIssuesStoreType } from "@/constants/issue";
|
||||||
|
// helpers
|
||||||
import { cn } from "@/helpers/common.helper";
|
import { cn } from "@/helpers/common.helper";
|
||||||
import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper";
|
import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper";
|
||||||
import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper";
|
import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper";
|
||||||
|
// hooks
|
||||||
import { useEventTracker, useEstimate, useLabel, useIssues, useProjectState, useProject } from "@/hooks/store";
|
import { useEventTracker, useEstimate, useLabel, useIssues, useProjectState, useProject } from "@/hooks/store";
|
||||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||||
// components
|
// local components
|
||||||
import { IssuePropertyLabels } from "../properties/labels";
|
import { IssuePropertyLabels } from "../properties/labels";
|
||||||
import { WithDisplayPropertiesHOC } from "../properties/with-display-properties-HOC";
|
import { WithDisplayPropertiesHOC } from "../properties/with-display-properties-HOC";
|
||||||
// helpers
|
|
||||||
// types
|
|
||||||
// constants
|
|
||||||
|
|
||||||
export interface IIssueProperties {
|
export interface IIssueProperties {
|
||||||
issue: TIssue;
|
issue: TIssue;
|
||||||
@ -64,6 +63,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
const currentLayout = `${activeLayout} layout`;
|
const currentLayout = `${activeLayout} layout`;
|
||||||
// derived values
|
// derived values
|
||||||
const stateDetails = getStateById(issue.state_id);
|
const stateDetails = getStateById(issue.state_id);
|
||||||
|
const subIssueCount = issue.sub_issues_count;
|
||||||
|
|
||||||
const issueOperations = useMemo(
|
const issueOperations = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@ -414,24 +414,24 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
<WithDisplayPropertiesHOC
|
<WithDisplayPropertiesHOC
|
||||||
displayProperties={displayProperties}
|
displayProperties={displayProperties}
|
||||||
displayPropertyKey="sub_issue_count"
|
displayPropertyKey="sub_issue_count"
|
||||||
shouldRenderProperty={(properties) => !!properties.sub_issue_count && !!issue.sub_issues_count}
|
shouldRenderProperty={(properties) => !!properties.sub_issue_count && !!subIssueCount}
|
||||||
>
|
>
|
||||||
<Tooltip tooltipHeading="Sub-issues" tooltipContent={`${issue.sub_issues_count}`} isMobile={isMobile}>
|
<Tooltip tooltipHeading="Sub-issues" tooltipContent={`${subIssueCount}`} isMobile={isMobile}>
|
||||||
<div
|
<div
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (issue.sub_issues_count) redirectToIssueDetail();
|
if (subIssueCount) redirectToIssueDetail();
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-5 flex-shrink-0 items-center justify-center gap-2 overflow-hidden rounded border-[0.5px] border-custom-border-300 px-2.5 py-1",
|
"flex h-5 flex-shrink-0 items-center justify-center gap-2 overflow-hidden rounded border-[0.5px] border-custom-border-300 px-2.5 py-1",
|
||||||
{
|
{
|
||||||
"hover:bg-custom-background-80 cursor-pointer": issue.sub_issues_count,
|
"hover:bg-custom-background-80 cursor-pointer": subIssueCount,
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Layers className="h-3 w-3 flex-shrink-0" strokeWidth={2} />
|
<Layers className="h-3 w-3 flex-shrink-0" strokeWidth={2} />
|
||||||
<div className="text-xs">{issue.sub_issues_count}</div>
|
<div className="text-xs">{subIssueCount}</div>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</WithDisplayPropertiesHOC>
|
</WithDisplayPropertiesHOC>
|
||||||
|
@ -18,6 +18,8 @@ export const SpreadsheetSubIssueColumn: React.FC<Props> = observer((props: Props
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
// hooks
|
// hooks
|
||||||
const { workspaceSlug } = useAppRouter();
|
const { workspaceSlug } = useAppRouter();
|
||||||
|
// derived values
|
||||||
|
const subIssueCount = issue.sub_issues_count;
|
||||||
|
|
||||||
const redirectToIssueDetail = () => {
|
const redirectToIssueDetail = () => {
|
||||||
router.push({
|
router.push({
|
||||||
@ -30,15 +32,15 @@ export const SpreadsheetSubIssueColumn: React.FC<Props> = observer((props: Props
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onClick={issue?.sub_issues_count ? redirectToIssueDetail : () => {}}
|
onClick={subIssueCount ? redirectToIssueDetail : () => {}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 px-2.5 py-1 text-xs hover:bg-custom-background-80",
|
"flex h-11 w-full items-center border-b-[0.5px] border-custom-border-200 px-2.5 py-1 text-xs hover:bg-custom-background-80",
|
||||||
{
|
{
|
||||||
"cursor-pointer": issue?.sub_issues_count,
|
"cursor-pointer": subIssueCount,
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{issue?.sub_issues_count} {issue?.sub_issues_count === 1 ? "sub-issue" : "sub-issues"}
|
{subIssueCount} {subIssueCount === 1 ? "sub-issue" : "sub-issues"}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -170,7 +170,6 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
|
|||||||
const { subIssues: subIssuesStore, issue } = useIssueDetail();
|
const { subIssues: subIssuesStore, issue } = useIssueDetail();
|
||||||
|
|
||||||
const issueDetail = issue.getIssueById(issueId);
|
const issueDetail = issue.getIssueById(issueId);
|
||||||
const subIssues = subIssuesStore.subIssuesByIssueId(issueId);
|
|
||||||
|
|
||||||
const paddingLeft = `${spacingLeft}px`;
|
const paddingLeft = `${spacingLeft}px`;
|
||||||
|
|
||||||
@ -204,8 +203,7 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const disableUserActions = !canEditProperties(issueDetail.project_id);
|
const disableUserActions = !canEditProperties(issueDetail.project_id);
|
||||||
// if sub issues have been fetched for the issue, use that for count or use issue's sub_issues_count
|
const subIssuesCount = issueDetail.sub_issues_count;
|
||||||
const subIssuesCount = subIssues ? subIssues.length : issueDetail.sub_issues_count;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -59,6 +59,7 @@ export const IssueListItem: React.FC<ISubIssues> = observer((props) => {
|
|||||||
undefined;
|
undefined;
|
||||||
|
|
||||||
const subIssueHelpers = subIssueHelpersByIssueId(parentIssueId);
|
const subIssueHelpers = subIssueHelpersByIssueId(parentIssueId);
|
||||||
|
const subIssueCount = issue?.sub_issues_count || 0;
|
||||||
|
|
||||||
const handleIssuePeekOverview = (issue: TIssue) =>
|
const handleIssuePeekOverview = (issue: TIssue) =>
|
||||||
workspaceSlug &&
|
workspaceSlug &&
|
||||||
@ -77,7 +78,7 @@ export const IssueListItem: React.FC<ISubIssues> = observer((props) => {
|
|||||||
style={{ paddingLeft: `${spacingLeft}px` }}
|
style={{ paddingLeft: `${spacingLeft}px` }}
|
||||||
>
|
>
|
||||||
<div className="h-[22px] w-[22px] flex-shrink-0">
|
<div className="h-[22px] w-[22px] flex-shrink-0">
|
||||||
{issue?.sub_issues_count > 0 && (
|
{subIssueCount > 0 && (
|
||||||
<>
|
<>
|
||||||
{subIssueHelpers.preview_loader.includes(issue.id) ? (
|
{subIssueHelpers.preview_loader.includes(issue.id) ? (
|
||||||
<div className="flex h-full w-full cursor-not-allowed items-center justify-center rounded-sm bg-custom-background-80 transition-all">
|
<div className="flex h-full w-full cursor-not-allowed items-center justify-center rounded-sm bg-custom-background-80 transition-all">
|
||||||
@ -205,7 +206,7 @@ export const IssueListItem: React.FC<ISubIssues> = observer((props) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{subIssueHelpers.issue_visibility.includes(issueId) && issue.sub_issues_count && issue.sub_issues_count > 0 && (
|
{subIssueHelpers.issue_visibility.includes(issueId) && subIssueCount > 0 && (
|
||||||
<IssueList
|
<IssueList
|
||||||
workspaceSlug={workspaceSlug}
|
workspaceSlug={workspaceSlug}
|
||||||
projectId={issue.project_id}
|
projectId={issue.project_id}
|
||||||
|
@ -174,6 +174,13 @@ export class IssueSubIssuesStore implements IIssueSubIssuesStore {
|
|||||||
|
|
||||||
this.rootIssueDetailStore.rootIssueStore.issues.addIssue(subIssues);
|
this.rootIssueDetailStore.rootIssueStore.issues.addIssue(subIssues);
|
||||||
|
|
||||||
|
// update sub-issues_count of the parent issue
|
||||||
|
set(
|
||||||
|
this.rootIssueDetailStore.rootIssueStore.issues.issuesMap,
|
||||||
|
[parentIssueId, "sub_issues_count"],
|
||||||
|
this.subIssues[parentIssueId].length
|
||||||
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
@ -270,6 +277,12 @@ export class IssueSubIssuesStore implements IIssueSubIssuesStore {
|
|||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
pull(this.subIssues[parentIssueId], issueId);
|
pull(this.subIssues[parentIssueId], issueId);
|
||||||
|
// update sub-issues_count of the parent issue
|
||||||
|
set(
|
||||||
|
this.rootIssueDetailStore.rootIssueStore.issues.issuesMap,
|
||||||
|
[parentIssueId, "sub_issues_count"],
|
||||||
|
this.subIssues[parentIssueId].length
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -301,6 +314,12 @@ export class IssueSubIssuesStore implements IIssueSubIssuesStore {
|
|||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
pull(this.subIssues[parentIssueId], issueId);
|
pull(this.subIssues[parentIssueId], issueId);
|
||||||
|
// update sub-issues_count of the parent issue
|
||||||
|
set(
|
||||||
|
this.rootIssueDetailStore.rootIssueStore.issues.issuesMap,
|
||||||
|
[parentIssueId, "sub_issues_count"],
|
||||||
|
this.subIssues[parentIssueId].length
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user