From 90ea34fad4341b85e3c2d677e89f9d316b43afd1 Mon Sep 17 00:00:00 2001 From: Sai Prakash Date: Tue, 14 Jul 2026 15:28:51 -0400 Subject: [PATCH 1/2] Redesign Code Plan detail page: description card, context tabs - Long descriptions no longer push the whole page down: the header keeps just title/badges/meta, and the description moves into its own card (above Design Spec) clamped to 5 lines with a Show more/less expander. Stats row now lands at the top of the viewport. - Tasks, Assets & PRs, Impact Analysis, and Linked Work Items now live in a tab group with Tasks as the default tab (with counts in each label), so tasks are visible immediately and every context section is one click away. Empty Impact/Work Items tabs get explanatory empty states instead of being hidden. - Add Task action sits on the tab row, always reachable. - Dropped dead imports/styles left over from the old inline layout. Co-Authored-By: Claude Fable 5 --- app/(dashboard)/plans/[id]/page.tsx | 212 ++++++++++-------- .../plans/[id]/plan-description-card.tsx | 61 +++++ 2 files changed, 178 insertions(+), 95 deletions(-) create mode 100644 app/(dashboard)/plans/[id]/plan-description-card.tsx diff --git a/app/(dashboard)/plans/[id]/page.tsx b/app/(dashboard)/plans/[id]/page.tsx index 3f275d0..ccbe430 100644 --- a/app/(dashboard)/plans/[id]/page.tsx +++ b/app/(dashboard)/plans/[id]/page.tsx @@ -6,6 +6,7 @@ import { users } from '@/lib/db/schema' import { eq } from 'drizzle-orm' import { getCodePlan, getCodePlans, getTeamMembers, getWorkItems, getAssetOptions, getImpactedAssets, getIntegrations } from '@/lib/db/queries' import { PlanAssetsSection } from './plan-assets-section' +import { PlanDescriptionCard } from './plan-description-card' import { SpecCard } from '@/components/spec-card' import { fetchSpecMarkdown } from '@/lib/specs' import { PlanSyncDialog } from './plan-sync-dialog' @@ -15,8 +16,9 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { Progress } from '@/components/ui/progress' import { Avatar, AvatarFallback } from '@/components/ui/avatar' -import { Calendar, Users, Clock, AlertCircle, CheckCircle2, Circle, Play } from 'lucide-react' -import type { CodePlanStatus, CodePlanType, TaskStatus } from '@/lib/types' +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' +import { Calendar, Users, AlertCircle } from 'lucide-react' +import type { CodePlanStatus, CodePlanType } from '@/lib/types' import { cn, formatDate } from '@/lib/utils' import { PlanStatusButtons, PlanEditSheet, AddTaskDialog } from './plan-actions' @@ -41,13 +43,6 @@ const typeStyles: Record = { bugfix: 'bg-chart-5/20 text-chart-5', } -const priorityStyles = { - low: 'bg-muted text-muted-foreground', - medium: 'bg-chart-2/20 text-chart-2', - high: 'bg-warning/20 text-warning', - critical: 'bg-destructive/20 text-destructive', -} - export default async function PlanDetailPage({ params }: { params: Promise<{ id: string }> }) { const { id } = await params const user = await authAdapter.getUser() @@ -87,7 +82,6 @@ export default async function PlanDetailPage({ params }: { params: Promise<{ id: {typeLabels[plan.type]} {plan.status} -

{plan.description}

)} + {/* Long-form description, clamped with an expander */} + {plan.description && } + {/* Linked design spec, rendered read-only from its source */} {plan.specUrl && ( )} - {/* Per-asset delivery: branch + PR per targeted asset */} - + {/* Tasks front and center; delivery/impact/demand context one click away */} + +
+ + Tasks ({plan.taskCount}) + Assets & PRs ({plan.planAssets.length}) + Impact ({impactedAssets.length}) + Work Items ({linkedItems.length}) + + +
- {/* Impact analysis: assets that depend on this plan's targets */} - {impactedAssets.length > 0 && ( - - - - Impact Analysis — {impactedAssets.length} dependent asset{impactedAssets.length > 1 ? 's' : ''} - - - -

- These assets depend on what this plan changes. Review them for breakage and coordinate their owners. -

-
    - {impactedAssets.map((impacted) => ( -
  • - {impacted.name} - {impacted.type} - - {impacted.dependencyType.replace('_', ' ')} → {impacted.viaAssetName} - - {impacted.health !== 'healthy' && ( - - {impacted.health} - - )} -
  • - ))} -
-
-
- )} + + ({ id: m.userId, name: m.user.name }))} + otherPlans={otherPlans} + /> + - {/* Linked work items — what this plan delivers or fixes */} - {linkedItems.length > 0 && ( - - - - Linked Work Items ({linkedItems.length}) - - - -
    - {linkedItems.map((item) => ( -
  • - - {item.title} - -
    - - {item.type.replace('_', ' ')} - - - {item.status.replace('_', ' ')} - -
    -
  • - ))} -
-
-
- )} + + {/* Per-asset delivery: branch + PR per targeted asset */} + + - {/* Tasks */} -
-
-

Tasks

- -
+ + {/* Impact analysis: assets that depend on this plan's targets */} + {impactedAssets.length === 0 ? ( + + + No dependent assets — nothing downstream depends on what this plan changes. + + + ) : ( + + + + Impact Analysis — {impactedAssets.length} dependent asset{impactedAssets.length > 1 ? 's' : ''} + + + +

+ These assets depend on what this plan changes. Review them for breakage and coordinate their owners. +

+
    + {impactedAssets.map((impacted) => ( +
  • + {impacted.name} + {impacted.type} + + {impacted.dependencyType.replace('_', ' ')} → {impacted.viaAssetName} + + {impacted.health !== 'healthy' && ( + + {impacted.health} + + )} +
  • + ))} +
+
+
+ )} +
- ({ id: m.userId, name: m.user.name }))} - otherPlans={otherPlans} - /> -
+ + {/* Linked work items — what this plan delivers or fixes */} + {linkedItems.length === 0 ? ( + + + No linked work items — link features, bugs, or tech debt this plan addresses from the Work Items view. + + + ) : ( + + + + Linked Work Items ({linkedItems.length}) + + + +
    + {linkedItems.map((item) => ( +
  • + + {item.title} + +
    + + {item.type.replace('_', ' ')} + + + {item.status.replace('_', ' ')} + +
    +
  • + ))} +
+
+
+ )} +
+
) } diff --git a/app/(dashboard)/plans/[id]/plan-description-card.tsx b/app/(dashboard)/plans/[id]/plan-description-card.tsx new file mode 100644 index 0000000..3a6dc32 --- /dev/null +++ b/app/(dashboard)/plans/[id]/plan-description-card.tsx @@ -0,0 +1,61 @@ +'use client' + +import { useEffect, useRef, useState } from 'react' +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' +import { Button } from '@/components/ui/button' +import { AlignLeft, ChevronDown, ChevronUp } from 'lucide-react' +import { cn } from '@/lib/utils' + +/** Long-form plan description in its own card, clamped to ~5 lines with an expander. */ +export function PlanDescriptionCard({ description }: { description: string }) { + const [expanded, setExpanded] = useState(false) + const [clamped, setClamped] = useState(false) + const textRef = useRef(null) + + useEffect(() => { + const el = textRef.current + if (el) setClamped(el.scrollHeight > el.clientHeight + 1) + }, [description]) + + return ( + + + + + Description + + + +

+ {description} +

+ {(clamped || expanded) && ( + + )} +
+
+ ) +} From b15f75d7b7a69be3249adebe5087d3dee225b0c4 Mon Sep 17 00:00:00 2001 From: Sai Prakash Date: Tue, 14 Jul 2026 15:29:11 -0400 Subject: [PATCH 2/2] v0.3.21 Co-Authored-By: Claude Fable 5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 94c7e32..7ddb45a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codeplans", - "version": "0.3.20", + "version": "0.3.21", "description": "Manage and track coordinated changes across your software architecture.", "author": "Sai Prakash ", "homepage": "https://codeplans.ai",