diff --git a/apiserver/plane/app/views/cycle/base.py b/apiserver/plane/app/views/cycle/base.py index 03b6a8b6bf..f355bb24be 100644 --- a/apiserver/plane/app/views/cycle/base.py +++ b/apiserver/plane/app/views/cycle/base.py @@ -14,6 +14,8 @@ from django.db.models import ( When, Value, CharField, + Subquery, + IntegerField, ) from django.utils import timezone from django.contrib.postgres.aggregates import ArrayAgg @@ -73,6 +75,60 @@ class CycleViewSet(WebhookMixin, BaseViewSet): project_id=self.kwargs.get("project_id"), workspace__slug=self.kwargs.get("slug"), ) + cancelled_issues = ( + Issue.issue_objects.filter( + state__group="cancelled", + issue_cycle__cycle_id=OuterRef("pk"), + ) + .values("issue_cycle__cycle_id") + .annotate(cnt=Count("pk")) + .values("cnt") + ) + completed_issues = ( + Issue.issue_objects.filter( + state__group="completed", + issue_cycle__cycle_id=OuterRef("pk"), + ) + .values("issue_cycle__cycle_id") + .annotate(cnt=Count("pk")) + .values("cnt") + ) + started_issues = ( + Issue.issue_objects.filter( + state__group="started", + issue_cycle__cycle_id=OuterRef("pk"), + ) + .values("issue_cycle__cycle_id") + .annotate(cnt=Count("pk")) + .values("cnt") + ) + unstarted_issues = ( + Issue.issue_objects.filter( + state__group="unstarted", + issue_cycle__cycle_id=OuterRef("pk"), + ) + .values("issue_cycle__cycle_id") + .annotate(cnt=Count("pk")) + .values("cnt") + ) + backlog_issues = ( + Issue.issue_objects.filter( + state__group="backlog", + issue_cycle__cycle_id=OuterRef("pk"), + ) + .values("issue_cycle__cycle_id") + .annotate(cnt=Count("pk")) + .values("cnt") + ) + total_issues = ( + Issue.issue_objects.filter( + issue_cycle__cycle_id=OuterRef("pk"), + ) + .values("issue_cycle__cycle_id") + .annotate(cnt=Count("pk")) + .values("cnt") + ) + return self.filter_queryset( super() .get_queryset() @@ -102,58 +158,39 @@ class CycleViewSet(WebhookMixin, BaseViewSet): ) .annotate(is_favorite=Exists(favorite_subquery)) .annotate( - completed_issues=Count( - "issue_cycle__issue__state__group", - filter=Q( - issue_cycle__issue__state__group="completed", - issue_cycle__issue__archived_at__isnull=True, - issue_cycle__issue__is_draft=False, - ), - distinct=True, + completed_issues=Coalesce( + Subquery(completed_issues[:1]), + Value(0, output_field=IntegerField()), ) ) .annotate( - cancelled_issues=Count( - "issue_cycle__issue__state__group", - filter=Q( - issue_cycle__issue__state__group="cancelled", - issue_cycle__issue__archived_at__isnull=True, - issue_cycle__issue__is_draft=False, - ), - distinct=True, + cancelled_issues=Coalesce( + Subquery(cancelled_issues[:1]), + Value(0, output_field=IntegerField()), ) ) .annotate( - started_issues=Count( - "issue_cycle__issue__state__group", - filter=Q( - issue_cycle__issue__state__group="started", - issue_cycle__issue__archived_at__isnull=True, - issue_cycle__issue__is_draft=False, - ), - distinct=True, + started_issues=Coalesce( + Subquery(started_issues[:1]), + Value(0, output_field=IntegerField()), ) ) .annotate( - unstarted_issues=Count( - "issue_cycle__issue__state__group", - filter=Q( - issue_cycle__issue__state__group="unstarted", - issue_cycle__issue__archived_at__isnull=True, - issue_cycle__issue__is_draft=False, - ), - distinct=True, + unstarted_issues=Coalesce( + Subquery(unstarted_issues[:1]), + Value(0, output_field=IntegerField()), ) ) .annotate( - backlog_issues=Count( - "issue_cycle__issue__state__group", - filter=Q( - issue_cycle__issue__state__group="backlog", - issue_cycle__issue__archived_at__isnull=True, - issue_cycle__issue__is_draft=False, - ), - distinct=True, + backlog_issues=Coalesce( + Subquery(backlog_issues[:1]), + Value(0, output_field=IntegerField()), + ) + ) + .annotate( + total_issues=Coalesce( + Subquery(total_issues[:1]), + Value(0, output_field=IntegerField()), ) ) .annotate( @@ -195,19 +232,7 @@ class CycleViewSet(WebhookMixin, BaseViewSet): ) def list(self, request, slug, project_id): - queryset = ( - self.get_queryset() - .filter(archived_at__isnull=True) - .annotate( - total_issues=Count( - "issue_cycle", - filter=Q( - issue_cycle__issue__archived_at__isnull=True, - issue_cycle__issue__is_draft=False, - ), - ) - ) - ) + queryset = self.get_queryset().filter(archived_at__isnull=True) cycle_view = request.GET.get("cycle_view", "all") # Update the order by @@ -409,6 +434,7 @@ class CycleViewSet(WebhookMixin, BaseViewSet): # meta fields "is_favorite", "cancelled_issues", + "total_issues", "completed_issues", "started_issues", "unstarted_issues", @@ -484,6 +510,7 @@ class CycleViewSet(WebhookMixin, BaseViewSet): "progress_snapshot", # meta fields "is_favorite", + "total_issues", "cancelled_issues", "completed_issues", "started_issues", @@ -497,32 +524,11 @@ class CycleViewSet(WebhookMixin, BaseViewSet): def retrieve(self, request, slug, project_id, pk): queryset = ( - self.get_queryset() - .filter(archived_at__isnull=True) - .filter(pk=pk) - .annotate( - total_issues=Count( - "issue_cycle", - filter=Q( - issue_cycle__issue__archived_at__isnull=True, - issue_cycle__issue__is_draft=False, - ), - ) - ) + self.get_queryset().filter(archived_at__isnull=True).filter(pk=pk) ) data = ( self.get_queryset() .filter(pk=pk) - .annotate( - total_issues=Issue.issue_objects.filter( - project_id=self.kwargs.get("project_id"), - parent__isnull=True, - issue_cycle__cycle_id=pk, - ) - .order_by() - .annotate(count=Func(F("id"), function="Count")) - .values("count") - ) .annotate( sub_issues=Issue.issue_objects.filter( project_id=self.kwargs.get("project_id"), diff --git a/apiserver/plane/app/views/module/base.py b/apiserver/plane/app/views/module/base.py index 61bb16e40e..7769aee3fa 100644 --- a/apiserver/plane/app/views/module/base.py +++ b/apiserver/plane/app/views/module/base.py @@ -3,7 +3,17 @@ import json # Django Imports from django.utils import timezone -from django.db.models import Prefetch, F, OuterRef, Exists, Count, Q, Func +from django.db.models import ( + Prefetch, + F, + OuterRef, + Exists, + Count, + Q, + Func, + Subquery, + IntegerField, +) from django.contrib.postgres.aggregates import ArrayAgg from django.contrib.postgres.fields import ArrayField from django.db.models import Value, UUIDField @@ -61,6 +71,59 @@ class ModuleViewSet(WebhookMixin, BaseViewSet): project_id=self.kwargs.get("project_id"), 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 ( super() .get_queryset() @@ -80,68 +143,39 @@ class ModuleViewSet(WebhookMixin, BaseViewSet): ) ) .annotate( - total_issues=Count( - "issue_module", - filter=Q( - 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, + completed_issues=Coalesce( + Subquery(completed_issues[:1]), + Value(0, output_field=IntegerField()), ) ) .annotate( - cancelled_issues=Count( - "issue_module__issue__state__group", - filter=Q( - issue_module__issue__state__group="cancelled", - issue_module__issue__archived_at__isnull=True, - issue_module__issue__is_draft=False, - ), - distinct=True, + cancelled_issues=Coalesce( + Subquery(cancelled_issues[:1]), + Value(0, output_field=IntegerField()), ) ) .annotate( - started_issues=Count( - "issue_module__issue__state__group", - filter=Q( - issue_module__issue__state__group="started", - issue_module__issue__archived_at__isnull=True, - issue_module__issue__is_draft=False, - ), - distinct=True, + started_issues=Coalesce( + Subquery(started_issues[:1]), + Value(0, output_field=IntegerField()), ) ) .annotate( - unstarted_issues=Count( - "issue_module__issue__state__group", - filter=Q( - issue_module__issue__state__group="unstarted", - issue_module__issue__archived_at__isnull=True, - issue_module__issue__is_draft=False, - ), - distinct=True, + unstarted_issues=Coalesce( + Subquery(unstarted_issues[:1]), + Value(0, output_field=IntegerField()), ) ) .annotate( - backlog_issues=Count( - "issue_module__issue__state__group", - filter=Q( - issue_module__issue__state__group="backlog", - issue_module__issue__archived_at__isnull=True, - issue_module__issue__is_draft=False, - ), - distinct=True, + backlog_issues=Coalesce( + Subquery(backlog_issues[:1]), + Value(0, output_field=IntegerField()), + ) + ) + .annotate( + total_issues=Coalesce( + Subquery(total_issues[:1]), + Value(0, output_field=IntegerField()), ) ) .annotate( @@ -191,6 +225,7 @@ class ModuleViewSet(WebhookMixin, BaseViewSet): "is_favorite", "cancelled_issues", "completed_issues", + "total_issues", "started_issues", "unstarted_issues", "backlog_issues", @@ -246,16 +281,6 @@ class ModuleViewSet(WebhookMixin, BaseViewSet): self.get_queryset() .filter(archived_at__isnull=True) .filter(pk=pk) - .annotate( - total_issues=Issue.issue_objects.filter( - project_id=self.kwargs.get("project_id"), - parent__isnull=True, - issue_module__module_id=pk, - ) - .order_by() - .annotate(count=Func(F("id"), function="Count")) - .values("count") - ) .annotate( sub_issues=Issue.issue_objects.filter( project_id=self.kwargs.get("project_id"), @@ -418,6 +443,7 @@ class ModuleViewSet(WebhookMixin, BaseViewSet): "cancelled_issues", "completed_issues", "started_issues", + "total_issues", "unstarted_issues", "backlog_issues", "created_at", diff --git a/web/components/cycles/active-cycle/cycle-stats.tsx b/web/components/cycles/active-cycle/cycle-stats.tsx index e27c995006..fd4bc93187 100644 --- a/web/components/cycles/active-cycle/cycle-stats.tsx +++ b/web/components/cycles/active-cycle/cycle-stats.tsx @@ -11,7 +11,9 @@ import { Tooltip, Loader, PriorityIcon, Avatar } from "@plane/ui"; // components import { SingleProgressStats } from "@/components/core"; import { StateDropdown } from "@/components/dropdowns"; +import { EmptyState } from "@/components/empty-state"; // constants +import { EmptyStateType } from "@/constants/empty-state"; import { CYCLE_ISSUES_WITH_PARAMS } from "@/constants/fetch-keys"; import { EIssuesStoreType } from "@/constants/issue"; // helper @@ -177,8 +179,12 @@ export const ActiveCycleStats: FC = observer((props) => { )) ) : ( -
- There are no high priority issues present in this cycle. +
+
) ) : ( @@ -195,63 +201,75 @@ export const ActiveCycleStats: FC = observer((props) => { as="div" className="flex h-52 w-full flex-col gap-1 overflow-y-auto text-custom-text-200 vertical-scrollbar scrollbar-sm" > - {cycle.distribution?.assignees?.map((assignee, index) => { - if (assignee.assignee_id) - return ( - - + {cycleIssues.length > 0 ? ( + cycle.distribution?.assignees?.map((assignee, index) => { + if (assignee.assignee_id) + return ( + + - {assignee.display_name} -
- } - completed={assignee.completed_issues} - total={assignee.total_issues} - /> - ); - else - return ( - -
- User + {assignee.display_name}
- No assignee - - } - completed={assignee.completed_issues} - total={assignee.total_issues} - /> - ); - })} + } + completed={assignee.completed_issues} + total={assignee.total_issues} + /> + ); + else + return ( + +
+ User +
+ No assignee + + } + completed={assignee.completed_issues} + total={assignee.total_issues} + /> + ); + }) + ) : ( +
+ +
+ )} - {cycle.distribution?.labels?.map((label, index) => ( - - - {label.label_name ?? "No labels"} - - } - completed={label.completed_issues} - total={label.total_issues} - /> - ))} + {cycleIssues.length > 0 ? ( + cycle.distribution?.labels?.map((label, index) => ( + + + {label.label_name ?? "No labels"} + + } + completed={label.completed_issues} + total={label.total_issues} + /> + )) + ) : ( +
+ +
+ )}
diff --git a/web/components/cycles/active-cycle/productivity.tsx b/web/components/cycles/active-cycle/productivity.tsx index 59c2ac3c90..a3366d9341 100644 --- a/web/components/cycles/active-cycle/productivity.tsx +++ b/web/components/cycles/active-cycle/productivity.tsx @@ -3,6 +3,9 @@ import { FC } from "react"; import { ICycle } from "@plane/types"; // components import ProgressChart from "@/components/core/sidebar/progress-chart"; +import { EmptyState } from "@/components/empty-state"; +// constants +import { EmptyStateType } from "@/constants/empty-state"; export type ActiveCycleProductivityProps = { cycle: ICycle; @@ -16,31 +19,40 @@ export const ActiveCycleProductivity: FC = (props)

Issue burndown

- -
-
-
-
- - Ideal + {cycle.total_issues > 0 ? ( + <> +
+
+
+
+ + Ideal +
+
+ + Current +
+
+ {`Pending issues - ${cycle.backlog_issues + cycle.unstarted_issues + cycle.started_issues}`}
-
- - Current +
+
- {`Pending issues - ${cycle.backlog_issues + cycle.unstarted_issues + cycle.started_issues}`} -
-
- -
-
+ + ) : ( + <> +
+ +
+ + )}
); }; diff --git a/web/components/cycles/active-cycle/progress.tsx b/web/components/cycles/active-cycle/progress.tsx index dea3b496a8..752f72bcc1 100644 --- a/web/components/cycles/active-cycle/progress.tsx +++ b/web/components/cycles/active-cycle/progress.tsx @@ -3,8 +3,11 @@ import { FC } from "react"; import { ICycle } from "@plane/types"; // ui import { LinearProgressIndicator } from "@plane/ui"; +// components +import { EmptyState } from "@/components/empty-state"; // constants import { CYCLE_STATE_GROUPS_DETAILS } from "@/constants/cycle"; +import { EmptyStateType } from "@/constants/empty-state"; export type ActiveCycleProgressProps = { cycle: ICycle; @@ -32,48 +35,56 @@ export const ActiveCycleProgress: FC = (props) => {

Progress

- - {`${cycle.completed_issues + cycle.cancelled_issues}/${cycle.total_issues - cycle.cancelled_issues} ${ - cycle.completed_issues + cycle.cancelled_issues > 1 ? "Issues" : "Issue" - } closed`} - + {cycle.total_issues > 0 && ( + + {`${cycle.completed_issues + cycle.cancelled_issues}/${cycle.total_issues - cycle.cancelled_issues} ${ + cycle.completed_issues + cycle.cancelled_issues > 1 ? "Issues" : "Issue" + } closed`} + + )}
- + {cycle.total_issues > 0 && }
-
- {Object.keys(groupedIssues).map((group, index) => ( - <> - {groupedIssues[group] > 0 && ( -
-
-
- - {group} + {cycle.total_issues > 0 ? ( +
+ {Object.keys(groupedIssues).map((group, index) => ( + <> + {groupedIssues[group] > 0 && ( +
+
+
+ + {group} +
+ {`${groupedIssues[group]} ${ + groupedIssues[group] > 1 ? "Issues" : "Issue" + }`}
- {`${groupedIssues[group]} ${ - groupedIssues[group] > 1 ? "Issues" : "Issue" - }`}
-
- )} - - ))} - {cycle.cancelled_issues > 0 && ( - - - {`${cycle.cancelled_issues} cancelled ${ - cycle.cancelled_issues > 1 ? "issues are" : "issue is" - } excluded from this report.`}{" "} + )} + + ))} + {cycle.cancelled_issues > 0 && ( + + + {`${cycle.cancelled_issues} cancelled ${ + cycle.cancelled_issues > 1 ? "issues are" : "issue is" + } excluded from this report.`}{" "} + - - )} -
+ )} +
+ ) : ( +
+ +
+ )}
); }; diff --git a/web/components/cycles/active-cycle/upcoming-cycles-list.tsx b/web/components/cycles/active-cycle/upcoming-cycles-list.tsx index f4156f3418..221ffab0b6 100644 --- a/web/components/cycles/active-cycle/upcoming-cycles-list.tsx +++ b/web/components/cycles/active-cycle/upcoming-cycles-list.tsx @@ -1,5 +1,7 @@ import { FC } from "react"; import { observer } from "mobx-react"; +import Image from "next/image"; +import { useTheme } from "next-themes"; // components import { UpcomingCycleListItem } from "@/components/cycles"; // hooks @@ -14,6 +16,11 @@ export const UpcomingCyclesList: FC = observer((props) => { // store hooks const { currentProjectUpcomingCycleIds } = useCycle(); + // theme + const { resolvedTheme } = useTheme(); + + const resolvedEmptyStatePath = `/empty-state/active-cycle/cycle-${resolvedTheme === "light" ? "light" : "dark"}.webp`; + if (!currentProjectUpcomingCycleIds) return null; return ( @@ -28,8 +35,18 @@ export const UpcomingCyclesList: FC = observer((props) => { ))}
) : ( -
-
+
+
+
+ button image +
No upcoming cycles

Create new cycles to find them here or check diff --git a/web/components/empty-state/empty-state.tsx b/web/components/empty-state/empty-state.tsx index 88fe216125..790bd5aecc 100644 --- a/web/components/empty-state/empty-state.tsx +++ b/web/components/empty-state/empty-state.tsx @@ -151,12 +151,12 @@ export const EmptyState: React.FC = (props) => { )} {layout === "screen-simple" && (

-
+
{key diff --git a/web/constants/empty-state.ts b/web/constants/empty-state.ts index 6705021a50..363147775d 100644 --- a/web/constants/empty-state.ts +++ b/web/constants/empty-state.ts @@ -84,6 +84,12 @@ export enum EmptyStateType { NOTIFICATION_ARCHIVED_EMPTY_STATE = "notification-archived-empty-state", NOTIFICATION_SNOOZED_EMPTY_STATE = "notification-snoozed-empty-state", NOTIFICATION_UNREAD_EMPTY_STATE = "notification-unread-empty-state", + + ACTIVE_CYCLE_PROGRESS_EMPTY_STATE = "active-cycle-progress-empty-state", + ACTIVE_CYCLE_CHART_EMPTY_STATE = "active-cycle-chart-empty-state", + ACTIVE_CYCLE_PRIORITY_ISSUE_EMPTY_STATE = "active-cycle-priority-issue-empty-state", + ACTIVE_CYCLE_ASSIGNEE_EMPTY_STATE = "active-cycle-assignee-empty-state", + ACTIVE_CYCLE_LABEL_EMPTY_STATE = "active-cycle-label-empty-state", } const emptyStateDetails = { @@ -584,6 +590,31 @@ const emptyStateDetails = { description: "Any notification you archive will be \n available here to help you focus", path: "/empty-state/search/archive", }, + [EmptyStateType.ACTIVE_CYCLE_PROGRESS_EMPTY_STATE]: { + key: EmptyStateType.ACTIVE_CYCLE_PROGRESS_EMPTY_STATE, + title: "Add issues to the cycle to view it's \n progress", + path: "/empty-state/active-cycle/progress", + }, + [EmptyStateType.ACTIVE_CYCLE_CHART_EMPTY_STATE]: { + key: EmptyStateType.ACTIVE_CYCLE_CHART_EMPTY_STATE, + title: "Add issues to the cycle to view the \n burndown chart.", + path: "/empty-state/active-cycle/chart", + }, + [EmptyStateType.ACTIVE_CYCLE_PRIORITY_ISSUE_EMPTY_STATE]: { + key: EmptyStateType.ACTIVE_CYCLE_PRIORITY_ISSUE_EMPTY_STATE, + title: "Observe high priority issues tackled in \n the cycle at a glance.", + path: "/empty-state/active-cycle/priority", + }, + [EmptyStateType.ACTIVE_CYCLE_ASSIGNEE_EMPTY_STATE]: { + key: EmptyStateType.ACTIVE_CYCLE_ASSIGNEE_EMPTY_STATE, + title: "Add assignees to issues to see a \n breakdown of work by assignees.", + path: "/empty-state/active-cycle/assignee", + }, + [EmptyStateType.ACTIVE_CYCLE_LABEL_EMPTY_STATE]: { + key: EmptyStateType.ACTIVE_CYCLE_LABEL_EMPTY_STATE, + title: "Add labels to issues to see the \n breakdown of work by labels.", + path: "/empty-state/active-cycle/label", + }, } as const; export const EMPTY_STATE_DETAILS: Record = emptyStateDetails; diff --git a/web/public/empty-state/active-cycle/assignee-dark.webp b/web/public/empty-state/active-cycle/assignee-dark.webp new file mode 100644 index 0000000000..2590627670 Binary files /dev/null and b/web/public/empty-state/active-cycle/assignee-dark.webp differ diff --git a/web/public/empty-state/active-cycle/assignee-light.webp b/web/public/empty-state/active-cycle/assignee-light.webp new file mode 100644 index 0000000000..b8ae5c0102 Binary files /dev/null and b/web/public/empty-state/active-cycle/assignee-light.webp differ diff --git a/web/public/empty-state/active-cycle/chart-dark.webp b/web/public/empty-state/active-cycle/chart-dark.webp new file mode 100644 index 0000000000..033d6fe3c4 Binary files /dev/null and b/web/public/empty-state/active-cycle/chart-dark.webp differ diff --git a/web/public/empty-state/active-cycle/chart-light.webp b/web/public/empty-state/active-cycle/chart-light.webp new file mode 100644 index 0000000000..587906fba3 Binary files /dev/null and b/web/public/empty-state/active-cycle/chart-light.webp differ diff --git a/web/public/empty-state/active-cycle/cycle-dark.webp b/web/public/empty-state/active-cycle/cycle-dark.webp new file mode 100644 index 0000000000..d092308046 Binary files /dev/null and b/web/public/empty-state/active-cycle/cycle-dark.webp differ diff --git a/web/public/empty-state/active-cycle/cycle-light.webp b/web/public/empty-state/active-cycle/cycle-light.webp new file mode 100644 index 0000000000..a218d4d268 Binary files /dev/null and b/web/public/empty-state/active-cycle/cycle-light.webp differ diff --git a/web/public/empty-state/active-cycle/label-dark.webp b/web/public/empty-state/active-cycle/label-dark.webp new file mode 100644 index 0000000000..c15d3be26e Binary files /dev/null and b/web/public/empty-state/active-cycle/label-dark.webp differ diff --git a/web/public/empty-state/active-cycle/label-light.webp b/web/public/empty-state/active-cycle/label-light.webp new file mode 100644 index 0000000000..e5ccc6994d Binary files /dev/null and b/web/public/empty-state/active-cycle/label-light.webp differ diff --git a/web/public/empty-state/active-cycle/priority-dark.webp b/web/public/empty-state/active-cycle/priority-dark.webp new file mode 100644 index 0000000000..f662e92eec Binary files /dev/null and b/web/public/empty-state/active-cycle/priority-dark.webp differ diff --git a/web/public/empty-state/active-cycle/priority-light.webp b/web/public/empty-state/active-cycle/priority-light.webp new file mode 100644 index 0000000000..fde814c6a7 Binary files /dev/null and b/web/public/empty-state/active-cycle/priority-light.webp differ diff --git a/web/public/empty-state/active-cycle/progress-dark.webp b/web/public/empty-state/active-cycle/progress-dark.webp new file mode 100644 index 0000000000..4beda66ea4 Binary files /dev/null and b/web/public/empty-state/active-cycle/progress-dark.webp differ diff --git a/web/public/empty-state/active-cycle/progress-light.webp b/web/public/empty-state/active-cycle/progress-light.webp new file mode 100644 index 0000000000..ae30cf76a5 Binary files /dev/null and b/web/public/empty-state/active-cycle/progress-light.webp differ