diff --git a/packages/views/issues/components/board-card.tsx b/packages/views/issues/components/board-card.tsx index eb47f97179..9dc9e60790 100644 --- a/packages/views/issues/components/board-card.tsx +++ b/packages/views/issues/components/board-card.tsx @@ -15,6 +15,8 @@ import { PriorityPicker, AssigneePicker, DueDatePicker } from "./pickers"; import { PRIORITY_CONFIG } from "@multica/core/issues/config"; import type { CardProperties } from "@multica/core/issues/stores/view-store"; import { useViewStore } from "@multica/core/issues/stores/view-store-context"; +import { ProgressRing } from "./progress-ring"; +import type { ChildProgress } from "./list-row"; function formatDate(date: string): string { return new Date(date).toLocaleDateString("en-US", { @@ -39,9 +41,11 @@ function PickerWrapper({ children }: { children: React.ReactNode }) { export const BoardCardContent = memo(function BoardCardContent({ issue, editable = false, + childProgress, }: { issue: Issue; editable?: boolean; + childProgress?: ChildProgress; }) { const storeProperties = useViewStore((s) => s.cardProperties); const priorityCfg = PRIORITY_CONFIG[issue.priority]; @@ -73,6 +77,16 @@ export const BoardCardContent = memo(function BoardCardContent({ {issue.title}

+ {/* Sub-issue progress */} + {childProgress && ( +
+ + + {childProgress.done}/{childProgress.total} + +
+ )} + {/* Description */} {showDescription && (

@@ -173,7 +187,7 @@ const animateLayoutChanges: AnimateLayoutChanges = (args) => { return defaultAnimateLayoutChanges(args); }; -export const DraggableBoardCard = memo(function DraggableBoardCard({ issue }: { issue: Issue }) { +export const DraggableBoardCard = memo(function DraggableBoardCard({ issue, childProgress }: { issue: Issue; childProgress?: ChildProgress }) { const { attributes, listeners, @@ -204,7 +218,7 @@ export const DraggableBoardCard = memo(function DraggableBoardCard({ issue }: { href={`/issues/${issue.id}`} className={`group block transition-colors ${isDragging ? "pointer-events-none" : ""}`} > - + ); diff --git a/packages/views/issues/components/board-column.tsx b/packages/views/issues/components/board-column.tsx index 0743ba9128..d5244d60bd 100644 --- a/packages/views/issues/components/board-column.tsx +++ b/packages/views/issues/components/board-column.tsx @@ -18,17 +18,20 @@ import { useModalStore } from "@multica/core/modals"; import { useViewStoreApi } from "@multica/core/issues/stores/view-store-context"; import { StatusIcon } from "./status-icon"; import { DraggableBoardCard } from "./board-card"; +import type { ChildProgress } from "./list-row"; export function BoardColumn({ status, issueIds, issueMap, + childProgressMap, totalCount, footer, }: { status: IssueStatus; issueIds: string[]; issueMap: Map; + childProgressMap?: Map; totalCount?: number; footer?: ReactNode; }) { @@ -102,7 +105,7 @@ export function BoardColumn({ > {resolvedIssues.map((issue) => ( - + ))} {issueIds.length === 0 && ( diff --git a/packages/views/issues/components/board-view.tsx b/packages/views/issues/components/board-view.tsx index f396c75147..34050a93fe 100644 --- a/packages/views/issues/components/board-view.tsx +++ b/packages/views/issues/components/board-view.tsx @@ -33,6 +33,7 @@ import { StatusIcon } from "./status-icon"; import { BoardColumn } from "./board-column"; import { BoardCardContent } from "./board-card"; import { InfiniteScrollSentinel } from "./infinite-scroll-sentinel"; +import type { ChildProgress } from "./list-row"; const COLUMN_IDS = new Set(ALL_STATUSES); @@ -93,12 +94,15 @@ function findColumn( return null; } +const EMPTY_PROGRESS_MAP = new Map(); + export function BoardView({ issues, allIssues, visibleStatuses, hiddenStatuses, onMoveIssue, + childProgressMap = EMPTY_PROGRESS_MAP, }: { issues: Issue[]; allIssues: Issue[]; @@ -109,6 +113,7 @@ export function BoardView({ newStatus: IssueStatus, newPosition?: number ) => void; + childProgressMap?: Map; }) { const sortBy = useViewStore((s) => s.sortBy); const sortDirection = useViewStore((s) => s.sortDirection); @@ -275,6 +280,7 @@ export function BoardView({ status={status} issueIds={columns[status] ?? []} issueMap={issueMapRef.current} + childProgressMap={childProgressMap} totalCount={status === "done" ? doneTotal : undefined} footer={ status === "done" && hasMore ? ( @@ -295,7 +301,7 @@ export function BoardView({ {activeIssue ? (

- +
) : null} diff --git a/packages/views/issues/components/issues-page.tsx b/packages/views/issues/components/issues-page.tsx index c21ebab2c7..079d4166ba 100644 --- a/packages/views/issues/components/issues-page.tsx +++ b/packages/views/issues/components/issues-page.tsx @@ -163,6 +163,7 @@ export function IssuesPage() { visibleStatuses={visibleStatuses} hiddenStatuses={hiddenStatuses} onMoveIssue={handleMoveIssue} + childProgressMap={childProgressMap} /> ) : ( diff --git a/packages/views/issues/components/list-row.tsx b/packages/views/issues/components/list-row.tsx index 0ff6cdd2ac..a000f94d8b 100644 --- a/packages/views/issues/components/list-row.tsx +++ b/packages/views/issues/components/list-row.tsx @@ -57,15 +57,17 @@ export const ListRow = memo(function ListRow({ {issue.identifier} - {issue.title} - {childProgress && ( - - - - {childProgress.done}/{childProgress.total} + + {issue.title} + {childProgress && ( + + + + {childProgress.done}/{childProgress.total} + - - )} + )} + {issue.due_date && ( {formatDate(issue.due_date)} diff --git a/packages/views/my-issues/components/my-issues-page.tsx b/packages/views/my-issues/components/my-issues-page.tsx index a1a6c27283..e6b8da0f62 100644 --- a/packages/views/my-issues/components/my-issues-page.tsx +++ b/packages/views/my-issues/components/my-issues-page.tsx @@ -203,6 +203,7 @@ export function MyIssuesPage() { visibleStatuses={visibleStatuses} hiddenStatuses={hiddenStatuses} onMoveIssue={handleMoveIssue} + childProgressMap={childProgressMap} /> ) : ( diff --git a/packages/views/projects/components/project-detail.tsx b/packages/views/projects/components/project-detail.tsx index de492a4b01..0ff8016694 100644 --- a/packages/views/projects/components/project-detail.tsx +++ b/packages/views/projects/components/project-detail.tsx @@ -160,6 +160,7 @@ function ProjectIssuesTab({ projectIssues }: { projectIssues: Issue[] }) { visibleStatuses={visibleStatuses} hiddenStatuses={hiddenStatuses} onMoveIssue={handleMoveIssue} + childProgressMap={childProgressMap} /> ) : (