diff --git a/apps/ui/src/components/views/board-view/components/kanban-card/card-actions.tsx b/apps/ui/src/components/views/board-view/components/kanban-card/card-actions.tsx index 68fd7e37..24c0eb85 100644 --- a/apps/ui/src/components/views/board-view/components/kanban-card/card-actions.tsx +++ b/apps/ui/src/components/views/board-view/components/kanban-card/card-actions.tsx @@ -6,7 +6,6 @@ import { RotateCcw, StopCircle, CheckCircle2, - GitCommit, FileText, Eye, Wand2, @@ -25,7 +24,6 @@ interface CardActionsProps { onForceStop?: () => void; onManualVerify?: () => void; onFollowUp?: () => void; - onCommit?: () => void; onImplement?: () => void; onComplete?: () => void; onViewPlan?: () => void; @@ -44,7 +42,6 @@ export function CardActions({ onForceStop, onManualVerify, onFollowUp, - onCommit, onImplement, onComplete, onViewPlan, @@ -251,7 +248,7 @@ export function CardActions({ Refine )} - {/* Show Verify button if PR was created (changes are committed), otherwise show Commit button */} + {/* Show Verify button if PR was created (changes are committed), otherwise show Mark as Verified button */} {feature.prUrl && onManualVerify ? ( - ) : onCommit ? ( + ) : onManualVerify ? ( ) : null} @@ -338,4 +335,3 @@ export function CardActions({ ); } - diff --git a/apps/ui/src/components/views/board-view/components/kanban-card/card-badges.tsx b/apps/ui/src/components/views/board-view/components/kanban-card/card-badges.tsx index 4fa5415a..fdfa4cf6 100644 --- a/apps/ui/src/components/views/board-view/components/kanban-card/card-badges.tsx +++ b/apps/ui/src/components/views/board-view/components/kanban-card/card-badges.tsx @@ -7,16 +7,46 @@ import { TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; -import { AlertCircle, Lock, Sparkles, Hand } from "lucide-react"; +import { AlertCircle, Lock, Hand, Sparkles } from "lucide-react"; import { getBlockingDependencies } from "@/lib/dependency-resolver"; +interface CardBadgeProps { + children: React.ReactNode; + className?: string; + "data-testid"?: string; + title?: string; +} + +/** + * Shared badge component matching the "Just Finished" badge style + * Used for priority badges and other card badges + */ +function CardBadge({ + children, + className, + "data-testid": dataTestId, + title, +}: CardBadgeProps) { + return ( +
+ {children} +
+ ); +} + interface CardBadgesProps { feature: Feature; } export function CardBadges({ feature }: CardBadgesProps) { const { enableDependencyBlocking, features } = useAppStore(); - const [currentTime, setCurrentTime] = useState(() => Date.now()); // Calculate blocking dependencies (if feature is in backlog and has incomplete dependencies) const blockingDependencies = useMemo(() => { @@ -26,50 +56,13 @@ export function CardBadges({ feature }: CardBadgesProps) { return getBlockingDependencies(feature, features); }, [enableDependencyBlocking, feature, features]); - const isJustFinished = useMemo(() => { - if ( - !feature.justFinishedAt || - feature.status !== "waiting_approval" || - feature.error - ) { - return false; - } - const finishedTime = new Date(feature.justFinishedAt).getTime(); - const twoMinutes = 2 * 60 * 1000; - return currentTime - finishedTime < twoMinutes; - }, [feature.justFinishedAt, feature.status, feature.error, currentTime]); - - useEffect(() => { - if (!feature.justFinishedAt || feature.status !== "waiting_approval") { - return; - } - - const finishedTime = new Date(feature.justFinishedAt).getTime(); - const twoMinutes = 2 * 60 * 1000; - const timeRemaining = twoMinutes - (currentTime - finishedTime); - - if (timeRemaining <= 0) { - return; - } - - // eslint-disable-next-line no-undef - const interval = setInterval(() => { - setCurrentTime(Date.now()); - }, 1000); - - return () => { - // eslint-disable-next-line no-undef - clearInterval(interval); - }; - }, [feature.justFinishedAt, feature.status, currentTime]); - // Status badges row (error, blocked, just finished) + // Status badges row (error, blocked) const showStatusBadges = feature.error || (blockingDependencies.length > 0 && !feature.error && !feature.skipTests && - feature.status === "backlog") || - isJustFinished; + feature.status === "backlog"); if (!showStatusBadges) { return null; @@ -117,13 +110,12 @@ export function CardBadges({ feature }: CardBadgesProps) { - +

Blocked by {blockingDependencies.length} incomplete{" "} - {blockingDependencies.length === 1 ? "dependency" : "dependencies"} + {blockingDependencies.length === 1 + ? "dependency" + : "dependencies"}

{blockingDependencies @@ -137,21 +129,6 @@ export function CardBadges({ feature }: CardBadgesProps) { )} - - {/* Just Finished badge */} - {isJustFinished && ( -

- -
- )} ); } @@ -161,11 +138,49 @@ interface PriorityBadgesProps { } export function PriorityBadges({ feature }: PriorityBadgesProps) { + const [currentTime, setCurrentTime] = useState(() => Date.now()); + + const isJustFinished = useMemo(() => { + if ( + !feature.justFinishedAt || + feature.status !== "waiting_approval" || + feature.error + ) { + return false; + } + const finishedTime = new Date(feature.justFinishedAt).getTime(); + const twoMinutes = 2 * 60 * 1000; + return currentTime - finishedTime < twoMinutes; + }, [feature.justFinishedAt, feature.status, feature.error, currentTime]); + + useEffect(() => { + if (!feature.justFinishedAt || feature.status !== "waiting_approval") { + return; + } + + const finishedTime = new Date(feature.justFinishedAt).getTime(); + const twoMinutes = 2 * 60 * 1000; + const timeRemaining = twoMinutes - (currentTime - finishedTime); + + if (timeRemaining <= 0) { + return; + } + + // eslint-disable-next-line no-undef + const interval = setInterval(() => { + setCurrentTime(Date.now()); + }, 1000); + + return () => { + // eslint-disable-next-line no-undef + clearInterval(interval); + }; + }, [feature.justFinishedAt, feature.status, currentTime]); + const showPriorityBadges = feature.priority || - (feature.skipTests && - !feature.error && - feature.status === "backlog"); + (feature.skipTests && !feature.error && feature.status === "backlog") || + isJustFinished; if (!showPriorityBadges) { return null; @@ -178,24 +193,32 @@ export function PriorityBadges({ feature }: PriorityBadgesProps) { -
- {feature.priority === 1 - ? "H" - : feature.priority === 2 - ? "M" - : "L"} -
+ {feature.priority === 1 ? ( + + H + + ) : feature.priority === 2 ? ( + + M + + ) : ( + + L + + )} +

@@ -210,29 +233,34 @@ export function PriorityBadges({ feature }: PriorityBadgesProps) { )} {/* Manual verification badge */} - {feature.skipTests && - !feature.error && - feature.status === "backlog" && ( - - - -

- -
- - -

Manual verification required

-
-
-
- )} + {feature.skipTests && !feature.error && feature.status === "backlog" && ( + + + + + + + + +

Manual verification required

+
+
+
+ )} + + {/* Just Finished badge */} + {isJustFinished && ( + + + + )} ); } - diff --git a/apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx b/apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx index 79cb9c4d..84ab2c76 100644 --- a/apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx +++ b/apps/ui/src/components/views/board-view/components/kanban-card/kanban-card.tsx @@ -21,7 +21,6 @@ interface KanbanCardProps { onManualVerify?: () => void; onMoveBackToInProgress?: () => void; onFollowUp?: () => void; - onCommit?: () => void; onImplement?: () => void; onComplete?: () => void; onViewPlan?: () => void; @@ -48,7 +47,6 @@ export const KanbanCard = memo(function KanbanCard({ onManualVerify, onMoveBackToInProgress: _onMoveBackToInProgress, onFollowUp, - onCommit, onImplement, onComplete, onViewPlan, @@ -198,7 +196,6 @@ export const KanbanCard = memo(function KanbanCard({ onForceStop={onForceStop} onManualVerify={onManualVerify} onFollowUp={onFollowUp} - onCommit={onCommit} onImplement={onImplement} onComplete={onComplete} onViewPlan={onViewPlan} diff --git a/apps/ui/src/components/views/board-view/kanban-board.tsx b/apps/ui/src/components/views/board-view/kanban-board.tsx index 1ebbf042..1dddffe3 100644 --- a/apps/ui/src/components/views/board-view/kanban-board.tsx +++ b/apps/ui/src/components/views/board-view/kanban-board.tsx @@ -194,7 +194,6 @@ export function KanbanBoard({ onMoveBackToInProgress(feature) } onFollowUp={() => onFollowUp(feature)} - onCommit={() => onCommit(feature)} onComplete={() => onComplete(feature)} onImplement={() => onImplement(feature)} onViewPlan={() => onViewPlan(feature)}