[WEB-522] chore: workspace active cycle (#495)

* chore: estimate active cycle

* fix: handled estimate validation on workspace active cycles

* chore: issue manager updated

---------

Co-authored-by: gurusainath <gurusainath007@gmail.com>
This commit is contained in:
Bavisetti Narayan
2024-06-25 19:09:43 +05:30
committed by GitHub
parent de00d6cf90
commit 13d71f2b92
2 changed files with 111 additions and 24 deletions

View File

@@ -10,18 +10,15 @@ from django.db.models import (
Q,
Value,
When,
Sum,
IntegerField
)
from django.db.models.functions import Cast
from django.utils import timezone
# Module imports
from plane.db.models import (
Cycle,
CycleFavorite,
Issue,
Label,
User,
)
from plane.db.models import Cycle, CycleFavorite, Issue, Label, User, Project
from plane.utils.analytics_plot import burndown_plot
# ee imports
from plane.ee.views.base import BaseAPIView
@@ -38,8 +35,109 @@ class WorkspaceActiveCycleEndpoint(BaseAPIView):
WorkspaceUserPermission,
]
def get_results_controller(self, results, plot_type, active_cycles=None):
def get_results_controller(self, results, active_cycles=None):
for cycle in results:
estimate_type = Project.objects.filter(
workspace__slug=self.kwargs.get("slug"),
pk=cycle["project_id"],
estimate__isnull=False,
estimate__type="points",
).exists()
cycle["estimate_distribution"] = {}
if estimate_type:
assignee_distribution = (
Issue.issue_objects.filter(
issue_cycle__cycle_id=cycle["id"],
workspace__slug=self.kwargs.get("slug"),
project_id=cycle["project_id"],
)
.annotate(display_name=F("assignees__display_name"))
.annotate(assignee_id=F("assignees__id"))
.annotate(avatar=F("assignees__avatar"))
.values("display_name", "assignee_id", "avatar")
.annotate(
total_estimates=Sum(
Cast("estimate_point__value", IntegerField())
)
)
.annotate(
completed_estimates=Sum(
Cast("estimate_point__value", IntegerField()),
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
is_draft=False,
),
)
)
.annotate(
pending_estimates=Sum(
Cast("estimate_point__value", IntegerField()),
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
is_draft=False,
),
)
)
.order_by("display_name")
)
label_distribution = (
Issue.issue_objects.filter(
issue_cycle__cycle_id=cycle["id"],
workspace__slug=self.kwargs.get("slug"),
project_id=cycle["project_id"],
)
.annotate(label_name=F("labels__name"))
.annotate(color=F("labels__color"))
.annotate(label_id=F("labels__id"))
.values("label_name", "color", "label_id")
.annotate(
total_estimates=Sum(
Cast("estimate_point__value", IntegerField())
)
)
.annotate(
completed_estimates=Sum(
Cast("estimate_point__value", IntegerField()),
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
is_draft=False,
),
)
)
.annotate(
pending_estimates=Sum(
Cast("estimate_point__value", IntegerField()),
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
is_draft=False,
),
)
)
.order_by("label_name")
)
cycle["estimate_distribution"] = {
"assignees": assignee_distribution,
"labels": label_distribution,
"completion_chart": {},
}
if cycle["start_date"] and cycle["end_date"]:
cycle["estimate_distribution"]["completion_chart"] = (
burndown_plot(
queryset=active_cycles.get(pk=cycle["id"]),
slug=self.kwargs.get("slug"),
project_id=cycle["project_id"],
plot_type="points",
cycle_id=cycle["id"],
)
)
assignee_distribution = (
Issue.issue_objects.filter(
issue_cycle__cycle_id=cycle["id"],
@@ -128,12 +226,11 @@ class WorkspaceActiveCycleEndpoint(BaseAPIView):
slug=self.kwargs.get("slug"),
project_id=cycle["project_id"],
cycle_id=cycle["id"],
plot_type=plot_type
plot_type="issues"
)
return results
def get(self, request, slug):
plot_type = request.GET.get("plot_type", "issues")
subquery = CycleFavorite.objects.filter(
user=self.request.user,
cycle_id=OuterRef("pk"),
@@ -256,7 +353,7 @@ class WorkspaceActiveCycleEndpoint(BaseAPIView):
active_cycles, many=True
).data,
controller=lambda results: self.get_results_controller(
results,plot_type, active_cycles
results, active_cycles
),
default_per_page=int(request.GET.get("per_page", 3)),
)
)

View File

@@ -1,13 +1,10 @@
import { FC, Fragment, useState } from "react";
import isEmpty from "lodash/isEmpty";
import { observer } from "mobx-react";
import { ICycle, TCyclePlotType } from "@plane/types";
import { CustomSelect } from "@plane/ui";
// components
import ProgressChart from "@/components/core/sidebar/progress-chart";
// hooks
import { useProjectEstimates } from "@/hooks/store";
// plane web constants
import { EEstimateSystem } from "@/plane-web/constants/estimates";
export type ActiveCycleProductivityProps = {
cycle: ICycle;
@@ -20,16 +17,9 @@ const cycleBurnDownChartOptions = [
export const ActiveCycleProductivity: FC<ActiveCycleProductivityProps> = observer((props) => {
const { cycle } = props;
// hooks
const { currentActiveEstimateId, areEstimateEnabledByProjectId, estimateById } = useProjectEstimates();
// state
const [plotType, setPlotType] = useState<TCyclePlotType>("burndown");
const isCurrentProjectEstimateEnabled =
cycle?.project_id && areEstimateEnabledByProjectId(cycle?.project_id) ? true : false;
const estimateDetails =
isCurrentProjectEstimateEnabled && currentActiveEstimateId && estimateById(currentActiveEstimateId);
const isCurrentEstimateTypeIsPoints = estimateDetails && estimateDetails?.type === EEstimateSystem.POINTS;
const isCurrentEstimateTypeIsPoints = !isEmpty(cycle?.estimate_distribution);
// derived values
const chartDistributionData = plotType === "points" ? cycle?.estimate_distribution : cycle?.distribution || undefined;