[WEB-989] chore: archived module and cycle sidebar details (#4191)

* chore: module and cycle archive

* fix: archived cycle sidebar details fetch

* fix: archived module sidebar details fetch

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
This commit is contained in:
Anmol Singh Bhatia 2024-04-15 19:46:14 +05:30 committed by GitHub
parent 7a4ee509da
commit 54196aafc0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 562 additions and 150 deletions

View File

@ -34,7 +34,7 @@ urlpatterns = [
name="transfer-issues", name="transfer-issues",
), ),
path( path(
"workspaces/<str:slug>/projects/<uuid:project_id>/cycles/<uuid:pk>/archive/", "workspaces/<str:slug>/projects/<uuid:project_id>/cycles/<uuid:cycle_id>/archive/",
CycleArchiveUnarchiveAPIEndpoint.as_view(), CycleArchiveUnarchiveAPIEndpoint.as_view(),
name="cycle-archive-unarchive", name="cycle-archive-unarchive",
), ),

View File

@ -154,9 +154,7 @@ class CycleAPIEndpoint(WebhookMixin, BaseAPIView):
data, data,
status=status.HTTP_200_OK, status=status.HTTP_200_OK,
) )
queryset = ( queryset = self.get_queryset().filter(archived_at__isnull=True)
self.get_queryset().filter(archived_at__isnull=True)
)
cycle_view = request.GET.get("cycle_view", "all") cycle_view = request.GET.get("cycle_view", "all")
# Current Cycle # Current Cycle
@ -495,17 +493,22 @@ class CycleArchiveUnarchiveAPIEndpoint(BaseAPIView):
).data, ).data,
) )
def post(self, request, slug, project_id, pk): def post(self, request, slug, project_id, cycle_id):
cycle = Cycle.objects.get( cycle = Cycle.objects.get(
pk=pk, project_id=project_id, workspace__slug=slug pk=cycle_id, project_id=project_id, workspace__slug=slug
) )
if cycle.end_date >= timezone.now().date():
return Response(
{"error": "Only completed cycles can be archived"},
status=status.HTTP_400_BAD_REQUEST,
)
cycle.archived_at = timezone.now() cycle.archived_at = timezone.now()
cycle.save() cycle.save()
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)
def delete(self, request, slug, project_id, pk): def delete(self, request, slug, project_id, cycle_id):
cycle = Cycle.objects.get( cycle = Cycle.objects.get(
pk=pk, project_id=project_id, workspace__slug=slug pk=cycle_id, project_id=project_id, workspace__slug=slug
) )
cycle.archived_at = None cycle.archived_at = None
cycle.save() cycle.save()

View File

@ -554,7 +554,7 @@ class ModuleArchiveUnarchiveAPIEndpoint(BaseAPIView):
.order_by(self.kwargs.get("order_by", "-created_at")) .order_by(self.kwargs.get("order_by", "-created_at"))
) )
def get(self, request, slug, project_id): def get(self, request, slug, project_id, pk):
return self.paginate( return self.paginate(
request=request, request=request,
queryset=(self.get_queryset()), queryset=(self.get_queryset()),
@ -570,6 +570,13 @@ class ModuleArchiveUnarchiveAPIEndpoint(BaseAPIView):
module = Module.objects.get( module = Module.objects.get(
pk=pk, project_id=project_id, workspace__slug=slug pk=pk, project_id=project_id, workspace__slug=slug
) )
if module.status not in ["completed", "cancelled"]:
return Response(
{
"error": "Only completed or cancelled modules can be archived"
},
status=status.HTTP_400_BAD_REQUEST,
)
module.archived_at = timezone.now() module.archived_at = timezone.now()
module.save() module.save()
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)

View File

@ -101,4 +101,9 @@ urlpatterns = [
CycleArchiveUnarchiveEndpoint.as_view(), CycleArchiveUnarchiveEndpoint.as_view(),
name="cycle-archive-unarchive", name="cycle-archive-unarchive",
), ),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/archived-cycles/<uuid:pk>/",
CycleArchiveUnarchiveEndpoint.as_view(),
name="cycle-archive-unarchive",
),
] ]

View File

@ -121,4 +121,9 @@ urlpatterns = [
ModuleArchiveUnarchiveEndpoint.as_view(), ModuleArchiveUnarchiveEndpoint.as_view(),
name="module-archive-unarchive", name="module-archive-unarchive",
), ),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/archived-modules/<uuid:pk>/",
ModuleArchiveUnarchiveEndpoint.as_view(),
name="module-archive-unarchive",
),
] ]

View File

@ -726,9 +726,20 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
) )
) )
.annotate(is_favorite=Exists(favorite_subquery)) .annotate(is_favorite=Exists(favorite_subquery))
.annotate(
total_issues=Count(
"issue_cycle__issue__id",
distinct=True,
filter=Q(
issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
.annotate( .annotate(
completed_issues=Count( completed_issues=Count(
"issue_cycle__issue__state__group", "issue_cycle__issue__id",
distinct=True,
filter=Q( filter=Q(
issue_cycle__issue__state__group="completed", issue_cycle__issue__state__group="completed",
issue_cycle__issue__archived_at__isnull=True, issue_cycle__issue__archived_at__isnull=True,
@ -738,7 +749,8 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
) )
.annotate( .annotate(
cancelled_issues=Count( cancelled_issues=Count(
"issue_cycle__issue__state__group", "issue_cycle__issue__id",
distinct=True,
filter=Q( filter=Q(
issue_cycle__issue__state__group="cancelled", issue_cycle__issue__state__group="cancelled",
issue_cycle__issue__archived_at__isnull=True, issue_cycle__issue__archived_at__isnull=True,
@ -748,7 +760,8 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
) )
.annotate( .annotate(
started_issues=Count( started_issues=Count(
"issue_cycle__issue__state__group", "issue_cycle__issue__id",
distinct=True,
filter=Q( filter=Q(
issue_cycle__issue__state__group="started", issue_cycle__issue__state__group="started",
issue_cycle__issue__archived_at__isnull=True, issue_cycle__issue__archived_at__isnull=True,
@ -758,7 +771,8 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
) )
.annotate( .annotate(
unstarted_issues=Count( unstarted_issues=Count(
"issue_cycle__issue__state__group", "issue_cycle__issue__id",
distinct=True,
filter=Q( filter=Q(
issue_cycle__issue__state__group="unstarted", issue_cycle__issue__state__group="unstarted",
issue_cycle__issue__archived_at__isnull=True, issue_cycle__issue__archived_at__isnull=True,
@ -768,7 +782,8 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
) )
.annotate( .annotate(
backlog_issues=Count( backlog_issues=Count(
"issue_cycle__issue__state__group", "issue_cycle__issue__id",
distinct=True,
filter=Q( filter=Q(
issue_cycle__issue__state__group="backlog", issue_cycle__issue__state__group="backlog",
issue_cycle__issue__archived_at__isnull=True, issue_cycle__issue__archived_at__isnull=True,
@ -802,9 +817,6 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
distinct=True, distinct=True,
filter=~Q( filter=~Q(
issue_cycle__issue__assignees__id__isnull=True issue_cycle__issue__assignees__id__isnull=True
)
& Q(
issue_cycle__issue__assignees__member_project__is_active=True
), ),
), ),
Value([], output_field=ArrayField(UUIDField())), Value([], output_field=ArrayField(UUIDField())),
@ -814,53 +826,224 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
.distinct() .distinct()
) )
def get(self, request, slug, project_id): def get(self, request, slug, project_id, pk=None):
queryset = ( if pk is None:
self.get_queryset() queryset = (
.annotate( self.get_queryset()
total_issues=Count( .annotate(
"issue_cycle", total_issues=Count(
filter=Q( "issue_cycle",
issue_cycle__issue__archived_at__isnull=True, filter=Q(
issue_cycle__issue__is_draft=False, issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
.values(
# necessary fields
"id",
"workspace_id",
"project_id",
# model fields
"name",
"description",
"start_date",
"end_date",
"owned_by_id",
"view_props",
"sort_order",
"external_source",
"external_id",
"progress_snapshot",
# meta fields
"total_issues",
"is_favorite",
"cancelled_issues",
"completed_issues",
"started_issues",
"unstarted_issues",
"backlog_issues",
"assignee_ids",
"status",
"archived_at",
)
).order_by("-is_favorite", "-created_at")
return Response(queryset, status=status.HTTP_200_OK)
else:
queryset = (
self.get_queryset()
.filter(archived_at__isnull=False)
.filter(pk=pk)
)
data = (
self.get_queryset()
.filter(pk=pk)
.annotate(
sub_issues=Issue.issue_objects.filter(
project_id=self.kwargs.get("project_id"),
parent__isnull=False,
issue_cycle__cycle_id=pk,
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.values(
# necessary fields
"id",
"workspace_id",
"project_id",
# model fields
"name",
"description",
"start_date",
"end_date",
"owned_by_id",
"view_props",
"sort_order",
"external_source",
"external_id",
"progress_snapshot",
"sub_issues",
# meta fields
"is_favorite",
"total_issues",
"cancelled_issues",
"completed_issues",
"started_issues",
"unstarted_issues",
"backlog_issues",
"assignee_ids",
"status",
)
.first()
)
queryset = queryset.first()
if data is None:
return Response(
{"error": "Cycle does not exist"},
status=status.HTTP_400_BAD_REQUEST,
)
# Assignee Distribution
assignee_distribution = (
Issue.objects.filter(
issue_cycle__cycle_id=pk,
workspace__slug=slug,
project_id=project_id,
)
.annotate(first_name=F("assignees__first_name"))
.annotate(last_name=F("assignees__last_name"))
.annotate(assignee_id=F("assignees__id"))
.annotate(avatar=F("assignees__avatar"))
.annotate(display_name=F("assignees__display_name"))
.values(
"first_name",
"last_name",
"assignee_id",
"avatar",
"display_name",
)
.annotate(
total_issues=Count(
"id",
filter=Q(archived_at__isnull=True, is_draft=False),
), ),
) )
.annotate(
completed_issues=Count(
"id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
is_draft=False,
),
)
)
.annotate(
pending_issues=Count(
"id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
is_draft=False,
),
)
)
.order_by("first_name", "last_name")
) )
.values(
# necessary fields # Label Distribution
"id", label_distribution = (
"workspace_id", Issue.objects.filter(
"project_id", issue_cycle__cycle_id=pk,
# model fields workspace__slug=slug,
"name", project_id=project_id,
"description", )
"start_date", .annotate(label_name=F("labels__name"))
"end_date", .annotate(color=F("labels__color"))
"owned_by_id", .annotate(label_id=F("labels__id"))
"view_props", .values("label_name", "color", "label_id")
"sort_order", .annotate(
"external_source", total_issues=Count(
"external_id", "id",
"progress_snapshot", filter=Q(archived_at__isnull=True, is_draft=False),
# meta fields ),
"total_issues", )
"is_favorite", .annotate(
"cancelled_issues", completed_issues=Count(
"completed_issues", "id",
"started_issues", filter=Q(
"unstarted_issues", completed_at__isnull=False,
"backlog_issues", archived_at__isnull=True,
"assignee_ids", is_draft=False,
"status", ),
"archived_at", )
)
.annotate(
pending_issues=Count(
"id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
is_draft=False,
),
)
)
.order_by("label_name")
)
data["distribution"] = {
"assignees": assignee_distribution,
"labels": label_distribution,
"completion_chart": {},
}
if queryset.start_date and queryset.end_date:
data["distribution"]["completion_chart"] = burndown_plot(
queryset=queryset,
slug=slug,
project_id=project_id,
cycle_id=pk,
)
return Response(
data,
status=status.HTTP_200_OK,
) )
).order_by("-is_favorite", "-created_at")
return Response(queryset, status=status.HTTP_200_OK)
def post(self, request, slug, project_id, cycle_id): def post(self, request, slug, project_id, cycle_id):
cycle = Cycle.objects.get( cycle = Cycle.objects.get(
pk=cycle_id, project_id=project_id, workspace__slug=slug pk=cycle_id, project_id=project_id, workspace__slug=slug
) )
if cycle.end_date >= timezone.now().date():
return Response(
{"error": "Only completed cycles can be archived"},
status=status.HTTP_400_BAD_REQUEST,
)
cycle.archived_at = timezone.now() cycle.archived_at = timezone.now()
cycle.save() cycle.save()
return Response( return Response(

View File

@ -528,13 +528,64 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
project_id=self.kwargs.get("project_id"), project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"), workspace__slug=self.kwargs.get("slug"),
) )
cancelled_issues = (
Issue.issue_objects.filter(
state__group="cancelled",
issue_module__module_id=OuterRef("pk"),
)
.values("issue_module__module_id")
.annotate(cnt=Count("pk"))
.values("cnt")
)
completed_issues = (
Issue.issue_objects.filter(
state__group="completed",
issue_module__module_id=OuterRef("pk"),
)
.values("issue_module__module_id")
.annotate(cnt=Count("pk"))
.values("cnt")
)
started_issues = (
Issue.issue_objects.filter(
state__group="started",
issue_module__module_id=OuterRef("pk"),
)
.values("issue_module__module_id")
.annotate(cnt=Count("pk"))
.values("cnt")
)
unstarted_issues = (
Issue.issue_objects.filter(
state__group="unstarted",
issue_module__module_id=OuterRef("pk"),
)
.values("issue_module__module_id")
.annotate(cnt=Count("pk"))
.values("cnt")
)
backlog_issues = (
Issue.issue_objects.filter(
state__group="backlog",
issue_module__module_id=OuterRef("pk"),
)
.values("issue_module__module_id")
.annotate(cnt=Count("pk"))
.values("cnt")
)
total_issues = (
Issue.issue_objects.filter(
issue_module__module_id=OuterRef("pk"),
)
.values("issue_module__module_id")
.annotate(cnt=Count("pk"))
.values("cnt")
)
return ( return (
Module.objects.filter(workspace__slug=self.kwargs.get("slug")) Module.objects.filter(workspace__slug=self.kwargs.get("slug"))
.filter(archived_at__isnull=False) .filter(archived_at__isnull=False)
.annotate(is_favorite=Exists(favorite_subquery)) .annotate(is_favorite=Exists(favorite_subquery))
.select_related("project") .select_related("workspace", "project", "lead")
.select_related("workspace")
.select_related("lead")
.prefetch_related("members") .prefetch_related("members")
.prefetch_related( .prefetch_related(
Prefetch( Prefetch(
@ -545,68 +596,39 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
) )
) )
.annotate( .annotate(
total_issues=Count( completed_issues=Coalesce(
"issue_module", Subquery(completed_issues[:1]),
filter=Q( Value(0, output_field=IntegerField()),
issue_module__issue__archived_at__isnull=True,
issue_module__issue__is_draft=False,
),
distinct=True,
),
)
.annotate(
completed_issues=Count(
"issue_module__issue__state__group",
filter=Q(
issue_module__issue__state__group="completed",
issue_module__issue__archived_at__isnull=True,
issue_module__issue__is_draft=False,
),
distinct=True,
) )
) )
.annotate( .annotate(
cancelled_issues=Count( cancelled_issues=Coalesce(
"issue_module__issue__state__group", Subquery(cancelled_issues[:1]),
filter=Q( Value(0, output_field=IntegerField()),
issue_module__issue__state__group="cancelled",
issue_module__issue__archived_at__isnull=True,
issue_module__issue__is_draft=False,
),
distinct=True,
) )
) )
.annotate( .annotate(
started_issues=Count( started_issues=Coalesce(
"issue_module__issue__state__group", Subquery(started_issues[:1]),
filter=Q( Value(0, output_field=IntegerField()),
issue_module__issue__state__group="started",
issue_module__issue__archived_at__isnull=True,
issue_module__issue__is_draft=False,
),
distinct=True,
) )
) )
.annotate( .annotate(
unstarted_issues=Count( unstarted_issues=Coalesce(
"issue_module__issue__state__group", Subquery(unstarted_issues[:1]),
filter=Q( Value(0, output_field=IntegerField()),
issue_module__issue__state__group="unstarted",
issue_module__issue__archived_at__isnull=True,
issue_module__issue__is_draft=False,
),
distinct=True,
) )
) )
.annotate( .annotate(
backlog_issues=Count( backlog_issues=Coalesce(
"issue_module__issue__state__group", Subquery(backlog_issues[:1]),
filter=Q( Value(0, output_field=IntegerField()),
issue_module__issue__state__group="backlog", )
issue_module__issue__archived_at__isnull=True, )
issue_module__issue__is_draft=False, .annotate(
), total_issues=Coalesce(
distinct=True, Subquery(total_issues[:1]),
Value(0, output_field=IntegerField()),
) )
) )
.annotate( .annotate(
@ -622,44 +644,180 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
.order_by("-is_favorite", "-created_at") .order_by("-is_favorite", "-created_at")
) )
def get(self, request, slug, project_id): def get(self, request, slug, project_id, pk=None):
queryset = self.get_queryset() if pk is None:
modules = queryset.values( # Required fields queryset = self.get_queryset()
"id", modules = queryset.values( # Required fields
"workspace_id", "id",
"project_id", "workspace_id",
# Model fields "project_id",
"name", # Model fields
"description", "name",
"description_text", "description",
"description_html", "description_text",
"start_date", "description_html",
"target_date", "start_date",
"status", "target_date",
"lead_id", "status",
"member_ids", "lead_id",
"view_props", "member_ids",
"sort_order", "view_props",
"external_source", "sort_order",
"external_id", "external_source",
# computed fields "external_id",
"total_issues", # computed fields
"is_favorite", "total_issues",
"cancelled_issues", "is_favorite",
"completed_issues", "cancelled_issues",
"started_issues", "completed_issues",
"unstarted_issues", "started_issues",
"backlog_issues", "unstarted_issues",
"created_at", "backlog_issues",
"updated_at", "created_at",
"archived_at", "updated_at",
) "archived_at",
return Response(modules, status=status.HTTP_200_OK) )
return Response(modules, status=status.HTTP_200_OK)
else:
queryset = (
self.get_queryset()
.filter(pk=pk)
.annotate(
sub_issues=Issue.issue_objects.filter(
project_id=self.kwargs.get("project_id"),
parent__isnull=False,
issue_module__module_id=pk,
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
)
assignee_distribution = (
Issue.objects.filter(
issue_module__module_id=pk,
workspace__slug=slug,
project_id=project_id,
)
.annotate(first_name=F("assignees__first_name"))
.annotate(last_name=F("assignees__last_name"))
.annotate(assignee_id=F("assignees__id"))
.annotate(display_name=F("assignees__display_name"))
.annotate(avatar=F("assignees__avatar"))
.values(
"first_name",
"last_name",
"assignee_id",
"avatar",
"display_name",
)
.annotate(
total_issues=Count(
"id",
filter=Q(
archived_at__isnull=True,
is_draft=False,
),
)
)
.annotate(
completed_issues=Count(
"id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
is_draft=False,
),
)
)
.annotate(
pending_issues=Count(
"id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
is_draft=False,
),
)
)
.order_by("first_name", "last_name")
)
label_distribution = (
Issue.objects.filter(
issue_module__module_id=pk,
workspace__slug=slug,
project_id=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_issues=Count(
"id",
filter=Q(
archived_at__isnull=True,
is_draft=False,
),
),
)
.annotate(
completed_issues=Count(
"id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
is_draft=False,
),
)
)
.annotate(
pending_issues=Count(
"id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
is_draft=False,
),
)
)
.order_by("label_name")
)
data = ModuleDetailSerializer(queryset.first()).data
data["distribution"] = {
"assignees": assignee_distribution,
"labels": label_distribution,
"completion_chart": {},
}
# Fetch the modules
modules = queryset.first()
if modules and modules.start_date and modules.target_date:
data["distribution"]["completion_chart"] = burndown_plot(
queryset=modules,
slug=slug,
project_id=project_id,
module_id=pk,
)
return Response(
data,
status=status.HTTP_200_OK,
)
def post(self, request, slug, project_id, module_id): def post(self, request, slug, project_id, module_id):
module = Module.objects.get( module = Module.objects.get(
pk=module_id, project_id=project_id, workspace__slug=slug pk=module_id, project_id=project_id, workspace__slug=slug
) )
if module.status not in ["completed", "cancelled"]:
return Response(
{
"error": "Only completed or cancelled modules can be archived"
},
status=status.HTTP_400_BAD_REQUEST,
)
module.archived_at = timezone.now() module.archived_at = timezone.now()
module.save() module.save()
return Response( return Response(

View File

@ -19,7 +19,7 @@ export const CyclePeekOverview: React.FC<Props> = observer(({ projectId, workspa
// refs // refs
const ref = React.useRef(null); const ref = React.useRef(null);
// store hooks // store hooks
const { fetchCycleDetails } = useCycle(); const { fetchCycleDetails, fetchArchivedCycleDetails } = useCycle();
const handleClose = () => { const handleClose = () => {
delete router.query.peekCycle; delete router.query.peekCycle;
@ -30,9 +30,10 @@ export const CyclePeekOverview: React.FC<Props> = observer(({ projectId, workspa
}; };
useEffect(() => { useEffect(() => {
if (!peekCycle || isArchived) return; if (!peekCycle) return;
fetchCycleDetails(workspaceSlug, projectId, peekCycle.toString()); if (isArchived) fetchArchivedCycleDetails(workspaceSlug, projectId, peekCycle.toString());
}, [fetchCycleDetails, isArchived, peekCycle, projectId, workspaceSlug]); else fetchCycleDetails(workspaceSlug, projectId, peekCycle.toString());
}, [fetchArchivedCycleDetails, fetchCycleDetails, isArchived, peekCycle, projectId, workspaceSlug]);
return ( return (
<> <>

View File

@ -19,7 +19,7 @@ export const ModulePeekOverview: React.FC<Props> = observer(({ projectId, worksp
// refs // refs
const ref = React.useRef(null); const ref = React.useRef(null);
// store hooks // store hooks
const { fetchModuleDetails } = useModule(); const { fetchModuleDetails, fetchArchivedModuleDetails } = useModule();
const handleClose = () => { const handleClose = () => {
delete router.query.peekModule; delete router.query.peekModule;
@ -30,10 +30,10 @@ export const ModulePeekOverview: React.FC<Props> = observer(({ projectId, worksp
}; };
useEffect(() => { useEffect(() => {
if (!peekModule || isArchived) return; if (!peekModule) return;
if (isArchived) fetchArchivedModuleDetails(workspaceSlug, projectId, peekModule.toString());
fetchModuleDetails(workspaceSlug, projectId, peekModule.toString()); else fetchModuleDetails(workspaceSlug, projectId, peekModule.toString());
}, [fetchModuleDetails, isArchived, peekModule, projectId, workspaceSlug]); }, [fetchArchivedModuleDetails, fetchModuleDetails, isArchived, peekModule, projectId, workspaceSlug]);
return ( return (
<> <>

View File

@ -18,6 +18,14 @@ export class CycleArchiveService extends APIService {
}); });
} }
async getArchivedCycleDetails(workspaceSlug: string, projectId: string, cycleId: string): Promise<ICycle> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-cycles/${cycleId}/`)
.then((res) => res?.data)
.catch((err) => {
throw err?.response?.data;
});
}
async archiveCycle( async archiveCycle(
workspaceSlug: string, workspaceSlug: string,
projectId: string, projectId: string,

View File

@ -18,6 +18,14 @@ export class ModuleArchiveService extends APIService {
}); });
} }
async getArchivedModuleDetails(workspaceSlug: string, projectId: string, moduleId: string): Promise<IModule> {
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-modules/${moduleId}/`)
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async archiveModule( async archiveModule(
workspaceSlug: string, workspaceSlug: string,
projectId: string, projectId: string,

View File

@ -46,6 +46,7 @@ export interface ICycleStore {
fetchAllCycles: (workspaceSlug: string, projectId: string) => Promise<undefined | ICycle[]>; fetchAllCycles: (workspaceSlug: string, projectId: string) => Promise<undefined | ICycle[]>;
fetchActiveCycle: (workspaceSlug: string, projectId: string) => Promise<undefined | ICycle[]>; fetchActiveCycle: (workspaceSlug: string, projectId: string) => Promise<undefined | ICycle[]>;
fetchArchivedCycles: (workspaceSlug: string, projectId: string) => Promise<undefined | ICycle[]>; fetchArchivedCycles: (workspaceSlug: string, projectId: string) => Promise<undefined | ICycle[]>;
fetchArchivedCycleDetails: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<ICycle>;
fetchCycleDetails: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<ICycle>; fetchCycleDetails: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<ICycle>;
// crud // crud
createCycle: (workspaceSlug: string, projectId: string, data: Partial<ICycle>) => Promise<ICycle>; createCycle: (workspaceSlug: string, projectId: string, data: Partial<ICycle>) => Promise<ICycle>;
@ -99,6 +100,7 @@ export class CycleStore implements ICycleStore {
fetchAllCycles: action, fetchAllCycles: action,
fetchActiveCycle: action, fetchActiveCycle: action,
fetchArchivedCycles: action, fetchArchivedCycles: action,
fetchArchivedCycleDetails: action,
fetchCycleDetails: action, fetchCycleDetails: action,
createCycle: action, createCycle: action,
updateCycleDetails: action, updateCycleDetails: action,
@ -415,6 +417,21 @@ export class CycleStore implements ICycleStore {
return response; return response;
}); });
/**
* @description fetches cycle details
* @param workspaceSlug
* @param projectId
* @param cycleId
* @returns
*/
fetchArchivedCycleDetails = async (workspaceSlug: string, projectId: string, cycleId: string) =>
await this.cycleArchiveService.getArchivedCycleDetails(workspaceSlug, projectId, cycleId).then((response) => {
runInAction(() => {
set(this.cycleMap, [response.id], { ...this.cycleMap?.[response.id], ...response });
});
return response;
});
/** /**
* @description fetches cycle details * @description fetches cycle details
* @param workspaceSlug * @param workspaceSlug

View File

@ -33,6 +33,7 @@ export interface IModuleStore {
fetchWorkspaceModules: (workspaceSlug: string) => Promise<IModule[]>; fetchWorkspaceModules: (workspaceSlug: string) => Promise<IModule[]>;
fetchModules: (workspaceSlug: string, projectId: string) => Promise<undefined | IModule[]>; fetchModules: (workspaceSlug: string, projectId: string) => Promise<undefined | IModule[]>;
fetchArchivedModules: (workspaceSlug: string, projectId: string) => Promise<undefined | IModule[]>; fetchArchivedModules: (workspaceSlug: string, projectId: string) => Promise<undefined | IModule[]>;
fetchArchivedModuleDetails: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<IModule>;
fetchModuleDetails: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<IModule>; fetchModuleDetails: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<IModule>;
// crud // crud
createModule: (workspaceSlug: string, projectId: string, data: Partial<IModule>) => Promise<IModule>; createModule: (workspaceSlug: string, projectId: string, data: Partial<IModule>) => Promise<IModule>;
@ -91,6 +92,7 @@ export class ModulesStore implements IModuleStore {
fetchWorkspaceModules: action, fetchWorkspaceModules: action,
fetchModules: action, fetchModules: action,
fetchArchivedModules: action, fetchArchivedModules: action,
fetchArchivedModuleDetails: action,
fetchModuleDetails: action, fetchModuleDetails: action,
createModule: action, createModule: action,
updateModuleDetails: action, updateModuleDetails: action,
@ -274,6 +276,21 @@ export class ModulesStore implements IModuleStore {
}); });
}; };
/**
* @description fetch module details
* @param workspaceSlug
* @param projectId
* @param moduleId
* @returns IModule
*/
fetchArchivedModuleDetails = async (workspaceSlug: string, projectId: string, moduleId: string) =>
await this.moduleArchiveService.getArchivedModuleDetails(workspaceSlug, projectId, moduleId).then((response) => {
runInAction(() => {
set(this.moduleMap, [moduleId], response);
});
return response;
});
/** /**
* @description fetch module details * @description fetch module details
* @param workspaceSlug * @param workspaceSlug