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: progress chart changes #5707

Merged
merged 4 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
20 changes: 17 additions & 3 deletions packages/types/src/cycle/cycle.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {TIssue, IIssueFilterOptions} from "@plane/types";
import type { TIssue, IIssueFilterOptions } from "@plane/types";

export type TCycleGroups = "current" | "upcoming" | "completed" | "draft";

Expand Down Expand Up @@ -43,6 +43,18 @@ export type TCycleEstimateDistribution = {
completion_chart: TCycleCompletionChartDistribution;
labels: (TCycleLabelsDistribution & TCycleEstimateDistributionBase)[];
};
export type TCycleProgress = {
date: string;
started: number;
pending: number;
ideal: number | null;
scope: number;
completed: number;
actual: number;
unstarted: number;
backlog: number;
cancelled: number;
};

export type TProgressSnapshot = {
total_issues: number;
Expand Down Expand Up @@ -90,6 +102,7 @@ export interface ICycle extends TProgressSnapshot {
};
workspace_id: string;
project_detail: IProjectDetails;
progress: any[];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider using TCycleProgress[] instead of any[]

While adding the progress property to the ICycle interface is a good addition, using any[] as the type is not ideal. It's generally recommended to avoid any when possible in TypeScript to maintain type safety.

Consider changing the type to TCycleProgress[] to leverage the newly defined TCycleProgress type:

-  progress: any[];
+  progress: TCycleProgress[];

This will provide better type checking and improve the overall type safety of your codebase.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
progress: any[];
progress: TCycleProgress[];


export interface CycleIssueResponse {
Expand All @@ -107,7 +120,7 @@ export interface CycleIssueResponse {
}

export type SelectCycleType =
| (ICycle & {actionType: "edit" | "delete" | "create-issue"})
| (ICycle & { actionType: "edit" | "delete" | "create-issue" })
| undefined;

export type CycleDateCheckData = {
Expand All @@ -116,4 +129,5 @@ export type CycleDateCheckData = {
cycle_id?: string;
};

export type TCyclePlotType = "burndown" | "points";
export type TCycleEstimateType = "issues" | "points";
export type TCyclePlotType = "burndown" | "burnup";
22 changes: 22 additions & 0 deletions packages/ui/src/icons/done-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as React from "react";

import { ISvgIcons } from "./type";

export const DoneState: React.FC<ISvgIcons> = ({ width = "10", height = "11", className, color }) => (
<svg
width={width}
height={height}
viewBox="0 0 10 11"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
Comment on lines +5 to +13
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Address unused 'color' prop and consider making SVG colors dynamic.

The component declaration looks good, but there's an issue with the 'color' prop:

  1. The 'color' prop is destructured but not used in the component. This could lead to confusion for users of the component.
  2. The SVG uses hardcoded colors, which limits its reusability.

Consider the following improvements:

  1. Remove the unused 'color' prop if it's not needed.
  2. If color customization is intended, use the 'color' prop to set the SVG colors dynamically.

Here's a suggested implementation:

- export const DoneState: React.FC<ISvgIcons> = ({ width = "10", height = "11", className, color }) => (
+ export const DoneState: React.FC<ISvgIcons> = ({ width = "10", height = "11", className, color = "#15A34A" }) => (
  <svg
    width={width}
    height={height}
    viewBox="0 0 10 11"
    fill="none"
    xmlns="http://www.w3.org/2000/svg"
    className={className}
  >
-   <circle cx="5" cy="5.5" r="4.4" stroke="#15A34A" stroke-width="1.2" />
+   <circle cx="5" cy="5.5" r="4.4" stroke={color} stroke-width="1.2" />
    <path
      fill-rule="evenodd"
      clip-rule="evenodd"
      d="M2.5 5.59375L3.82582 6.91957L4.26777 6.47763L2.94194 5.15181L2.5 5.59375ZM4.26777 7.36152L7.36136 4.26793L6.91942 3.82599L3.82583 6.91958L4.26777 7.36152Z"
-     fill="#15A34A"
+     fill={color}
    />
  </svg>
);

This change allows users to customize the icon color while maintaining a default value.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const DoneState: React.FC<ISvgIcons> = ({ width = "10", height = "11", className, color }) => (
<svg
width={width}
height={height}
viewBox="0 0 10 11"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
export const DoneState: React.FC<ISvgIcons> = ({ width = "10", height = "11", className, color = "#15A34A" }) => (
<svg
width={width}
height={height}
viewBox="0 0 10 11"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<circle cx="5" cy="5.5" r="4.4" stroke={color} stroke-width="1.2" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M2.5 5.59375L3.82582 6.91957L4.26777 6.47763L2.94194 5.15181L2.5 5.59375ZM4.26777 7.36152L7.36136 4.26793L6.91942 3.82599L3.82583 6.91958L4.26777 7.36152Z"
fill={color}
/>
</svg>
);

<circle cx="5" cy="5.5" r="4.4" stroke="#15A34A" stroke-width="1.2" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M2.5 5.59375L3.82582 6.91957L4.26777 6.47763L2.94194 5.15181L2.5 5.59375ZM4.26777 7.36152L7.36136 4.26793L6.91942 3.82599L3.82583 6.91958L4.26777 7.36152Z"
fill="#15A34A"
/>
</svg>
);
17 changes: 17 additions & 0 deletions packages/ui/src/icons/in-progress-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as React from "react";

import { ISvgIcons } from "./type";

export const InProgressState: React.FC<ISvgIcons> = ({ width = "10", height = "11", className, color }) => (
<svg
width={width}
height={height}
viewBox="0 0 12 13"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<circle cx="6" cy="6.5" r="4.4" stroke="#EA8900" stroke-width="1.2" />
<circle cx="6" cy="6.5" r="2.4" stroke="#EA8900" stroke-width="1.2" stroke-dasharray="4 4" />
</svg>
);
3 changes: 3 additions & 0 deletions packages/ui/src/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ export * from "./dropdown-icon";
export * from "./intake";
export * from "./user-activity-icon";
export * from "./favorite-folder-icon";
export * from "./planned-icon";
export * from "./in-progress-icon";
export * from "./done-icon";
40 changes: 40 additions & 0 deletions packages/ui/src/icons/planned-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as React from "react";

import { ISvgIcons } from "./type";

export const PlannedState: React.FC<ISvgIcons> = ({ width = "10", height = "11", className, color }) => (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Address unused color prop.

The color prop is destructured in the component parameters but not used in the SVG. This could lead to confusion for developers using this component.

Consider one of the following options:

  1. Remove the color prop if it's not needed.
  2. Implement color customization using the color prop as suggested in the previous comment.
  3. If the color prop is intended for future use, add a TODO comment explaining its purpose.

<svg
width={width}
height={height}
viewBox="0 0 12 13"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<g clip-path="url(#clip0_3180_28635)">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M7.11853 4.7C7.20073 4.88749 7.38342 5.01866 7.59656 5.02037C7.88848 5.02271 8.12698 4.7813 8.12925 4.48116L8.13344 3.92962C8.1348 3.74982 8.04958 3.58096 7.90581 3.47859C7.76203 3.37623 7.57832 3.3536 7.41509 3.41815L3.97959 4.77682C3.77547 4.85755 3.64077 5.05919 3.64077 5.28406L3.64077 9.0883C3.64077 9.27834 3.73732 9.45458 3.8954 9.55308C4.05347 9.65157 4.25011 9.65802 4.41396 9.57008L4.90523 9.30643C5.16402 9.16754 5.26431 8.83925 5.12922 8.57317C5.04115 8.39971 4.8748 8.29551 4.69795 8.28247L4.69795 5.65729L7.11853 4.7Z"
fill="#455068"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M5.00428 3.06914C5.08648 3.25663 5.26916 3.3878 5.4823 3.38951C5.77422 3.39185 6.01272 3.15044 6.015 2.8503L6.01918 2.29876C6.02054 2.11896 5.93532 1.9501 5.79155 1.84774C5.64777 1.74537 5.46406 1.72274 5.30084 1.78729L1.86534 3.14597C1.66121 3.22669 1.52652 3.42834 1.52652 3.6532L1.52652 7.45745C1.52652 7.64749 1.62307 7.82372 1.78114 7.92222C1.93922 8.02071 2.13585 8.02716 2.29971 7.93922L2.79097 7.67557C3.04977 7.53668 3.15005 7.20839 3.01496 6.94231C2.92689 6.76885 2.76054 6.66465 2.5837 6.65161L2.5837 4.02643L5.00428 3.06914Z"
fill="#455068"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M10.473 9.34799C10.4728 9.57269 10.3382 9.77413 10.1342 9.85482L6.70129 11.2129C6.53874 11.2772 6.35582 11.255 6.21225 11.1536C6.06867 11.0523 5.98288 10.8847 5.98288 10.7056L5.98288 6.90139C5.98288 6.67653 6.11757 6.47489 6.3217 6.39416L9.7572 5.03548C9.91981 4.97118 10.1028 4.99338 10.2464 5.09484C10.3899 5.19629 10.4757 5.36397 10.4756 5.5431L10.473 9.34799ZM9.41784 6.33426L7.04006 7.27463L7.04006 9.91423L9.41605 8.97431L9.41784 6.33426Z"
fill="#455068"
/>
</g>
<defs>
<clipPath id="clip0_3180_28635">
<rect width="12" height="12" fill="white" transform="translate(0 0.5)" />
</clipPath>
</defs>
</svg>
);
5 changes: 3 additions & 2 deletions packages/ui/src/loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ const Loader = ({ children, className = "" }: Props) => (
type ItemProps = {
height?: string;
width?: string;
className?: string;
};

const Item: React.FC<ItemProps> = ({ height = "auto", width = "auto" }) => (
<div className="rounded-md bg-custom-background-80" style={{ height: height, width: width }} />
const Item: React.FC<ItemProps> = ({ height = "auto", width = "auto", className = "" }) => (
<div className={cn("rounded-md bg-custom-background-80", className)} style={{ height: height, width: width }} />
);

Loader.Item = Item;
Expand Down
8 changes: 4 additions & 4 deletions packages/ui/src/progress/circular-progress-indicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface ICircularProgressIndicator {
}

export const CircularProgressIndicator: React.FC<ICircularProgressIndicator> = (props) => {
const { size = 40, percentage = 25, strokeWidth = 6, children } = props;
const { size = 40, percentage = 25, strokeWidth = 6, strokeColor = "stroke-custom-primary-100", children } = props;

const sqSize = size;
const radius = (size - strokeWidth) / 2;
Expand All @@ -27,7 +27,7 @@ export const CircularProgressIndicator: React.FC<ICircularProgressIndicator> = (
strokeWidth={`${strokeWidth}px`}
style={{ filter: "url(#filter0_bi_377_19141)" }}
/>
<defs>
{/* <defs>
<filter
id="filter0_bi_377_19141"
x="-3.57544"
Expand All @@ -53,9 +53,9 @@ export const CircularProgressIndicator: React.FC<ICircularProgressIndicator> = (
<feColorMatrix type="matrix" values="0 0 0 0 0.63125 0 0 0 0 0.6625 0 0 0 0 0.75 0 0 0 0.35 0" />
<feBlend mode="normal" in2="shape" result="effect2_innerShadow_377_19141" />
</filter>
</defs>
</defs> */}
<circle
className="fill-none stroke-custom-primary-100 "
className={`fill-none ${strokeColor}`}
cx={size / 2}
cy={size / 2}
r={radius}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ const CycleDetailPage = observer(() => {
{cycleId && !isSidebarCollapsed && (
<div
className={cn(
"flex h-full w-[24rem] flex-shrink-0 flex-col gap-3.5 overflow-y-auto border-l border-custom-border-100 bg-custom-sidebar-background-100 px-6 duration-300 vertical-scrollbar scrollbar-sm absolute right-0 z-[13]"
"flex h-full w-[21.5rem] flex-shrink-0 flex-col gap-3.5 overflow-y-auto border-l border-custom-border-100 bg-custom-sidebar-background-100 px-4 duration-300 vertical-scrollbar scrollbar-sm absolute right-0 z-[13]"
)}
style={{
boxShadow:
"0px 1px 4px 0px rgba(0, 0, 0, 0.06), 0px 2px 4px 0px rgba(16, 24, 40, 0.06), 0px 1px 8px -1px rgba(16, 24, 40, 0.06)",
}}
>
<CycleDetailsSidebar cycleId={cycleId.toString()} handleClose={toggleSidebar} />
<CycleDetailsSidebar handleClose={toggleSidebar} />
Copy link
Contributor

@coderabbitai coderabbitai bot Sep 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

CycleDetailsSidebar still utilizes the cycleId prop.

The cycleId prop has been removed from the CycleDetailsSidebar component in web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/[cycleId]/page.tsx. However, the search results indicate that cycleId is still being passed to CycleDetailsSidebar in other parts of the codebase, which may lead to inconsistencies or runtime errors.

  • Instances to review:
    • web/core/components/cycles/cycle-peek-overview.tsx
    • web/core/components/cycles/list/cycles-list-item-action.tsx
    • web/core/components/cycles/board/cycles-board-card.tsx

Please verify all usages of the CycleDetailsSidebar component to ensure that the removal of the cycleId prop does not negatively impact functionality.

🔗 Analysis chain

Verify CycleDetailsSidebar functionality after prop removal.

The cycleId prop has been removed from the CycleDetailsSidebar component. This simplification of the component's interface is good for maintainability.

Please ensure that the CycleDetailsSidebar component can still function correctly without the cycleId prop. Run the following script to check if cycleId is still being used within the CycleDetailsSidebar component:

If the script returns any results, it indicates that cycleId is still being used within the component, which may cause issues.


Please run the following script to verify if cycleId is still being used within the CycleDetailsSidebar component:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if cycleId is still being used within the CycleDetailsSidebar component.

# Test: Search for cycleId usage in CycleDetailsSidebar
ast-grep --lang typescript --pattern 'const CycleDetailsSidebar = ($_) => { $$$ cycleId $$$ }'

Length of output: 96


Script:

#!/bin/bash
# Description: Search for any occurrences of cycleId within the CycleDetailsSidebar component.

# Search for 'cycleId' usage in CycleDetailsSidebar
rg 'cycleId' $(fd 'CycleDetailsSidebar' --type f)

Length of output: 72381

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc: @gakshita

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

</div>
)}
</div>
Expand Down
1 change: 1 addition & 0 deletions web/ce/components/cycles/active-cycle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./root";
89 changes: 89 additions & 0 deletions web/ce/components/cycles/active-cycle/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"use client";

import { observer } from "mobx-react";
import { Disclosure } from "@headlessui/react";
// ui
import { Row } from "@plane/ui";
// components
import {
ActiveCycleProductivity,
ActiveCycleProgress,
ActiveCycleStats,
CycleListGroupHeader,
CyclesListItem,
} from "@/components/cycles";
import useCyclesDetails from "@/components/cycles/active-cycle/use-cycles-details";
import { EmptyState } from "@/components/empty-state";
// constants
import { EmptyStateType } from "@/constants/empty-state";
import { useCycle } from "@/hooks/store";
import { ActiveCycleIssueDetails } from "@/store/issue/cycle";

interface IActiveCycleDetails {
workspaceSlug: string;
projectId: string;
}

export const ActiveCycleRoot: React.FC<IActiveCycleDetails> = observer((props) => {
const { workspaceSlug, projectId } = props;
const { currentProjectActiveCycle, currentProjectActiveCycleId } = useCycle();
const {
handleFiltersUpdate,
cycle: activeCycle,
cycleIssueDetails,
} = useCyclesDetails({ workspaceSlug, projectId, cycleId: currentProjectActiveCycleId });

return (
<>
<Disclosure as="div" className="flex flex-shrink-0 flex-col" defaultOpen>
{({ open }) => (
<>
<Disclosure.Button className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 cursor-pointer">
<CycleListGroupHeader title="Active cycle" type="current" isExpanded={open} />
</Disclosure.Button>
<Disclosure.Panel>
{!currentProjectActiveCycle ? (
<EmptyState type={EmptyStateType.PROJECT_CYCLE_ACTIVE} size="sm" />
) : (
<div className="flex flex-col border-b border-custom-border-200">
{currentProjectActiveCycleId && (
<CyclesListItem
key={currentProjectActiveCycleId}
cycleId={currentProjectActiveCycleId}
workspaceSlug={workspaceSlug}
projectId={projectId}
className="!border-b-transparent"
/>
)}
<Row className="bg-custom-background-100 pt-3 pb-6">
<div className="grid grid-cols-1 bg-custom-background-100 gap-3 lg:grid-cols-2 xl:grid-cols-3">
<ActiveCycleProgress
handleFiltersUpdate={handleFiltersUpdate}
projectId={projectId}
workspaceSlug={workspaceSlug}
cycle={activeCycle}
/>
<ActiveCycleProductivity
workspaceSlug={workspaceSlug}
projectId={projectId}
cycle={activeCycle}
/>
<ActiveCycleStats
workspaceSlug={workspaceSlug}
projectId={projectId}
cycle={activeCycle}
cycleId={currentProjectActiveCycleId}
handleFiltersUpdate={handleFiltersUpdate}
cycleIssueDetails={cycleIssueDetails as ActiveCycleIssueDetails}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid Unnecessary Type Assertion

At line 77, cycleIssueDetails is cast as ActiveCycleIssueDetails. If cycleIssueDetails already has the correct type from useCyclesDetails, the type assertion may be unnecessary. Relying on type inference or ensuring that useCyclesDetails correctly types cycleIssueDetails can prevent potential type masking and improve type safety.

You can modify useCyclesDetails to return cycleIssueDetails with the correct type, avoiding the need for type assertion here.

/>
</div>
</Row>
</div>
)}
</Disclosure.Panel>
</>
)}
</Disclosure>
</>
);
});
1 change: 1 addition & 0 deletions web/ce/components/cycles/analytics-sidebar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./sidebar-chart";
57 changes: 57 additions & 0 deletions web/ce/components/cycles/analytics-sidebar/sidebar-chart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Fragment } from "react";
import { TCycleDistribution, TCycleEstimateDistribution } from "@plane/types";
import { Loader } from "@plane/ui";
import ProgressChart from "@/components/core/sidebar/progress-chart";

type ProgressChartProps = {
chartDistributionData: TCycleEstimateDistribution | TCycleDistribution | undefined;
cycleStartDate: Date | undefined;
cycleEndDate: Date | undefined;
totalEstimatePoints: number;
totalIssues: number;
plotType: string;
};
export const SidebarBaseChart = (props: ProgressChartProps) => {
const { chartDistributionData, cycleStartDate, cycleEndDate, totalEstimatePoints, totalIssues, plotType } = props;
const completionChartDistributionData = chartDistributionData?.completion_chart || undefined;

return (
<div>
<div className="relative flex items-center gap-2">
<div className="flex items-center justify-center gap-1 text-xs">
<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 text-xs">
<span className="h-2.5 w-2.5 rounded-full bg-[#4C8FFF]" />
<span>Current</span>
</div>
</div>
{cycleStartDate && cycleEndDate && completionChartDistributionData ? (
<Fragment>
{plotType === "points" ? (
<ProgressChart
distribution={completionChartDistributionData}
startDate={cycleStartDate}
endDate={cycleEndDate}
totalIssues={totalEstimatePoints}
plotTitle={"points"}
/>
) : (
<ProgressChart
distribution={completionChartDistributionData}
startDate={cycleStartDate}
endDate={cycleEndDate}
totalIssues={totalIssues}
plotTitle={"issues"}
/>
)}
</Fragment>
) : (
<Loader className="w-full h-[160px] mt-4">
<Loader.Item width="100%" height="100%" />
</Loader>
)}
</div>
);
};
2 changes: 2 additions & 0 deletions web/ce/components/cycles/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./active-cycle";
export * from "./analytics-sidebar";
1 change: 0 additions & 1 deletion web/core/components/cycles/active-cycle/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from "./root";
export * from "./header";
export * from "./stats";
export * from "./upcoming-cycles-list-item";
Expand Down
Loading
Loading