feat(frontend): Refactor Kanban board to focus on Story management
Refactored the Kanban board from a mixed Epic/Story/Task view to focus exclusively on Stories, which are the right granularity for Kanban management. Changes: - Created StoryCard component with Epic breadcrumb, priority badges, and estimated hours display - Updated KanbanColumn to use Story type and display epic names - Created CreateStoryDialog for story creation with epic selection - Added useProjectStories hook to fetch all stories across epics for a project - Refactored Kanban page to show Stories only with drag-and-drop status updates - Updated SignalR event handlers to focus on Story events only - Changed UI text from 'New Issue' to 'New Story' and 'update issue status' to 'update story status' - Implemented story status change via useChangeStoryStatus hook 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3,16 +3,18 @@
|
||||
import { useDroppable } from '@dnd-kit/core';
|
||||
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Issue } from '@/lib/api/issues';
|
||||
import { IssueCard } from './IssueCard';
|
||||
import { Story } from '@/types/project';
|
||||
import { StoryCard } from './StoryCard';
|
||||
|
||||
interface KanbanColumnProps {
|
||||
id: string;
|
||||
title: string;
|
||||
issues: Issue[];
|
||||
stories: Story[];
|
||||
epicNames?: Record<string, string>; // Map of epicId -> epicName
|
||||
taskCounts?: Record<string, number>; // Map of storyId -> taskCount
|
||||
}
|
||||
|
||||
export function KanbanColumn({ id, title, issues }: KanbanColumnProps) {
|
||||
export function KanbanColumn({ id, title, stories, epicNames = {}, taskCounts = {} }: KanbanColumnProps) {
|
||||
const { setNodeRef } = useDroppable({ id });
|
||||
|
||||
return (
|
||||
@@ -20,21 +22,26 @@ export function KanbanColumn({ id, title, issues }: KanbanColumnProps) {
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm font-medium flex items-center justify-between">
|
||||
<span>{title}</span>
|
||||
<span className="text-muted-foreground">{issues.length}</span>
|
||||
<span className="text-muted-foreground">{stories.length}</span>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent ref={setNodeRef} className="space-y-2 min-h-[400px]">
|
||||
<SortableContext
|
||||
items={issues.map((i) => i.id)}
|
||||
items={stories.map((s) => s.id)}
|
||||
strategy={verticalListSortingStrategy}
|
||||
>
|
||||
{issues.map((issue) => (
|
||||
<IssueCard key={issue.id} issue={issue} />
|
||||
{stories.map((story) => (
|
||||
<StoryCard
|
||||
key={story.id}
|
||||
story={story}
|
||||
epicName={epicNames[story.epicId]}
|
||||
taskCount={taskCounts[story.id]}
|
||||
/>
|
||||
))}
|
||||
</SortableContext>
|
||||
{issues.length === 0 && (
|
||||
{stories.length === 0 && (
|
||||
<div className="flex h-32 items-center justify-center rounded-lg border-2 border-dashed border-muted-foreground/25">
|
||||
<p className="text-sm text-muted-foreground">No issues</p>
|
||||
<p className="text-sm text-muted-foreground">No stories</p>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
|
||||
Reference in New Issue
Block a user