refactor: migrate web progress indicators to @makeplane/propel (#9698)

* refactor: migrate web progress indicators to @makeplane/propel

* style: fix comboButton indentation in dropdowns

* fix: scale cycle and module progress rings to 30px
This commit is contained in:
Anmol Singh Bhatia
2026-08-28 00:10:29 +05:30
committed by GitHub
parent 8b021935aa
commit c3cc04777a
7 changed files with 77 additions and 50 deletions

View File

@@ -10,8 +10,9 @@ import { useTheme } from "next-themes";
import { PROGRESS_STATE_GROUPS_DETAILS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import type { TWorkItemFilterCondition } from "@plane/shared-state";
import { LinearProgress } from "@makeplane/propel/components/linear-progress";
import type { ICycle } from "@plane/types";
import { LinearProgressIndicator, Loader } from "@plane/ui";
import { Loader } from "@plane/ui";
// assets
import darkProgressAsset from "@/app/assets/empty-state/active-cycle/progress-dark.webp?url";
import lightProgressAsset from "@/app/assets/empty-state/active-cycle/progress-light.webp?url";
@@ -32,12 +33,9 @@ export const ActiveCycleProgress = observer(function ActiveCycleProgress(props:
// plane hooks
const { t } = useTranslation();
// derived values
const progressIndicatorData = PROGRESS_STATE_GROUPS_DETAILS.map((group, index) => ({
id: index,
name: group.title,
value: cycle && cycle.total_issues > 0 ? (cycle[group.key as keyof ICycle] as number) : 0,
color: group.color,
}));
const closedIssues = cycle ? cycle.completed_issues + cycle.cancelled_issues : 0;
const closableIssues = cycle ? cycle.total_issues - cycle.cancelled_issues : 0;
const progressValue = closableIssues > 0 ? (closedIssues / closableIssues) * 100 : 0;
const groupedIssues: any = cycle
? {
completed: cycle?.completed_issues,
@@ -61,7 +59,15 @@ export const ActiveCycleProgress = observer(function ActiveCycleProgress(props:
</span>
)}
</div>
{cycle.total_issues > 0 && <LinearProgressIndicator size="lg" data={progressIndicatorData} />}
{cycle.total_issues > 0 && (
<LinearProgress
value={progressValue}
size="md"
variant="brand"
showValue={false}
aria-label="Cycle progress"
/>
)}
</div>
{cycle.total_issues > 0 ? (

View File

@@ -8,10 +8,10 @@ import type { MouseEvent } from "react";
import { useRef } from "react";
import { observer } from "mobx-react";
import { usePathname, useSearchParams } from "next/navigation";
import { CircularProgress } from "@makeplane/propel/components/circular-progress";
import { CheckIcon } from "@plane/propel/icons";
// plane imports
import type { TCycleGroups } from "@plane/types";
import { CircularProgressIndicator } from "@plane/ui";
// components
import { generateQueryParams, calculateCycleProgress } from "@plane/utils";
import { ListItem } from "@/components/core/list";
@@ -86,13 +86,23 @@ export const CyclesListItem = observer(function CyclesListItem(props: TCyclesLis
onItemClick={handleItemClick}
className={className}
prependTitleElement={
<CircularProgressIndicator size={30} percentage={progress} strokeWidth={3}>
{progress === 100 ? (
<CheckIcon className="h-3 w-3 stroke-2" />
) : (
<span className="text-9 text-primary">{`${progress}%`}</span>
)}
</CircularProgressIndicator>
<div className="relative size-[30px]">
<div className="absolute inset-0 flex scale-150 items-center justify-center">
<CircularProgress
value={progress}
size="md"
variant={progress === 100 ? "success" : "brand"}
aria-label="Cycle progress"
/>
</div>
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
{progress === 100 ? (
<CheckIcon className="h-3 w-3 stroke-2" />
) : (
<span className="text-9 text-primary">{`${progress}%`}</span>
)}
</div>
</div>
}
actionableItems={
<CycleListItemAction

View File

@@ -6,8 +6,8 @@
import { observer } from "mobx-react";
// ui
import { CircularProgress } from "@makeplane/propel/components/circular-progress";
import { Tooltip } from "@plane/propel/tooltip";
import { CircularProgressIndicator } from "@plane/ui";
// components
import { getFileExtension } from "@plane/utils";
import { getFileIcon } from "@/components/icons";
@@ -41,7 +41,7 @@ export const IssueAttachmentsUploadItem = observer(function IssueAttachmentsUplo
</div>
<div className="flex flex-shrink-0 items-center gap-2">
<span className="flex-shrink-0">
<CircularProgressIndicator size={20} strokeWidth={3} percentage={uploadStatus.progress} />
<CircularProgress value={uploadStatus.progress} size="md" variant="brand" aria-label="Upload progress" />
</span>
<div className="flex-shrink-0 text-13 font-medium">{uploadStatus.progress}% done</div>
</div>

View File

@@ -5,8 +5,8 @@
*/
import { observer } from "mobx-react";
import { CircularProgress } from "@makeplane/propel/components/circular-progress";
import { Tooltip } from "@plane/propel/tooltip";
import { CircularProgressIndicator } from "@plane/ui";
import { getFileExtension, truncateText } from "@plane/utils";
// ui
// icons
@@ -49,7 +49,7 @@ export const IssueAttachmentsUploadDetails = observer(function IssueAttachmentsU
</div>
<div className="flex flex-shrink-0 items-center gap-2">
<span className="flex-shrink-0">
<CircularProgressIndicator size={20} strokeWidth={3} percentage={uploadStatus.progress} />
<CircularProgress value={uploadStatus.progress} size="md" variant="brand" aria-label="Upload progress" />
</span>
<div className="flex-shrink-0 text-13 font-medium">{uploadStatus.progress}% done</div>
</div>

View File

@@ -6,10 +6,11 @@
import { observer } from "mobx-react";
// plane imports
import { CircularProgress } from "@makeplane/propel/components/circular-progress";
import { useTranslation } from "@plane/i18n";
import type { TIssueServiceType } from "@plane/types";
import { EIssueServiceType } from "@plane/types";
import { CircularProgressIndicator, CollapsibleButton } from "@plane/ui";
import { CollapsibleButton } from "@plane/ui";
// hooks
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
import { SubWorkItemTitleActions } from "./title-actions";
@@ -48,7 +49,12 @@ export const SubIssuesCollapsibleTitle = observer(function SubIssuesCollapsibleT
title={`${issueServiceType === EIssueServiceType.EPICS ? t("issue.label", { count: 1 }) : t("common.sub_work_items")}`}
indicatorElement={
<div className="flex items-center gap-1.5 text-13 text-tertiary">
<CircularProgressIndicator size={18} percentage={percentage} strokeWidth={3} />
<CircularProgress
value={percentage}
size="md"
variant={percentage === 100 ? "success" : "brand"}
aria-label="Sub-work-item progress"
/>
<span>
{completedCount}/{totalCount} {t("common.done")}
</span>

View File

@@ -11,19 +11,14 @@ import Link from "next/link";
import { useParams, usePathname, useSearchParams } from "next/navigation";
import { Info, SquareUser } from "lucide-react";
// plane package imports
import {
MODULE_STATUS,
PROGRESS_STATE_GROUPS_DETAILS,
EUserPermissions,
EUserPermissionsLevel,
IS_FAVORITE_MENU_OPEN,
} from "@plane/constants";
import { MODULE_STATUS, EUserPermissions, EUserPermissionsLevel, IS_FAVORITE_MENU_OPEN } from "@plane/constants";
import { useLocalStorage } from "@plane/hooks";
import { LinearProgress } from "@makeplane/propel/components/linear-progress";
import { WorkItemsIcon } from "@plane/propel/icons";
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/propel/toast";
import { Tooltip } from "@plane/propel/tooltip";
import type { IModule } from "@plane/types";
import { Card, FavoriteStar, LinearProgressIndicator } from "@plane/ui";
import { Card, FavoriteStar } from "@plane/ui";
import { getDate, renderFormattedPayloadDate, generateQueryParams } from "@plane/utils";
// components
import { DateRangeDropdown } from "@/components/dropdowns/date-range";
@@ -175,13 +170,7 @@ export const ModuleCardItem = observer(function ModuleCardItem(props: Props) {
: `0 work items`;
const moduleLeadDetails = moduleDetails.lead_id ? getUserDetails(moduleDetails.lead_id) : undefined;
const progressIndicatorData = PROGRESS_STATE_GROUPS_DETAILS.map((group, index) => ({
id: index,
name: group.title,
value: moduleTotalIssues > 0 ? (moduleDetails[group.key as keyof IModule] as number) : 0,
color: group.color,
}));
const progressValue = moduleTotalIssues > 0 ? (moduleCompletedIssues / moduleTotalIssues) * 100 : 0;
return (
<div className="relative" data-prevent-progress>
@@ -222,7 +211,13 @@ export const ModuleCardItem = observer(function ModuleCardItem(props: Props) {
</Tooltip>
)}
</div>
<LinearProgressIndicator size="lg" data={progressIndicatorData} />
<LinearProgress
value={progressValue}
size="md"
variant="brand"
showValue={false}
aria-label="Module progress"
/>
<div className="flex items-center justify-between py-0.5" onClick={handleEventPropagation}>
<DateRangeDropdown
buttonContainerClassName={`h-6 w-full flex ${isDisabled ? "cursor-not-allowed" : "cursor-pointer"} items-center gap-1.5 text-tertiary border-[0.5px] border-strong rounded-sm text-11`}

View File

@@ -11,7 +11,7 @@ import { useParams, usePathname, useSearchParams } from "next/navigation";
import { Info } from "lucide-react";
import { CheckIcon } from "@plane/propel/icons";
// ui
import { CircularProgressIndicator } from "@plane/ui";
import { CircularProgress } from "@makeplane/propel/components/circular-progress";
// components
import { generateQueryParams } from "@plane/utils";
import { ListItem } from "@/components/core/list";
@@ -76,19 +76,29 @@ export const ModuleListItem = observer(function ModuleListItem(props: Props) {
itemLink={`/${workspaceSlug?.toString()}/projects/${moduleDetails.project_id}/modules/${moduleDetails.id}`}
onItemClick={handleItemClick}
prependTitleElement={
<CircularProgressIndicator size={30} percentage={progress} strokeWidth={3}>
{completedModuleCheck ? (
progress === 100 ? (
<div className="relative size-[30px]">
<div className="absolute inset-0 flex scale-150 items-center justify-center">
<CircularProgress
value={progress}
size="md"
variant={progress === 100 ? "success" : "brand"}
aria-label="Module progress"
/>
</div>
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
{completedModuleCheck ? (
progress === 100 ? (
<CheckIcon className="h-3 w-3 stroke-[2] text-accent-primary" />
) : (
<span className="text-13 text-accent-primary">{`!`}</span>
)
) : progress === 100 ? (
<CheckIcon className="h-3 w-3 stroke-[2] text-accent-primary" />
) : (
<span className="text-13 text-accent-primary">{`!`}</span>
)
) : progress === 100 ? (
<CheckIcon className="h-3 w-3 stroke-[2] text-accent-primary" />
) : (
<span className="text-9 text-tertiary">{`${progress}%`}</span>
)}
</CircularProgressIndicator>
<span className="text-9 text-tertiary">{`${progress}%`}</span>
)}
</div>
</div>
}
appendTitleElement={
<button