Taming the Review Beast: Iterative Refinement in Workflow UIs
We tackled a critical workflow review panel, transforming a clunky card-based layout into an elegant, interactive table, and empowering users with granular control for iterative refinement.
Building complex workflow systems often means wrestling with the user interface. One of the most critical, and often challenging, areas is the "review" step. This is where users interact with the system's output, make decisions, and guide the next steps. Recently, we dove deep into refining our Review Key Points Panel, aiming to make it not just functional, but truly intuitive and powerful.
Our goal was clear:
- Refine the layout: Move from a disjointed card-based view to a clean, aligned table.
- Improve focus: Make verbose analysis collapsible by default, showing key metadata upfront.
- Empower iteration: Add a per-item "Recreate" action for fine-grained control over the workflow.
This post details the journey, the roadblocks we hit, and the lessons we learned in making these improvements.
The Challenge: A Review Panel Begging for Order
Our existing Review Key Points Panel was, to put it mildly, a bit unwieldy. Each "key point" (a finding or insight generated by an upstream LLM step) was rendered as an independent card. While this worked for simple displays, it quickly fell apart when trying to compare items or quickly scan for information. Severity badges, categories, and titles floated independently, making it hard to visually parse.
Furthermore, the detailed review analysis for each key point was expanded by default. While crucial information, it often cluttered the primary interaction surface, forcing users to scroll past reams of text just to see the next item.
Finally, our iterative development needed more granularity. If a single key point wasn't quite right, the only option was often to re-run the entire upstream step. We needed a way to target specific findings for refinement.
Lesson 1: When Flexbox Fails, Embrace the Grid
Our first instinct for layout refinement is often Flexbox. It's powerful, flexible, and usually gets the job done.
Attempt: Initially, we tried using a Flexbox-based layout within each card to align elements. Failure: While elements within a single card aligned perfectly, there was no guarantee that the "Severity" column in one card would align with the "Severity" column in the next card. Each card was an independent layout context, leading to a jagged, misaligned appearance across rows. This made scanning and comparing key points a frustrating experience.
Solution & Takeaway: For true, consistent column alignment across multiple "rows" (even if they're conceptually separate items), CSS Grid is often the superior choice.
We refactored src/components/workflow/review-key-points-panel.tsx to leverage CSS Grid. By defining the grid on the parent container, we could enforce strict column widths for all children, regardless of their content within those bounds.
// Simplified CSS Grid class for the key points panel
// This ensures consistent column alignment across all key point items
<div className="grid grid-cols-[16px_72px_90px_1fr_auto] gap-2 items-center">
{/* Column 1: Chevron for collapse/expand */}
<div className="flex items-center justify-center">...</div>
{/* Column 2: Severity Badge */}
<div className="flex items-center">...</div>
{/* Column 3: Category */}
<div className="text-xs font-semibold">...</div>
{/* Column 4: Finding Title (takes remaining space) */}
<div className="truncate">...</div>
{/* Column 5: Status Icon / Action Buttons */}
<div className="flex justify-end">...</div>
</div>
The grid-cols-[16px_72px_90px_1fr_auto] definition was key:
16px: For the expand/collapse chevron.72px: Perfectly sized for our severity badges.90px: For the category label.1fr: The finding title takes up the remaining available space.auto: For the action buttons/status icon, letting them size naturally.
This instantly transformed the panel into a clean, table-like display, making it much easier to digest the information.
Lesson 2: Default States Matter – Prioritize Primary Interactions
User feedback is invaluable. While the detailed analysis of each key point is essential, having it expanded by default was a constant source of friction.
Attempt: The review analysis output was initially expanded by default. Failure: Users consistently reported that the sheer verbosity of the analysis section overshadowed the primary interaction surface – the list of key points themselves. It required excessive scrolling and made it harder to get a quick overview of all findings.
Solution & Takeaway: Default states should prioritize the most common or critical user interaction. For verbose, secondary information, default-collapsed is often the way to go.
In src/app/(dashboard)/dashboard/workflows/[id]/page.tsx, we implemented a collapsible section for the review analysis. Importantly, we made it default collapsed using a state variable (expandedPrompts[step.id + '-analysis'] ?? false). To ensure users still had a quick glance at the analysis's impact, we pulled key metadata (tokens used, cost, duration) directly into the collapse header. This provides context without demanding screen real estate.
// Within the KeyPoint component rendering the analysis
<Collapsible
open={expandedPrompts[keyPoint.id + '-analysis'] ?? false}
onOpenChange={(isOpen) => setExpandedPrompt(keyPoint.id + '-analysis', isOpen)}
>
<CollapsibleTrigger asChild>
<button className="flex items-center justify-between w-full text-sm text-nyx-dimmed hover:text-nyx-accent">
<span>
Review Analysis
{keyPoint.analysisMetadata && (
<span className="ml-2 text-xs text-nyx-light">
({keyPoint.analysisMetadata.tokens} tokens, ${keyPoint.analysisMetadata.cost.toFixed(4)}, {keyPoint.analysisMetadata.durationMs}ms)
</span>
)}
</span>
<ChevronDown className={cn("h-4 w-4 transition-transform", expandedPrompts[keyPoint.id + '-analysis'] && "rotate-180")} />
</button>
</CollapsibleTrigger>
<CollapsibleContent>
{/* ... full analysis content here ... */}
</CollapsibleContent>
</Collapsible>
This subtle change significantly improved the panel's usability, allowing users to focus on the key points and dive into the analysis only when needed.
Empowering Iteration: Per-Item "Recreate"
One of the most powerful additions was the ability to "Recreate" a single key point. In generative AI workflows, it's rare for everything to be perfect on the first try. Iteration is key, and the more granular that iteration, the faster and more efficient the refinement process.
We added a "Recreate" button to each individual key point. Clicking this button triggers onRecreateItem(keyPointId), which in turn calls a recreateFromKeyPoint mutation. Crucially, this mutation uses mode: "recreate_with_hints", allowing the system to re-run the upstream LLM step specifically for that item, potentially injecting hints derived from the previous attempt or user feedback.
This enables a powerful iteration loop:
- Identify issue: A key point isn't quite right.
- Recreate: Click "Recreate" on that specific item.
- Re-run: The upstream step (e.g., "Design Features") is re-run, targeting the problematic area.
- New Review: A new review is generated with updated key points.
- Address & Approve: Iterate until all key points are "green" (kept) or resolved.
Alongside "Recreate," we also provided "Keep," "Edit," and "Discard" actions, with the status of each item clearly indicated by an icon in the rightmost column. The expanded detail panel also received a subtle border-l-2 for visual hierarchy, with edit mode highlighting using border-nyx-accent/30.
What's Next? Continuous Improvement
With these core improvements committed and pushed to main, our immediate next steps involve rigorous testing of the new layout and the per-item "Recreate" functionality. We'll be running through the full iteration loop to ensure a smooth user experience.
Beyond that, we're always looking to refine our codebase:
- Type Consolidation: The
ReviewKeyPointtype is currently duplicated between server and client. This needs to be consolidated into a shared types file. - Component Extraction: Our workflow detail page is growing large (~1650 lines). The review panel section is a prime candidate for extraction into a standalone component, improving maintainability and readability.
This session was a fantastic example of how small, focused improvements, driven by user feedback and a deep understanding of UI/UX principles, can significantly enhance the developer and end-user experience in complex applications.
{
"thingsDone": [
"Refactored review key points panel to CSS Grid table layout",
"Implemented collapsible review analysis with default-collapsed state",
"Added per-item 'Recreate' button with 'recreate_with_hints' mode",
"Added Keep, Recreate, Edit, Discard action buttons with status icons",
"Improved visual hierarchy for expanded detail panel and edit mode"
],
"pains": [
"Flexbox failed for consistent column alignment across multiple 'rows'",
"Default expanded review analysis was too verbose and distracting"
],
"successes": [
"Achieved perfect column alignment using CSS Grid",
"Improved user focus by defaulting analysis to collapsed state",
"Enabled granular iterative refinement with per-item recreate functionality",
"Enhanced overall UI/UX for the review workflow"
],
"techStack": [
"React",
"Next.js",
"TypeScript",
"CSS Grid",
"Tailwind CSS",
"Mutation (likely TanStack Query or similar)"
]
}