Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: cycle and module sidebar analytics improvement #3559

Merged
merged 5 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions apiserver/plane/app/views/cycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,13 +242,13 @@ def list(self, request, slug, project_id):
.values("display_name", "assignee_id", "avatar")
.annotate(
total_issues=Count(
"assignee_id",
"id",
filter=Q(archived_at__isnull=True, is_draft=False),
),
)
.annotate(
completed_issues=Count(
"assignee_id",
"id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
Expand All @@ -258,7 +258,7 @@ def list(self, request, slug, project_id):
)
.annotate(
pending_issues=Count(
"assignee_id",
"id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
Expand All @@ -281,13 +281,13 @@ def list(self, request, slug, project_id):
.values("label_name", "color", "label_id")
.annotate(
total_issues=Count(
"label_id",
"id",
filter=Q(archived_at__isnull=True, is_draft=False),
)
)
.annotate(
completed_issues=Count(
"label_id",
"id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
Expand All @@ -297,7 +297,7 @@ def list(self, request, slug, project_id):
)
.annotate(
pending_issues=Count(
"label_id",
"id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
Expand Down Expand Up @@ -419,13 +419,13 @@ def retrieve(self, request, slug, project_id, pk):
)
.annotate(
total_issues=Count(
"assignee_id",
"id",
filter=Q(archived_at__isnull=True, is_draft=False),
),
)
.annotate(
completed_issues=Count(
"assignee_id",
"id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
Expand All @@ -435,7 +435,7 @@ def retrieve(self, request, slug, project_id, pk):
)
.annotate(
pending_issues=Count(
"assignee_id",
"id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
Expand All @@ -459,13 +459,13 @@ def retrieve(self, request, slug, project_id, pk):
.values("label_name", "color", "label_id")
.annotate(
total_issues=Count(
"label_id",
"id",
filter=Q(archived_at__isnull=True, is_draft=False),
),
)
.annotate(
completed_issues=Count(
"label_id",
"id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
Expand All @@ -475,7 +475,7 @@ def retrieve(self, request, slug, project_id, pk):
)
.annotate(
pending_issues=Count(
"label_id",
"id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
Expand Down
12 changes: 6 additions & 6 deletions apiserver/plane/app/views/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ def retrieve(self, request, slug, project_id, pk):
)
.annotate(
total_issues=Count(
"assignee_id",
"id",
filter=Q(
archived_at__isnull=True,
is_draft=False,
Expand All @@ -206,7 +206,7 @@ def retrieve(self, request, slug, project_id, pk):
)
.annotate(
completed_issues=Count(
"assignee_id",
"id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
Expand All @@ -216,7 +216,7 @@ def retrieve(self, request, slug, project_id, pk):
)
.annotate(
pending_issues=Count(
"assignee_id",
"id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
Expand All @@ -239,7 +239,7 @@ def retrieve(self, request, slug, project_id, pk):
.values("label_name", "color", "label_id")
.annotate(
total_issues=Count(
"label_id",
"id",
filter=Q(
archived_at__isnull=True,
is_draft=False,
Expand All @@ -248,7 +248,7 @@ def retrieve(self, request, slug, project_id, pk):
)
.annotate(
completed_issues=Count(
"label_id",
"id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
Expand All @@ -258,7 +258,7 @@ def retrieve(self, request, slug, project_id, pk):
)
.annotate(
pending_issues=Count(
"label_id",
"id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
Expand Down
1 change: 0 additions & 1 deletion packages/ui/src/icons/priority-icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ export const PriorityIcon: React.FC<IPriorityIcon> = (props) => {
>
<Icon
size={size}
viewBox="0 0 23.5 24"
className={cn(
{
"text-white": priority === "urgent",
Expand Down
19 changes: 12 additions & 7 deletions web/components/core/sidebar/progress-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,15 @@ const ProgressChart: React.FC<Props> = ({ distribution, startDate, endDate, tota
{
id: "pending",
color: "#3F76FF",
data: chartData.map((item, index) => ({
index,
x: item.currentDate,
y: item.pending,
color: "#3F76FF",
})),
data:
chartData.length > 0
? chartData.map((item, index) => ({
index,
x: item.currentDate,
y: item.pending,
color: "#3F76FF",
}))
: [],
enableArea: true,
},
{
Expand Down Expand Up @@ -121,7 +124,9 @@ const ProgressChart: React.FC<Props> = ({ distribution, startDate, endDate, tota
enableArea
colors={(datum) => datum.color ?? "#3F76FF"}
customYAxisTickValues={[0, totalIssues]}
gridXValues={chartData.map((item, index) => (index % 2 === 0 ? item.currentDate : ""))}
gridXValues={
chartData.length > 0 ? chartData.map((item, index) => (index % 2 === 0 ? item.currentDate : "")) : undefined
}
enableSlices="x"
sliceTooltip={(datum) => (
<div className="rounded-md border border-custom-border-200 bg-custom-background-80 p-2 text-xs">
Expand Down
30 changes: 12 additions & 18 deletions web/components/cycles/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -319,13 +319,7 @@ 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.total_issues === cycleDetails.completed_issues
? cycleDetails.total_issues > 1
? `${cycleDetails.total_issues}`
: `${cycleDetails.total_issues}`
: `${cycleDetails.completed_issues}/${cycleDetails.total_issues}`;
cycleDetails.total_issues === 0 ? "0 Issue" : `${cycleDetails.completed_issues}/${cycleDetails.total_issues}`;

const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;

Expand Down Expand Up @@ -575,7 +569,9 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
<Transition show={open}>
<Disclosure.Panel>
<div className="flex flex-col gap-3">
{isStartValid && isEndValid ? (
{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">
Expand All @@ -589,16 +585,14 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
</div>
</div>
</div>
{cycleDetails && cycleDetails.distribution && (
<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 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>
) : (
""
Expand Down
16 changes: 5 additions & 11 deletions web/components/modules/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -262,13 +262,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
const moduleStatus = MODULE_STATUS.find((status) => status.value === moduleDetails.status);

const issueCount =
moduleDetails.total_issues === 0
? "0 Issue"
: moduleDetails.total_issues === moduleDetails.completed_issues
? moduleDetails.total_issues > 1
? `${moduleDetails.total_issues}`
: `${moduleDetails.total_issues}`
: `${moduleDetails.completed_issues}/${moduleDetails.total_issues}`;
moduleDetails.total_issues === 0 ? "0 Issue" : `${moduleDetails.completed_issues}/${moduleDetails.total_issues}`;

const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;

Expand Down Expand Up @@ -582,7 +576,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
<Transition show={open}>
<Disclosure.Panel>
<div className="flex flex-col gap-3">
{isStartValid && isEndValid ? (
{moduleDetails.start_date && moduleDetails.target_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">
Expand All @@ -598,9 +592,9 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
</div>
<div className="relative h-40 w-80">
<ProgressChart
distribution={moduleDetails.distribution?.completion_chart}
startDate={moduleDetails.start_date ?? ""}
endDate={moduleDetails.target_date ?? ""}
distribution={moduleDetails.distribution?.completion_chart ?? {}}
startDate={moduleDetails.start_date}
endDate={moduleDetails.target_date}
totalIssues={moduleDetails.total_issues}
/>
</div>
Expand Down
22 changes: 9 additions & 13 deletions web/layouts/app-layout/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ProjectSidebarList } from "components/project";
import { useApplication } from "hooks/store";
import useOutsideClickDetector from "hooks/use-outside-click-detector";

export interface IAppSidebar { }
export interface IAppSidebar {}

export const AppSidebar: FC<IAppSidebar> = observer(() => {
// store hooks
Expand All @@ -34,24 +34,23 @@ export const AppSidebar: FC<IAppSidebar> = observer(() => {
}
};
handleResize();
window.addEventListener('resize', handleResize);
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener('resize', handleResize);
window.removeEventListener("resize", handleResize);
};
}, [themStore]);

return (
<div
className={`inset-y-0 z-30 flex h-full flex-shrink-0 flex-grow-0 flex-col border-r border-custom-sidebar-border-200 bg-custom-sidebar-background-100 duration-300
className={`inset-y-0 z-20 flex h-full flex-shrink-0 flex-grow-0 flex-col border-r border-custom-sidebar-border-200 bg-custom-sidebar-background-100 duration-300
fixed md:relative
${themStore.sidebarCollapsed ? "-ml-[280px]" : ""}
sm:${themStore.sidebarCollapsed ? "-ml-[280px]" : ""}
md:ml-0 ${themStore.sidebarCollapsed ? 'w-[80px]' : 'w-[280px]'}
lg:ml-0 ${themStore.sidebarCollapsed ? 'w-[80px]' : 'w-[280px]'}
`} >
<div
ref={ref}
className="flex h-full w-full flex-1 flex-col">
md:ml-0 ${themStore.sidebarCollapsed ? "w-[80px]" : "w-[280px]"}
lg:ml-0 ${themStore.sidebarCollapsed ? "w-[80px]" : "w-[280px]"}
`}
>
<div ref={ref} className="flex h-full w-full flex-1 flex-col">
<WorkspaceSidebarDropdown />
<WorkspaceSidebarQuickAction />
<WorkspaceSidebarMenu />
Expand All @@ -61,6 +60,3 @@ export const AppSidebar: FC<IAppSidebar> = observer(() => {
</div>
);
});



1 change: 1 addition & 0 deletions web/store/cycle.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export class CycleStore implements ICycleStore {
set(this.cycleMap, [cycleId], { ...this.cycleMap?.[cycleId], ...data });
});
const response = await this.cycleService.patchCycle(workspaceSlug, projectId, cycleId, data);
this.fetchCycleDetails(workspaceSlug, projectId, cycleId);
return response;
} catch (error) {
console.log("Failed to patch cycle from cycle store");
Expand Down
6 changes: 6 additions & 0 deletions web/store/issue/cycle/issue.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {

const params = this.rootIssueStore?.cycleIssuesFilter?.appliedFilters;
const response = await this.cycleService.getCycleIssuesWithParams(workspaceSlug, projectId, cycleId, params);
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);

runInAction(() => {
set(
Expand Down Expand Up @@ -182,6 +183,7 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {

const response = await this.rootIssueStore.projectIssues.createIssue(workspaceSlug, projectId, data);
await this.addIssueToCycle(workspaceSlug, projectId, cycleId, [response.id]);
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);

return response;
} catch (error) {
Expand Down Expand Up @@ -218,6 +220,7 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
if (!cycleId) throw new Error("Cycle Id is required");

const response = await this.rootIssueStore.projectIssues.removeIssue(workspaceSlug, projectId, issueId);
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);

const issueIndex = this.issues[cycleId].findIndex((_issueId) => _issueId === issueId);
if (issueIndex >= 0)
Expand Down Expand Up @@ -246,6 +249,7 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
});

const response = await this.createIssue(workspaceSlug, projectId, data, cycleId);
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);

const quickAddIssueIndex = this.issues[cycleId].findIndex((_issueId) => _issueId === data.id);
if (quickAddIssueIndex >= 0)
Expand Down Expand Up @@ -273,6 +277,7 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
issueIds.forEach((issueId) => {
this.rootStore.issues.updateIssue(issueId, { cycle_id: cycleId });
});
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);

return issueToCycle;
} catch (error) {
Expand All @@ -289,6 +294,7 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
this.rootStore.issues.updateIssue(issueId, { cycle_id: null });

const response = await this.issueService.removeIssueFromCycle(workspaceSlug, projectId, cycleId, issueId);
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);

return response;
} catch (error) {
Expand Down
Loading
Loading