feat: completed cycle snapshot (#3600)
* fix: transfer cycle old distribtion captured * chore: active cycle snapshot * chore: migration file changed * chore: distribution payload changed * chore: labels and assignee structure change * chore: migration changes * chore: cycle snapshot progress payload updated * chore: cycle snapshot progress type added * chore: snapshot progress stats updated in cycle sidebar * chore: empty string validation --------- Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@plane.so>
This commit is contained in:
parent
e2affc3fa6
commit
27037a2177
6 changed files with 370 additions and 47 deletions
|
|
@ -3,6 +3,7 @@ import { useRouter } from "next/router";
|
|||
import { observer } from "mobx-react-lite";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { Disclosure, Popover, Transition } from "@headlessui/react";
|
||||
import isEmpty from "lodash/isEmpty";
|
||||
// services
|
||||
import { CycleService } from "services/cycle.service";
|
||||
// hooks
|
||||
|
|
@ -293,7 +294,11 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||
const isEndValid = new Date(`${cycleDetails?.end_date}`) >= new Date(`${cycleDetails?.start_date}`);
|
||||
|
||||
const progressPercentage = cycleDetails
|
||||
? Math.round((cycleDetails.completed_issues / cycleDetails.total_issues) * 100)
|
||||
? isCompleted
|
||||
? Math.round(
|
||||
(cycleDetails.progress_snapshot.completed_issues / cycleDetails.progress_snapshot.total_issues) * 100
|
||||
)
|
||||
: Math.round((cycleDetails.completed_issues / cycleDetails.total_issues) * 100)
|
||||
: null;
|
||||
|
||||
if (!cycleDetails)
|
||||
|
|
@ -317,7 +322,14 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||
const currentCycle = CYCLE_STATUS.find((status) => status.value === cycleStatus);
|
||||
|
||||
const issueCount =
|
||||
cycleDetails.total_issues === 0 ? "0 Issue" : `${cycleDetails.completed_issues}/${cycleDetails.total_issues}`;
|
||||
isCompleted && !isEmpty(cycleDetails.progress_snapshot)
|
||||
? cycleDetails.progress_snapshot.total_issues === 0
|
||||
? "0 Issue"
|
||||
: `${cycleDetails.progress_snapshot.completed_issues}/${cycleDetails.progress_snapshot.total_issues}`
|
||||
: cycleDetails.total_issues === 0
|
||||
? "0 Issue"
|
||||
: `${cycleDetails.completed_issues}/${cycleDetails.total_issues}`;
|
||||
|
||||
const daysLeft = findHowManyDaysLeft(cycleDetails.end_date);
|
||||
|
||||
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
|
||||
|
|
@ -568,49 +580,105 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||
<Transition show={open}>
|
||||
<Disclosure.Panel>
|
||||
<div className="flex flex-col gap-3">
|
||||
{cycleDetails.distribution?.completion_chart &&
|
||||
cycleDetails.start_date &&
|
||||
cycleDetails.end_date ? (
|
||||
<div className="h-full w-full pt-4">
|
||||
<div className="flex items-start gap-4 py-2 text-xs">
|
||||
<div className="flex items-center gap-3 text-custom-text-100">
|
||||
<div className="flex items-center justify-center gap-1">
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-[#A9BBD0]" />
|
||||
<span>Ideal</span>
|
||||
{isCompleted && !isEmpty(cycleDetails.progress_snapshot) ? (
|
||||
<>
|
||||
{cycleDetails.progress_snapshot.distribution?.completion_chart &&
|
||||
cycleDetails.start_date &&
|
||||
cycleDetails.end_date && (
|
||||
<div className="h-full w-full pt-4">
|
||||
<div className="flex items-start gap-4 py-2 text-xs">
|
||||
<div className="flex items-center gap-3 text-custom-text-100">
|
||||
<div className="flex items-center justify-center gap-1">
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-[#A9BBD0]" />
|
||||
<span>Ideal</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-1">
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-[#4C8FFF]" />
|
||||
<span>Current</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative h-40 w-80">
|
||||
<ProgressChart
|
||||
distribution={cycleDetails.progress_snapshot.distribution?.completion_chart}
|
||||
startDate={cycleDetails.start_date}
|
||||
endDate={cycleDetails.end_date}
|
||||
totalIssues={cycleDetails.progress_snapshot.total_issues}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-1">
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-[#4C8FFF]" />
|
||||
<span>Current</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative h-40 w-80">
|
||||
<ProgressChart
|
||||
distribution={cycleDetails.distribution?.completion_chart}
|
||||
startDate={cycleDetails.start_date}
|
||||
endDate={cycleDetails.end_date}
|
||||
totalIssues={cycleDetails.total_issues}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
""
|
||||
<>
|
||||
{cycleDetails.distribution?.completion_chart &&
|
||||
cycleDetails.start_date &&
|
||||
cycleDetails.end_date && (
|
||||
<div className="h-full w-full pt-4">
|
||||
<div className="flex items-start gap-4 py-2 text-xs">
|
||||
<div className="flex items-center gap-3 text-custom-text-100">
|
||||
<div className="flex items-center justify-center gap-1">
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-[#A9BBD0]" />
|
||||
<span>Ideal</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-1">
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-[#4C8FFF]" />
|
||||
<span>Current</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative h-40 w-80">
|
||||
<ProgressChart
|
||||
distribution={cycleDetails.distribution?.completion_chart}
|
||||
startDate={cycleDetails.start_date}
|
||||
endDate={cycleDetails.end_date}
|
||||
totalIssues={cycleDetails.total_issues}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{cycleDetails.total_issues > 0 && cycleDetails.distribution && (
|
||||
<div className="h-full w-full border-t border-custom-border-200 pt-5">
|
||||
<SidebarProgressStats
|
||||
distribution={cycleDetails.distribution}
|
||||
groupedIssues={{
|
||||
backlog: cycleDetails.backlog_issues,
|
||||
unstarted: cycleDetails.unstarted_issues,
|
||||
started: cycleDetails.started_issues,
|
||||
completed: cycleDetails.completed_issues,
|
||||
cancelled: cycleDetails.cancelled_issues,
|
||||
}}
|
||||
totalIssues={cycleDetails.total_issues}
|
||||
isPeekView={Boolean(peekCycle)}
|
||||
/>
|
||||
</div>
|
||||
{/* stats */}
|
||||
{isCompleted && !isEmpty(cycleDetails.progress_snapshot) ? (
|
||||
<>
|
||||
{cycleDetails.progress_snapshot.total_issues > 0 &&
|
||||
cycleDetails.progress_snapshot.distribution && (
|
||||
<div className="h-full w-full border-t border-custom-border-200 pt-5">
|
||||
<SidebarProgressStats
|
||||
distribution={cycleDetails.progress_snapshot.distribution}
|
||||
groupedIssues={{
|
||||
backlog: cycleDetails.progress_snapshot.backlog_issues,
|
||||
unstarted: cycleDetails.progress_snapshot.unstarted_issues,
|
||||
started: cycleDetails.progress_snapshot.started_issues,
|
||||
completed: cycleDetails.progress_snapshot.completed_issues,
|
||||
cancelled: cycleDetails.progress_snapshot.cancelled_issues,
|
||||
}}
|
||||
totalIssues={cycleDetails.progress_snapshot.total_issues}
|
||||
isPeekView={Boolean(peekCycle)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{cycleDetails.total_issues > 0 && cycleDetails.distribution && (
|
||||
<div className="h-full w-full border-t border-custom-border-200 pt-5">
|
||||
<SidebarProgressStats
|
||||
distribution={cycleDetails.distribution}
|
||||
groupedIssues={{
|
||||
backlog: cycleDetails.backlog_issues,
|
||||
unstarted: cycleDetails.unstarted_issues,
|
||||
started: cycleDetails.started_issues,
|
||||
completed: cycleDetails.completed_issues,
|
||||
cancelled: cycleDetails.cancelled_issues,
|
||||
}}
|
||||
totalIssues={cycleDetails.total_issues}
|
||||
isPeekView={Boolean(peekCycle)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Disclosure.Panel>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue